diff options
374 files changed, 4535 insertions, 2919 deletions
diff --git a/Android.bp b/Android.bp index 85632b2b89..2c4fb37908 100644 --- a/Android.bp +++ b/Android.bp @@ -409,6 +409,9 @@ android_library { lint: { baseline_filename: "lint-baseline.xml", }, + flags_packages: [ + "com_android_launcher3_flags", + ], } // diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 6948133abb..768ba652de 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -1,8 +1,10 @@ [Builtin Hooks] ktfmt = true +bpfmt = true [Builtin Hooks Options] ktfmt = --kotlinlang-style +bpfmt = -d [Tool Paths] ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index c5774bb16a..cd8b891de5 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -311,6 +311,13 @@ flag { } flag { + name: "all_apps_blur" + namespace: "launcher" + description: "Content behind the all apps panel in Launcher will be blurred." + bug: "400827727" +} + +flag { name: "multiline_search_bar" namespace: "launcher" description: "Search bar can wrap to multi-line" @@ -559,6 +566,14 @@ flag { } flag { + name: "google_sans_flex_font" + namespace: "launcher" + description: "Adds refresh for font family. Needs to be fixed to be used in resources." + bug: "395145453" + is_fixed_read_only: true +} + +flag { name: "restore_archived_shortcuts" namespace: "launcher" description: "Makes sure pre-archived pinned shortcuts also get restored" @@ -656,3 +671,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "sync_app_launch_with_taskbar_stash" + namespace: "launcher" + description: "Syncs the two animations (app launch, taskbar stash) so they play at the same time." + bug: "319162553" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "remove_apps_refresh_on_right_click" + namespace: "launcher" + description: "Remove predicted apps refresh on right click" + bug: "343650193" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/quickstep/res/color/app_chip_menu_item_color_fg.xml b/quickstep/res/color/app_chip_menu_item_color_fg.xml new file mode 100644 index 0000000000..fa1dc34dce --- /dev/null +++ b/quickstep/res/color/app_chip_menu_item_color_fg.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:alpha="0.15" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_pressed="true" /> + <item android:alpha="0.11" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_hovered="true" /> + <item android:color="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/quickstep/res/color/app_chip_state_color_fg.xml b/quickstep/res/color/app_chip_state_color_fg.xml new file mode 100644 index 0000000000..58dfee0cf6 --- /dev/null +++ b/quickstep/res/color/app_chip_state_color_fg.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:alpha="0.15" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_pressed="true" /> + <item android:alpha="0.11" android:color="@color/materialColorOnSurface" android:state_enabled="true" android:state_hovered="true" /> + <item android:color="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/quickstep/res/drawable/app_chip_fg.xml b/quickstep/res/drawable/app_chip_fg.xml new file mode 100644 index 0000000000..7b19c9e134 --- /dev/null +++ b/quickstep/res/drawable/app_chip_fg.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/app_chip_state_color_fg" /> +</shape>
\ No newline at end of file diff --git a/quickstep/res/drawable/app_chip_menu_item_bg.xml b/quickstep/res/drawable/app_chip_menu_item_bg.xml new file mode 100644 index 0000000000..39e88d2eed --- /dev/null +++ b/quickstep/res/drawable/app_chip_menu_item_bg.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/materialColorSurfaceBright" /> +</shape> diff --git a/quickstep/res/drawable/app_chip_menu_item_fg.xml b/quickstep/res/drawable/app_chip_menu_item_fg.xml new file mode 100644 index 0000000000..96d067d5b8 --- /dev/null +++ b/quickstep/res/drawable/app_chip_menu_item_fg.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/app_chip_menu_item_color_fg" /> + <corners android:radius="@dimen/task_menu_item_corner_radius" /> +</shape> diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml index b44510d47c..b45a04ad2a 100644 --- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml +++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml @@ -21,14 +21,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:importantForAccessibility="yes" - android:background="@drawable/keyboard_quick_switch_task_view_background" - android:clipToOutline="true" - launcher:focusBorderColor="@color/materialColorOutline"> + launcher:focusBorderColor="@color/materialColorSecondary"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content" android:layout_width="@dimen/keyboard_quick_switch_taskview_width" android:layout_height="@dimen/keyboard_quick_switch_taskview_height" + android:background="@drawable/keyboard_quick_switch_task_view_background" + android:clipToOutline="true" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml index 56b1adfb52..672b715c1d 100644 --- a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml +++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml @@ -21,14 +21,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:importantForAccessibility="yes" - android:background="@drawable/keyboard_quick_switch_task_view_background" - android:clipToOutline="true" - launcher:focusBorderColor="@androidprv:color/materialColorOutline"> + launcher:focusBorderColor="@color/materialColorSecondary"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content" android:layout_width="0dp" android:layout_height="@dimen/keyboard_quick_switch_taskview_height" + android:background="@drawable/keyboard_quick_switch_task_view_background" + android:clipToOutline="true" app:layout_constraintDimensionRatio="1:1" app:layout_constraintTop_toTopOf="parent" diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml index 0972be16e3..09fb5094fe 100644 --- a/quickstep/res/layout/icon_app_chip_view.xml +++ b/quickstep/res/layout/icon_app_chip_view.xml @@ -22,10 +22,12 @@ android:layout_width="@dimen/task_thumbnail_icon_menu_expanded_width" android:layout_height="@dimen/task_thumbnail_icon_menu_expanded_height" android:clipToOutline="true" - android:focusable="false" + android:focusable="true" + android:focusableInTouchMode="false" android:importantForAccessibility="no" android:autoMirrored="true" android:elevation="@dimen/task_thumbnail_icon_menu_elevation" + android:foreground="@drawable/app_chip_fg" android:background="@color/materialColorSurfaceBright"> <!-- ignoring warning because the user of the anchor is a Rect where RTL is not needed --> @@ -77,4 +79,5 @@ android:background="@drawable/icon_menu_arrow_background" android:src="@drawable/ic_chevron_down" android:importantForAccessibility="no" /> + </com.android.quickstep.views.IconAppChipView>
\ No newline at end of file diff --git a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml index db47ff08ba..d281732a2a 100644 --- a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml +++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml @@ -20,9 +20,8 @@ xmlns:launcher="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:clipToOutline="true" android:importantForAccessibility="yes" - launcher:focusBorderColor="@androidprv:color/materialColorOutline" + launcher:focusBorderColor="@color/materialColorSecondary" launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius"> <androidx.constraintlayout.widget.ConstraintLayout @@ -31,6 +30,7 @@ android:layout_height="@dimen/keyboard_quick_switch_taskview_height" android:background="@drawable/keyboard_quick_switch_text_button_background" android:backgroundTint="@androidprv:color/materialColorSurfaceContainer" + android:clipToOutline="true" android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding" app:layout_constraintTop_toTopOf="parent" diff --git a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml index 5a3ee8374a..3321306ae0 100644 --- a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml +++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml @@ -20,9 +20,8 @@ xmlns:launcher="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:clipToOutline="true" android:importantForAccessibility="yes" - launcher:focusBorderColor="@androidprv:color/materialColorOutline" + launcher:focusBorderColor="@color/materialColorSecondary" launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius"> <androidx.constraintlayout.widget.ConstraintLayout @@ -31,6 +30,7 @@ android:layout_height="@dimen/keyboard_quick_switch_taskview_height" android:background="@drawable/keyboard_quick_switch_text_button_background" android:backgroundTint="@androidprv:color/materialColorSurfaceBright" + android:clipToOutline="true" android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding" app:layout_constraintTop_toTopOf="parent" diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml index 37bb02737a..218a3f26f1 100644 --- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml +++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml @@ -21,14 +21,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:importantForAccessibility="yes" - android:background="@drawable/keyboard_quick_switch_task_view_background" - android:clipToOutline="true" - launcher:focusBorderColor="@color/materialColorOutline"> + launcher:focusBorderColor="@color/materialColorSecondary"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content" android:layout_width="@dimen/keyboard_quick_switch_taskview_width" android:layout_height="@dimen/keyboard_quick_switch_taskview_height" + android:background="@drawable/keyboard_quick_switch_task_view_background" + android:clipToOutline="true" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml index 33d8c16a53..d3f5bf1ac6 100644 --- a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml +++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml @@ -21,14 +21,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:importantForAccessibility="yes" - android:background="@drawable/keyboard_quick_switch_task_view_background" - android:clipToOutline="true" - launcher:focusBorderColor="@androidprv:color/materialColorOutline"> + launcher:focusBorderColor="@color/materialColorSecondary"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content" android:layout_width="0dp" android:layout_height="@dimen/keyboard_quick_switch_taskview_height" + android:background="@drawable/keyboard_quick_switch_task_view_background" + android:clipToOutline="true" app:layout_constraintDimensionRatio="1:1" app:layout_constraintTop_toTopOf="parent" diff --git a/quickstep/res/layout/task_header_view.xml b/quickstep/res/layout/task_header_view.xml index ea5c24e54c..849153fd9e 100644 --- a/quickstep/res/layout/task_header_view.xml +++ b/quickstep/res/layout/task_header_view.xml @@ -15,52 +15,48 @@ --> <com.android.quickstep.views.TaskHeaderView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/task_header_view" android:layout_width="match_parent" android:layout_height="wrap_content" - android:id="@+id/task_header_view" + android:paddingTop="@dimen/task_thumbnail_header_padding_top_bottom" + android:paddingBottom="@dimen/task_thumbnail_header_padding_top_bottom" + android:paddingStart="@dimen/task_thumbnail_header_padding_start_end" + android:paddingEnd="@dimen/task_thumbnail_header_padding_start_end" android:background="@drawable/task_thumbnail_header_bg"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="@dimen/task_thumbnail_header_height" - android:layout_marginStart="@dimen/task_thumbnail_header_margin_edge" - android:layout_marginEnd="@dimen/task_thumbnail_header_margin_edge" + <ImageView + android:id="@+id/header_app_icon" + android:layout_width="@dimen/task_thumbnail_header_icon_size" + android:layout_height="@dimen/task_thumbnail_header_icon_size" + android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views" + android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views" + android:contentDescription="@string/header_app_icon_description" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + <TextView + android:id="@+id/header_app_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views" + android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views" + android:maxLines="1" + android:text="@string/header_default_app_title" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/header_app_icon" + app:layout_constraintTop_toTopOf="parent" /> + <ImageButton + android:id="@+id/header_close_button" + android:layout_width="@dimen/task_thumbnail_header_icon_size" + android:layout_height="@dimen/task_thumbnail_header_icon_size" + android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views" + android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views" + android:background="@null" + android:contentDescription="@string/header_close_icon_description" + android:src="@drawable/task_header_close_button" + android:tint="@android:color/darker_gray" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent"> - <ImageView - android:id="@+id/header_app_icon" - android:contentDescription="@string/header_app_icon_description" - android:layout_width="@dimen/task_thumbnail_header_icon_size" - android:layout_height="@dimen/task_thumbnail_header_icon_size" - android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/header_app_title" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" /> - <TextView - android:id="@+id/header_app_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views" - android:maxLines="1" - android:text="@string/header_default_app_title" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/header_app_icon" - app:layout_constraintTop_toTopOf="parent" /> - <ImageButton - android:id="@+id/header_close_button" - android:contentDescription="@string/header_close_icon_description" - android:layout_width="@dimen/task_thumbnail_header_icon_size" - android:layout_height="@dimen/task_thumbnail_header_icon_size" - android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views" - android:src="@drawable/task_header_close_button" - android:tint="@android:color/darker_gray" - android:background="@null" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/header_app_title" - app:layout_constraintHorizontal_bias="1" /> - </androidx.constraintlayout.widget.ConstraintLayout> + app:layout_constraintHorizontal_bias="1" + app:layout_constraintStart_toEndOf="@id/header_app_title" + app:layout_constraintTop_toTopOf="parent" /> </com.android.quickstep.views.TaskHeaderView> diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index 7a6435b5f8..83e6f79ce0 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taakbalkoorloop"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Maak app as ’n borrel oop"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Werkskerm"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Appikoon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Maak Toe-knoppie"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Speld aan taakbalk vas"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ontspeld van taakbalk"</string> </resources> diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 7286f3fd75..d5967346aa 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"የተግባር አሞሌ ትርፍ ፍሰት"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"መተግበሪያን እንደ ዓረፋ ይክፈቱ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ዴስክቶፕ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"የመተግበሪያ አዶ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"የመተግበሪያ ርዕስ"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"የዝጋ አዝራር"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ተግባር አሞሌ ላይ ፒን አድርግ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ከተግባር አሞሌ ንቀል"</string> </resources> diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index e673ac64d1..ec379830c0 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"القائمة الكاملة لشريط التطبيقات"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"فتح التطبيق كفقاعة"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"وضع الكمبيوتر المكتبي"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" من \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"رمز التطبيق"</string> <string name="header_default_app_title" msgid="8308052350689531566">"عنوان التطبيق"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"زر الإغلاق"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"التثبيت على شريط التطبيقات"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"إزالة التثبيت من شريط التطبيقات"</string> </resources> diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml index 4f3c22d187..9cadc10d25 100644 --- a/quickstep/res/values-as/strings.xml +++ b/quickstep/res/values-as/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"টাস্কবাৰ অ’ভাৰফ্ল"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"বাবল হিচাপে এপ্টো খোলক"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্}one{অধিক এপ্}other{অধিক এপ্}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"এপৰ আইকন"</string> <string name="header_default_app_title" msgid="8308052350689531566">"এপৰ শিৰোনাম"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"বন্ধ কৰা বুটাম"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"টাস্কবাৰত পিন কৰক"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"টাস্কবাৰৰ পৰা আনপিন কৰক"</string> </resources> diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index f7f22e29fc..bf34d27520 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tapşırıqlar Paneli üzrə əlavə menyu"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Tətbiqi yumrucuq kimi açın"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Tətbiq ikonası"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Tətbiq başlığı"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Qapatma düyməsi"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"İşləmə panelinə bərkidin"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"İşləmə panelindən çıxarın"</string> </resources> diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index 67ecbcd62d..14724e95eb 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Preklopna traka zadataka"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Naziv aplikacije"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Dugme Zatvori"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Zakači za traku zad."</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkači sa trake zad."</string> </resources> diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml index 436ed3f01d..5f55b41df2 100644 --- a/quickstep/res/values-be/strings.xml +++ b/quickstep/res/values-be/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Меню з пашырэннем панэлі задач"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Адкрыць праграму ва ўсплывальным акне"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Працоўны стол"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, крыніца: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Значок праграмы"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Назва праграмы"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрыць\""</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Замацаваць на панэлі"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Адмацаваць ад панэлі"</string> </resources> diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index 922a473d95..871501f64e 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Меню при препълване на лентата на задачите"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отваряне на приложението като балонче"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за настолни компютри"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Икона на приложението"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Име на приложението"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Бутон за затваряне"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Лент. на зад.: фикс."</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Лент. на зад.: осв."</string> </resources> diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml index 974994a48d..a1e30bb00d 100644 --- a/quickstep/res/values-bn/strings.xml +++ b/quickstep/res/values-bn/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"টাস্কবার ওভারফ্লো"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"বাবল হিসেবে অ্যাপ খুলুন"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"অ্যাপ আইকন"</string> <string name="header_default_app_title" msgid="8308052350689531566">"অ্যাপের শিরোনাম"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"বন্ধ করার বোতাম"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"টাস্কবারে পিন করুন"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"টাস্কবার থেকে আনপিন করুন"</string> </resources> diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index c89f84a350..57aa3c3e30 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Preklopni meni trake zadataka"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Naslov aplikacije"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Dugme za zatvaranje"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Zakači na traku zadataka"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkači s trake zadataka"</string> </resources> diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml index 87591da093..e729ff5639 100644 --- a/quickstep/res/values-ca/strings.xml +++ b/quickstep/res/values-ca/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Menú addicional de la barra de tasques"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Obre l\'aplicació com a bombolla"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Escriptori"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icona de l\'aplicació"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Títol de l\'aplicació"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Botó Tanca"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixa a barra tasques"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Deixa de fixar"</string> </resources> diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index 6d53ca872a..5106ae3119 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Přetečení panelu aplikací"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otevřít aplikaci jako bublinu"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikace"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Název aplikace"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Tlačítko Zavřít"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Připnout na panel"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odepnout z panelu"</string> </resources> diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml index debea45b39..1328da9132 100644 --- a/quickstep/res/values-da/strings.xml +++ b/quickstep/res/values-da/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Prikmenu på proceslinjen"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Åbn appen som en boble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Computertilstand"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Knappen Luk"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fastgør til proceslinje"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Frigør fra proceslinje"</string> </resources> diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml index b4d5ac1e58..2074d5e27b 100644 --- a/quickstep/res/values-de/strings.xml +++ b/quickstep/res/values-de/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Dreipunkt-Menü der Taskleiste"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"App als Bubble öffnen"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktopmodus"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ aus <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"App-Symbol"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titel der App"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Schaltfläche „Schließen“"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"An Taskleiste pinnen"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Von Taskleiste lösen"</string> </resources> diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index 5dde857181..8951e20f5d 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Υπερχείλιση γραμμής εργαλείων"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Άνοιγμα εφαρμογής σε συννεφάκι"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Υπολογιστής"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Εικονίδιο εφαρμογής"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Τίτλος εφαρμογής"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Κουμπί κλεισίματος"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Καρφ. σε γρ. εργαλ."</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ξεκαρφ. από γρ. εργαλ."</string> </resources> diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml index eef812ceca..18e59840a0 100644 --- a/quickstep/res/values-en-rAU/strings.xml +++ b/quickstep/res/values-en-rAU/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string> </resources> diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml index d1319ce239..8f52c66954 100644 --- a/quickstep/res/values-en-rCA/strings.xml +++ b/quickstep/res/values-en-rCA/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index eef812ceca..18e59840a0 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string> </resources> diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml index eef812ceca..18e59840a0 100644 --- a/quickstep/res/values-en-rIN/strings.xml +++ b/quickstep/res/values-en-rIN/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar overflow"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Open app as a bubble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"App icon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"App title"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Close button"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Pin to taskbar"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Unpin from taskbar"</string> </resources> diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml index 17e3a7d1cf..d909af12aa 100644 --- a/quickstep/res/values-es-rUS/strings.xml +++ b/quickstep/res/values-es-rUS/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir app como burbuja"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index 69628cf53c..016e5794bb 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -92,7 +92,7 @@ <string name="allset_button_hint" msgid="2395219947744706291">"Toca el botón de inicio para ir a la pantalla de inicio"</string> <string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes empezar a usar tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> - <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ajustes de navegación del sistema"</annotation></string> + <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Opciones de navegación"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartir"</string> <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string> <string name="action_split" msgid="2098009717623550676">"Dividir"</string> @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barra de tareas ampliada"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir aplicación como burbuja"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icono de la aplicación"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Título de la aplicación"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Botón de cerrar"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fijar a la barra"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Desfijar de la barra"</string> </resources> diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml index 41cb357afe..ecf59afd75 100644 --- a/quickstep/res/values-et/strings.xml +++ b/quickstep/res/values-et/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tegumiriba ületäide"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Rakenduse avamine mullina"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Lauaarvuti"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Rakenduse ikoon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Rakenduse pealkiri"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Sulgemisnupp"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Tegumiribale kinnitamine"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Tegumiribalt vabastamine"</string> </resources> diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml index 15c47421cf..90748c09ad 100644 --- a/quickstep/res/values-eu/strings.xml +++ b/quickstep/res/values-eu/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Zereginen barraren luzapena"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ireki aplikazioa burbuila gisa"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenagailua"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Aplikazioaren ikonoa"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Aplikazioaren izena"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Ixteko botoia"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Ainguratu zereginen barran"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Kendu aingura zereginen barratik"</string> </resources> diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index 810632b1e7..ee9ed1df98 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"سرریز نوار وظیفه"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"باز کردن برنامه بهصورت حبابک"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"رایانه"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"نماد برنامه"</string> <string name="header_default_app_title" msgid="8308052350689531566">"عنوان برنامه"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"دکمه بستن"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"سنجاق به نوار وظیفه"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"برداشتن از نواروظیفه"</string> </resources> diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml index e23ae308f9..f681e0d2e7 100644 --- a/quickstep/res/values-fi/strings.xml +++ b/quickstep/res/values-fi/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tehtäväpalkin ylivuotu"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Avaa sovellus kuplana"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Tietokone"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Sovelluskuvake"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Sovelluksen nimi"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Sulje-painike"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Kiinnitä palkkiin"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Poista palkista"</string> </resources> diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml index 448abf5938..5b1f1498a8 100644 --- a/quickstep/res/values-fr-rCA/strings.xml +++ b/quickstep/res/values-fr-rCA/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barre des tâches à développer"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ouvrir l\'appli sous forme de bulle"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Bureau"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icône de l\'appli"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Nom de l\'appli"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Bouton Fermer"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Éping. (barre tâche)"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Détacher (bar. tâc.)"</string> </resources> diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml index 59310e2dce..95b448d415 100644 --- a/quickstep/res/values-fr/strings.xml +++ b/quickstep/res/values-fr/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Développement de la barre des tâches"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ouvrir l\'appli sous forme de bulle"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Mode ordinateur"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icône de l\'application"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titre de l\'application"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Bouton \"Fermer\""</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Épingler à la barre"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Désépingler de la barre"</string> </resources> diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index 994b5fd9d1..e59b4519e9 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Menú adicional da barra de tarefas"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir aplicación como unha burbulla"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icona da aplicación"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Título da aplicación"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Botón Pechar"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixar na barra"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Soltar da barra"</string> </resources> diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml index 03fbd63590..b0238d0145 100644 --- a/quickstep/res/values-gu/strings.xml +++ b/quickstep/res/values-gu/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ટાસ્કબાર ઓવરફ્લો"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"બબલ તરીકે ઍપ ખોલો"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ડેસ્કટૉપ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>થી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ઍપનું આઇકન"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ઍપનું શીર્ષક"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\'બંધ કરો\' બટન"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ટાસ્કબારમાં પિન કરો"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ટાસ્કબારમાંથી અનપિન કરો"</string> </resources> diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml index 89648d4fee..6aba44cdf0 100644 --- a/quickstep/res/values-hi/strings.xml +++ b/quickstep/res/values-hi/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओवरफ़्लो आइकॉन"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ऐप्लिकेशन को बबल के तौर पर खोलें"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> की <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> वाली सूचना"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ऐप्लिकेशन आइकॉन"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ऐप्लिकेशन का नाम"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\'बंद करें\' बटन"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबार में पिन करें"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबार से अनपिन करें"</string> </resources> diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index e4a0f7c3cc..963ce57464 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Dodatni izbornik trake sa zadacima"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvori aplikaciju kao oblačić"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Računalo"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacije"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Naziv aplikacije"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Gumb Zatvori"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Prikvači na traku"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Otkvači s trake"</string> </resources> diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml index ac97372375..093c92d797 100644 --- a/quickstep/res/values-hu/strings.xml +++ b/quickstep/res/values-hu/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Feladatsáv túlcsordulása"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Alkalmazás megnyitása buborékként"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Asztali"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, forrás: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Alkalmazásikon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Alkalmazás neve"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Bezárás gomb"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Kitűzés a feladatsávon"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Kitűzés feloldása"</string> </resources> diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml index 27ac83740c..0fa5d2d02b 100644 --- a/quickstep/res/values-hy/strings.xml +++ b/quickstep/res/values-hy/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Հավելվածների վահանակի լրացուցիչ ընտրացանկ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Բացել հավելվածը պղպջակի ձևով"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Համակարգիչ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածից"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Հավելվածի պատկերակ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Հավելվածի անվանում"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"«Փակել» կոճակ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Ամրացնել վահանակում"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Ապամրացնել վահանակից"</string> </resources> diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index 69a2a82ab0..fe28340343 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tambahan Taskbar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Buka aplikasi sebagai balon"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikon aplikasi"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Judul aplikasi"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Tombol tutup"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Sematkan ke taskbar"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Lepaskan dari taskbar"</string> </resources> diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml index a8c2770ba4..a0657ddad7 100644 --- a/quickstep/res/values-is/strings.xml +++ b/quickstep/res/values-is/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Yfirflæði á forritastiku"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Opna forrit sem blöðru"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{forrit til viðbótar}one{forrit til viðbótar}other{forrit til viðbótar}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Skjáborð"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Forritstákn"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titil forrits"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Hnappur til að loka"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Festa á forritastiku"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Losa af forritastiku"</string> </resources> diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml index 7d0bcd8873..bc795e4182 100644 --- a/quickstep/res/values-it/strings.xml +++ b/quickstep/res/values-it/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Overflow barra delle app"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Apri l\'app come fumetto"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icona dell\'app"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titolo dell\'app"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Pulsante Chiudi"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fissa alla barra app"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Sblocca da barra app"</string> </resources> diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml index 55295cf42c..3f5ddfc26b 100644 --- a/quickstep/res/values-iw/strings.xml +++ b/quickstep/res/values-iw/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"אפשרויות נוספות בסרגל האפליקציות"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"פתיחת האפליקציה בבועה"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"מחשב"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מתוך <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"סמל האפליקציה"</string> <string name="header_default_app_title" msgid="8308052350689531566">"שם האפליקציה"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"כפתור הסגירה"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"הצמדה לסרגל האפליקציות"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ביטול ההצמדה לסרגל"</string> </resources> diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index b66126f5a1..d6f64a59b3 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -140,9 +140,15 @@ <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string> <string name="open_app_as_a_bubble" msgid="6642626287247807473">"アプリをバブルとして開く"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"デスクトップ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string> diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml index 0608631429..1ea1eeab7e 100644 --- a/quickstep/res/values-ka/strings.xml +++ b/quickstep/res/values-ka/strings.xml @@ -140,9 +140,15 @@ <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string> <string name="open_app_as_a_bubble" msgid="6642626287247807473">"აპის გახსნა ბუშტის სახით"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"დესკტოპი"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>-იდან"</string> diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml index 8e18fab93d..b06ac371d6 100644 --- a/quickstep/res/values-kk/strings.xml +++ b/quickstep/res/values-kk/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"\"Тапсырмалар жолағы\" қосымша мәзірі"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Қолданбаны қалқыма терезе түрінде ашу"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ұсынатын <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Қолданба белгішесі"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Қолданба атауы"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\"Жабу\" түймесі"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Тапсырмалар жолағына бекіту"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Тапсырмалар жолағынан босату"</string> </resources> diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index 44f7fe4602..6686851340 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ម៉ឺនុយបន្ថែមរបារកិច្ចការ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"បើកកម្មវិធីជាផ្ទាំងសារ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"អេក្រង់ដើម"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"រូបកម្មវិធី"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ចំណងជើងកម្មវិធី"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"ប៊ូតុងបិទ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ខ្ទាស់ទៅរបារកិច្ចការ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ដកខ្ទាស់ពីរបារកិច្ចការ"</string> </resources> diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 2187634d54..3bb3d46a22 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -140,9 +140,15 @@ <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ಆ್ಯಪ್ ಅನ್ನು ಬಬಲ್ ಆಗಿ ತೆರೆಯಿರಿ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ಡೆಸ್ಕ್ಟಾಪ್"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್ಫ್ಲೋ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಂದ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml index e5e53593e7..367908f99d 100644 --- a/quickstep/res/values-ko/strings.xml +++ b/quickstep/res/values-ko/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"태스크 바 오버플로"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"앱을 대화창으로 열기"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"데스크톱"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"앱 아이콘"</string> <string name="header_default_app_title" msgid="8308052350689531566">"앱 제목"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"닫기 버튼"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"태스크 바에 고정"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"태스크 바에서 고정 해제"</string> </resources> diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml index d23ee7e67a..834e38fac4 100644 --- a/quickstep/res/values-ky/strings.xml +++ b/quickstep/res/values-ky/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"\"Тапшырмалар панели\" кошумча менюсу"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Колдонмону көбүкчө катары ачуу"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Колдонмонун сүрөтчөсү"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Колдонмонун аталышы"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Жабуу баскычы"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Тапшырмалар панелине кадоо"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Тапшырмалар панелинен алып коюу"</string> </resources> diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml index 84073114c1..80b745b2b6 100644 --- a/quickstep/res/values-lo/strings.xml +++ b/quickstep/res/values-lo/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ສ່ວນເພີ່ມເຕີມຂອງແຖບໜ້າວຽກ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ເປີດແອັບເປັນຟອງ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ເດັສທັອບ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ໄອຄອນແອັບ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ຊື່ແອັບ"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"ປຸ່ມປິດ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ປັກໝຸດໄປໃສ່ແຖບໜ້າວຽກ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ຖອດປັກໝຸດຈາກແຖບໜ້າວຽກ"</string> </resources> diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index 268eeb7268..bb1fff342e 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Atidaryti programą kaip burbulą"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildoma programa}one{papildoma programa}few{papildomos programos}many{papildomos programos}other{papildomų programų}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Stalinis kompiuteris"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string> diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index ad83c24a44..c3c21a69cb 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Uzdevumu joslas pārpilde"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Atvērt lietotni kā burbuli"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Darbvirsma"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Lietotnes ikona"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Lietotnes nosaukums"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Poga Aizvērt"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Piespraust uzdevumu joslai"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Atspraust no uzdevumu joslas"</string> </resources> diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index 96edee69ac..7362c82ff6 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Проширено балонче на „Лента со задачи“"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отвори апликација како балонче"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за компјутер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Икона за апликацијата"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Наслов на апликацијата"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Копче за затворање"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Закачи на лентата"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Откачи од лентата"</string> </resources> diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 628acd1bec..9aa1d1c51d 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ടാസ്ക്ബാർ ഓവർഫ്ലോ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ആപ്പ് ഒരു ബബിളായി തുറക്കുക"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ഡെസ്ക്ടോപ്പ്"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ആപ്പ് ഐക്കൺ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ആപ്പിന്റെ പേര്"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"അടയ്ക്കുക ബട്ടൺ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ടാസ്ക്ബാറിൽ ചേർക്കൂ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ടാസ്ക്ബാറിൽ നിന്ന് മാറ്റൂ"</string> </resources> diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index ac3c40e9ee..129b75c1ec 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Ажлын хэсгийн урт цэс"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Аппыг бөмбөлөг байдлаар нээх"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Дэлгэц"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>-с ирсэн <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Aппын дүрс тэмдэг"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Аппын нэр"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Хаах товч"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Ажлын хэсэгт бэхлэх"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Бэхэлснийг болиулах"</string> </resources> diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml index 6f8234308b..818b824539 100644 --- a/quickstep/res/values-mr/strings.xml +++ b/quickstep/res/values-mr/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओव्हरफ्लो"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"बबल म्हणून अॅप उघडा"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अॅप}other{आणखी अॅप्स}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> वरील <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"अॅपचा आयकन"</string> <string name="header_default_app_title" msgid="8308052350689531566">"अॅपचे शीर्षक"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"बंद करा बटण"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबारवर पिन करा"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबारवरून अनपिन करा"</string> </resources> diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml index b85b62c09c..c06811beeb 100644 --- a/quickstep/res/values-ms/strings.xml +++ b/quickstep/res/values-ms/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Limpahan Bar Tugas"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Buka apl sebagai gelembung"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikon apl"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Tajuk apl"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Butang tutup"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Semat pada bar tugas"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Nyahsemat drpd bar tugas"</string> </resources> diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index 467ef26650..b556deddc8 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar မီနူးအပို"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"အက်ပ်ကို ပူဖောင်းကွက်အဖြစ် ဖွင့်ရန်"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ဒက်စ်တော့"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"အက်ပ်သင်္ကေတ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"အက်ပ်ခေါင်းစဉ်"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"အပိတ် ခလုတ်"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Taskbar ၌ ပင်ထိုးရန်"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Taskbar မှ ဖြုတ်ရန်"</string> </resources> diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml index 2690a61b8b..4528a83cc3 100644 --- a/quickstep/res/values-nb/strings.xml +++ b/quickstep/res/values-nb/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Overflyt for oppgavelinjen"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Åpne appen som en boble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Skrivebord"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Apptittel"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Lukkeknapp"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fest i oppgavelinjen"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Løsne i oppgavelinje"</string> </resources> diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index d03fcceaa4..2d35a223c8 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"टास्कबार ओभरफ्लो"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"एपलाई बबलका रूपमा खोल्नुहोस्"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> मा देखाइएका <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"एप जनाउने आइकन"</string> <string name="header_default_app_title" msgid="8308052350689531566">"एपको शीर्षक"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\"बन्द गर्नुहोस्\" बटन"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"टास्कबारमा पिन गर्नुहोस्"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"टास्कबारबाट पिन गर्नुहोस्"</string> </resources> diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml index d265f9606d..3086c40915 100644 --- a/quickstep/res/values-nl/strings.xml +++ b/quickstep/res/values-nl/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taakbalkoverloop"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"App openen als ballon"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Icoon van app"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titel van app"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Knop Sluiten"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Vastzetten op taakbalk"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Losmaken van taakbalk"</string> </resources> diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml index e19fee567d..4581f9751e 100644 --- a/quickstep/res/values-or/strings.xml +++ b/quickstep/res/values-or/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ଟାସ୍କବାର ଓଭରଫ୍ଲୋ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ଏକ ବବଲ ଭାବେ ଆପ ଖୋଲନ୍ତୁ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ଡେସ୍କଟପ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ଆପ ଆଇକନ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ଆପ ଟାଇଟେଲ"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\"ବନ୍ଦ କରନ୍ତୁ\" ବଟନ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ଟାସ୍କବାରରେ ପିନ କର"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ଟାସ୍କବାରରୁ ଅନପିନ କର"</string> </resources> diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index 4a015e4505..ac88e6fb56 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ਟਾਸਕਬਾਰ ਓਵਰਫ਼ਲੋ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ਐਪ ਨੂੰ ਬਬਲ ਵਜੋਂ ਖੋਲ੍ਹੋ"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ਡੈਸਕਟਾਪ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ਐਪ ਪ੍ਰਤੀਕ"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ਐਪ ਸਿਰਲੇਖ"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\'ਬੰਦ ਕਰੋ\' ਬਟਨ"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ਟਾਸਕਬਾਰ \'ਤੇ ਪਿੰਨ ਕਰੋ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ਟਾਸਕਬਾਰ ਤੋਂ ਅਣਪਿੰਨ ਕਰੋ"</string> </resources> diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml index 89297a2417..090dc4ccf3 100644 --- a/quickstep/res/values-pl/strings.xml +++ b/quickstep/res/values-pl/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Rozwijany pasek aplikacji"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otwórz aplikację jako dymek"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Pulpit"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikacji"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Tytuł aplikacji"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Przycisk Zamknij"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Przypnij do paska"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odepnij od paska"</string> </resources> diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml index 8c3818253f..ff5dbf72d5 100644 --- a/quickstep/res/values-pt-rPT/strings.xml +++ b/quickstep/res/values-pt-rPT/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir app como um balão"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index 5ea0194dd0..bc0b8382a4 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Barra de tarefas flutuante"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Abrir o app como um balão"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ícone do app"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Título do app"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Botão \"Fechar\""</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixar na barra de tarefas"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Liberar da barra de tarefas"</string> </resources> diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml index 08e4081527..0d1aab1a87 100644 --- a/quickstep/res/values-ro/strings.xml +++ b/quickstep/res/values-ro/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Meniu suplimentar pentru bara de activități"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Deschide aplicația ca balon"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicație suplimentară}few{mai multe aplicații}other{mai multe aplicații}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Pictograma aplicației"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titlul aplicației"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Buton de închidere"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fixează pe bara de activități"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Anulează fixarea din bara de activități"</string> </resources> diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index 65af36f590..3cf299d669 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Дополнительное меню панели задач"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Открыть приложение во всплывающем окне"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим компьютера"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Значок приложения"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Название приложения"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрыть\""</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Закрепить на панели"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Открепить от панели"</string> </resources> diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index 7e00beb83e..0b4efc4210 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"කාර්ය තීරුව පිටාර යාම"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"යෙදුම බුබුලක් ලෙස විවෘත කරන්න"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ඩෙස්ක්ටොපය"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> සිට <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"යෙදුම් නිරූපකය"</string> <string name="header_default_app_title" msgid="8308052350689531566">"යෙදුම් මාතෘකාව"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"වැසීමේ බොත්තම"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"කාර්ය තීරුවට අමුණන්න"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"කාර්ය තීරුවෙන් ඉවත් කරන්න"</string> </resources> diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index 1170e711e6..9ca4ae7d89 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Rozšírená ponuka panela aplikácií"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Otvoriť aplikáciu ako bublinu"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ďalšia aplikácia}few{ďalšie aplikácie}many{ďalšie aplikácie}other{ďalšie aplikácie}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona aplikácie"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Názov aplikácie"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Tlačidlo Zavrieť"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Pripnúť na panel"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Odopnúť z panela"</string> </resources> diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index 9ed661cf35..9a437bcc59 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Odpri aplikacijo kot oblaček"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}two{dodatni aplikaciji}few{dodatne aplikacije}other{dodatnih aplikacij}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Namizni računalnik"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index 965699dd1f..c72b926ec5 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Tejkalimi i shiritit të detyrave"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Hap aplikacionin si një flluskë"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ikona e aplikacionit"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Titulli i aplikacionit"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Butoni i mbylljes"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Gozhdo te shiriti"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Zhgozhdo nga shiriti"</string> </resources> diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index c827cdabd9..c418302ad6 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Преклопна трака задатака"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Отвори апликацију као облачић"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Рачунар"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Икона апликације"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Назив апликације"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Дугме Затвори"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Закачи за траку зад."</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Откачи са траке зад."</string> </resources> diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml index 5713036419..76c8d3dbeb 100644 --- a/quickstep/res/values-sv/strings.xml +++ b/quickstep/res/values-sv/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Fler alternativ för aktivitetsfältet"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Öppna appen som en bubbla"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Skrivbordsläge"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Appikon"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Apptitel"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Knappen Stäng"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Fäst i aktivitetsfält"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Lossa från aktivitetsfält"</string> </resources> diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index f1dbcbc807..ca800d9867 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Upauzana wa Vipengele vya Ziada"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Fungua programu kama kiputo"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuta ya Mezani"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Aikoni ya programu"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Kichwa cha programu"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Kitufe cha kufunga"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Bandika kwa upauzana"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Bandua kwa upauzana"</string> </resources> diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml index 04dfc30206..236982a037 100644 --- a/quickstep/res/values-ta/strings.xml +++ b/quickstep/res/values-ta/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"செயல் பட்டிக்கான கூடுதல் விருப்பங்கள்"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ஆப்ஸைக் குமிழாகத் திற"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"டெஸ்க்டாப்"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> வழங்கும் <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ஆப்ஸ் ஐகான்"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ஆப்ஸ் தலைப்பு"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"மூடுவதற்கான பட்டன்"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"செயல்பட்டியில் பின் செய்"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"செயல்பட்டியிலிருந்து அகற்று"</string> </resources> diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 516c2f76dc..d5bc982dba 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -140,9 +140,15 @@ <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string> <string name="open_app_as_a_bubble" msgid="6642626287247807473">"యాప్ను బబుల్లాగా తెరవండి"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్}other{మరిన్ని యాప్లు}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"డెస్క్టాప్"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్ఫ్లో"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 04eac38e9d..67673582c5 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"การดำเนินการเพิ่มเติมของแถบงาน"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"เปิดแอปเป็นบับเบิล"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"เดสก์ท็อป"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ไอคอนแอป"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ชื่อแอป"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"ปุ่มปิด"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ปักหมุดไปยังแถบงาน"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"เลิกปักหมุดจากแถบงาน"</string> </resources> diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index 89ead25e90..479a5d358f 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -140,9 +140,15 @@ <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="open_app_as_a_bubble" msgid="6642626287247807473">"Buksan ang app bilang bubble"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> + <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index f2c42d074a..e68056ad0f 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Görev Çubuğu Taşması"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Uygulamayı balon olarak aç"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Uygulama simgesi"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Uygulama başlığı"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Kapat düğmesi"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Çubuğa sabitle"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Çubuktan kaldır"</string> </resources> diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 82d8a60121..350b23b85c 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Додаткове меню панелі завдань"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Відкрити додаток у спливаючому вікні"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Комп’ютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> з додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Значок додатка"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Назва додатка"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Кнопка \"Закрити\""</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"На панель завдань"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"З панелі завдань"</string> </resources> diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml index 65436ae48b..3b46f51cc5 100644 --- a/quickstep/res/values-ur/strings.xml +++ b/quickstep/res/values-ur/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"ٹاسک بار اوورفلو"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"ایپ کو بطور ببل کھولیں"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"ڈیسک ٹاپ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"ایپ آئیکن"</string> <string name="header_default_app_title" msgid="8308052350689531566">"ایپ کا عنوان"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"\'بند کریں\' بٹن"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"ٹاسک بار میں پن کریں"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"ٹاسک بار سے پن ہٹائیں"</string> </resources> diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml index b761b5da3f..3f616580a6 100644 --- a/quickstep/res/values-uz/strings.xml +++ b/quickstep/res/values-uz/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Vazifalar panelini kengaytirish"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Ilovani qalqib chiquvchi oynada ochish"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuter"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Ilova belgisi"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Ilova nomi"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Yopish tugmasi"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Panelga qadash"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Vazifalar panelidan yechib olish"</string> </resources> diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 383f915989..6f486606b3 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Trình đơn mục bổ sung trên thanh tác vụ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Mở ứng dụng dưới dạng bong bóng"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Máy tính"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Biểu tượng ứng dụng"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Tên ứng dụng"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Nút đóng"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Ghim vào thanh tác vụ"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Bỏ ghim khỏi thanh tác vụ"</string> </resources> diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml index 17d022eef0..8e8badc88b 100644 --- a/quickstep/res/values-zh-rCN/strings.xml +++ b/quickstep/res/values-zh-rCN/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"任务栏溢出图标"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"以气泡的形式打开应用"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面模式"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"来自“<xliff:g id="APP_NAME">%2$s</xliff:g>”的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"应用图标"</string> <string name="header_default_app_title" msgid="8308052350689531566">"应用名称"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"“关闭”按钮"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"固定到任务栏"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"从任务栏取消固定"</string> </resources> diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index 47bb6d460c..9f5745a35d 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"工作列溢位"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"在小視窗開啟應用程式"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> 的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"應用程式圖示"</string> <string name="header_default_app_title" msgid="8308052350689531566">"應用程式名稱"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"關閉按鈕"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"固定至工作列"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"取消固定至工作列"</string> </resources> diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index 58c7bb52fe..d11cafda29 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"工作列溢位"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"以泡泡形式開啟應用程式"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"電腦模式"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"應用程式圖示"</string> <string name="header_default_app_title" msgid="8308052350689531566">"應用程式標題"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"關閉按鈕"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"固定到工作列"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"從工作列中取消固定"</string> </resources> diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index 8d0a6dbcbe..1d9996599f 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -139,11 +139,16 @@ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Ukuphuphuma Kwetaskbar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string> - <!-- no translation found for open_app_as_a_bubble (6642626287247807473) --> + <string name="open_app_as_a_bubble" msgid="6642626287247807473">"Vula i-app njengebhamuza"</string> + <!-- no translation found for quick_switch_pane_title (4677158207760585812) --> + <skip /> + <!-- no translation found for quick_switch_content_description (2851244536728720005) --> <skip /> <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string> <string name="quick_switch_desktop" msgid="8393802056024499749">"Ideskithophu"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> + <!-- no translation found for quick_switch_task_with_position_in_parent (4968670948331508951) --> + <skip /> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string> <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string> @@ -157,8 +162,6 @@ <string name="header_app_icon_description" msgid="2184625881433608027">"Isithonjana se-app"</string> <string name="header_default_app_title" msgid="8308052350689531566">"Isihloko se-app"</string> <string name="header_close_icon_description" msgid="5400033616675911319">"Inkinobho yokuvala"</string> - <!-- no translation found for pin_to_taskbar (6607778046321626950) --> - <skip /> - <!-- no translation found for unpin_from_taskbar (2178811773165572676) --> - <skip /> + <string name="pin_to_taskbar" msgid="6607778046321626950">"Phina kutaskbar"</string> + <string name="unpin_from_taskbar" msgid="2178811773165572676">"Susa ukuphina i-taskbar"</string> </resources> diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index e69fa4d9fe..1ce28cf995 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -47,6 +47,7 @@ <string name="wellbeing_provider_pkg" translatable="false"/> <integer name="max_depth_blur_radius">23</integer> + <dimen name="max_depth_blur_radius_enhanced">34dp</dimen> <!-- If predicted widgets from prediction service are less than this number, additional eligible widgets may be added locally by launcher. When set to 0, no widgets will be added diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 36e6902972..aa9e8241b7 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -82,9 +82,9 @@ <dimen name="task_thumbnail_icon_menu_drawable_touch_size">44dp</dimen> <dimen name="task_thumbnail_icon_menu_elevation">4dp</dimen> <!-- The size of the task thumbnail header --> - <dimen name="task_thumbnail_header_height">30dp</dimen> - <dimen name="task_thumbnail_header_margin_edge">18dp</dimen> - <dimen name="task_thumbnail_header_margin_between_views">9dp</dimen> + <dimen name="task_thumbnail_header_padding_top_bottom">6dp</dimen> + <dimen name="task_thumbnail_header_padding_start_end">12dp</dimen> + <dimen name="task_thumbnail_header_margin_between_views">8dp</dimen> <dimen name="task_thumbnail_header_icon_size">18dp</dimen> <dimen name="task_thumbnail_header_round_corner_radius">16dp</dimen> @@ -510,7 +510,8 @@ <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen> <!-- Keyboard Quick Switch --> - <dimen name="keyboard_quick_switch_border_width">4dp</dimen> + <dimen name="keyboard_quick_switch_border_width">5dp</dimen> + <dimen name="keyboard_quick_switch_border_stroke">3dp</dimen> <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen> <dimen name="keyboard_quick_switch_taskview_height">136dp</dimen> <dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen> @@ -531,8 +532,8 @@ <dimen name="keyboard_quick_switch_text_button_fade_edge_length">20dp</dimen> <dimen name="keyboard_quick_switch_scroll_button_width">36dp</dimen> <dimen name="keyboard_quick_switch_scroll_button_height">56dp</dimen> - <dimen name="keyboard_quick_switch_scroll_button_horizontal_padding">12dp</dimen> - <dimen name="keyboard_quick_switch_scroll_button_vertical_padding">32dp</dimen> + <dimen name="keyboard_quick_switch_scroll_button_horizontal_padding">6dp</dimen> + <dimen name="keyboard_quick_switch_scroll_button_vertical_padding">16dp</dimen> <dimen name="keyboard_quick_switch_scroll_button_corner_radius">18dp</dimen> <!-- Digital Wellbeing --> diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index 7578bd546f..f263f7efc3 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -345,12 +345,10 @@ <!-- Accessibility label for quick switch tiles that include information about the tile's position in the parent list [CHAR LIMIT=NONE] --> <string name="quick_switch_task_with_position_in_parent"><xliff:g id="task_description" example="Chrome">%1$s</xliff:g>, item <xliff:g id="index_in_parent" example="1">%2$d</xliff:g> of <xliff:g id="total_tasks" example="5">%3$d</xliff:g></string> - <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content left - TODO(b/397975686): Make these translatable when verified by UX. --> - <string name="quick_switch_scroll_arrow_left" translatable="false">Scroll left</string> - <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content right - TODO(b/397975686): Make these translatable when verified by UX. --> - <string name="quick_switch_scroll_arrow_right" translatable="false">Scroll right</string> + <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content left --> + <string name="quick_switch_scroll_arrow_left">Scroll left</string> + <!-- Accessibility label for an arrow button within quick switch UI that scrolls the quick switch content right --> + <string name="quick_switch_scroll_arrow_right">Scroll right</string> <!-- Strings for bubble bar --> <!-- Fallback name for a bubble if it does have a title [CHAR_LIMIT=none] --> diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index aae8a56593..954272c612 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -92,6 +92,7 @@ import android.os.Looper; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; +import android.util.Log; import android.util.Pair; import android.util.Size; import android.view.CrossWindowBlurListeners; @@ -182,6 +183,7 @@ import java.util.Map.Entry; * Manages the opening and closing app transitions from Launcher */ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener { + private static final String TAG = "QuickstepTransitionManager"; private static final boolean ENABLE_SHELL_STARTING_SURFACE = SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); @@ -1207,7 +1209,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener mLauncher.removeOnDeviceProfileChangeListener(this); SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null); if (BuildConfig.IS_STUDIO_BUILD && !mRegisteredTaskStackChangeListener.isEmpty()) { - throw new IllegalStateException("Failed to run onEndCallback created from" + Log.e(TAG, "IllegalState: Failed to run onEndCallback created from" + " getActivityLaunchOptions()"); } mRegisteredTaskStackChangeListener.forEach(TaskRestartedDuringLaunchListener::unregister); diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java index 4d3e3bea67..cdae9caa5c 100644 --- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java +++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java @@ -166,7 +166,7 @@ public class WidgetPickerActivity extends BaseActivity implements mApp = LauncherAppState.getInstance(this); InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile(); mDeviceProfile = idp.getDeviceProfile(this); - mModel = new WidgetsModel(); + mModel = new WidgetsModel(mApp.getContext()); mWidgetPickerDataProvider = new WidgetPickerDataProvider(this); setContentView(R.layout.widget_picker_activity); @@ -309,8 +309,7 @@ public class WidgetPickerActivity extends BaseActivity implements */ private void refreshAndBindWidgets() { MODEL_EXECUTOR.execute(() -> { - LauncherAppState app = LauncherAppState.getInstance(this); - mModel.update(app, null); + mModel.update(null); StringCache stringCache = new StringCache(); stringCache.loadStrings(this); @@ -321,9 +320,10 @@ public class WidgetPickerActivity extends BaseActivity implements // animation. openWidgetsSheet(); if (mUiSurface != null) { - mWidgetPredictionsRequester = new WidgetPredictionsRequester(app.getContext(), - mUiSurface, mModel.getWidgetsByComponentKeyForPicker()); - mWidgetPredictionsRequester.request(mAddedWidgets, /*listener=*/ this); + mWidgetPredictionsRequester = new WidgetPredictionsRequester( + getApplicationContext(), mUiSurface, + mModel.getWidgetsByComponentKeyForPicker()); + mWidgetPredictionsRequester.request(mAddedWidgets, this); } }); } diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt index 1438edf8ef..a9e5145530 100644 --- a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt +++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt @@ -93,7 +93,7 @@ class DesktopAppLaunchAnimatorHelper( } if (trampolineCloseChange != null) { val trampolineCloseAnimator = - createTrampolineCloseAnimator(trampolineCloseChange, transaction) + createTrampolineCloseAnimator(trampolineCloseChange, transaction, finishCallback) animatorsList.add(trampolineCloseAnimator) } return animatorsList @@ -112,7 +112,7 @@ class DesktopAppLaunchAnimatorHelper( private fun getTrampolineCloseChange(info: TransitionInfo): Change? { if ( info.changes.size < 2 || - !DesktopModeFlags.ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX.isTrue + !DesktopModeFlags.ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX.isTrue ) { return null } @@ -194,13 +194,22 @@ class DesktopAppLaunchAnimatorHelper( ) } - private fun createTrampolineCloseAnimator(change: Change, transaction: Transaction): Animator { + private fun createTrampolineCloseAnimator( + change: Change, + transaction: Transaction, + onAnimFinish: (Animator) -> Unit, + ): Animator { return ValueAnimator.ofFloat(1f, 0f).apply { duration = 100L interpolator = Interpolators.LINEAR addUpdateListener { animation -> transaction.setAlpha(change.leash, animation.animatedValue as Float).apply() } + addListener( + onEnd = { animation -> + onAnimFinish(animation) + } + ) } } diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java index fd71151bbe..3544844bd2 100644 --- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java +++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java @@ -32,9 +32,9 @@ import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.launcher3.ConstantItem; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel.ModelUpdateTask; import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.QuickstepModelDelegate.PredictorState; import com.android.launcher3.model.data.AppInfo; @@ -65,8 +65,8 @@ public class PredictionUpdateTask implements ModelUpdateTask { @Override public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel, @NonNull AllAppsList apps) { - LauncherAppState app = taskController.getApp(); - Context context = app.getContext(); + IconCache iconCache = taskController.getIconCache(); + Context context = taskController.getContext(); // TODO: remove this LauncherPrefs.get(context).put(LAST_PREDICTION_ENABLED, !mTargets.isEmpty()); @@ -84,7 +84,7 @@ public class PredictionUpdateTask implements ModelUpdateTask { if (si != null) { usersForChangedShortcuts.add(si.getUserHandle()); itemInfo = new WorkspaceItemInfo(si, context); - app.getIconCache().getShortcutIcon(itemInfo, si); + iconCache.getShortcutIcon(itemInfo, si); } else { String className = target.getClassName(); if (COMPONENT_CLASS_MARKER.equals(className)) { @@ -96,7 +96,7 @@ public class PredictionUpdateTask implements ModelUpdateTask { itemInfo = apps.data.stream() .filter(info -> user.equals(info.user) && cn.equals(info.componentName)) .map(ai -> { - app.getIconCache().getTitleAndIcon(ai, mPredictorState.lookupFlag); + iconCache.getTitleAndIcon(ai, mPredictorState.lookupFlag); return ai.makeWorkspaceItem(context); }) .findAny() @@ -107,7 +107,7 @@ public class PredictionUpdateTask implements ModelUpdateTask { return null; } AppInfo ai = new AppInfo(context, lai, user); - app.getIconCache().getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG); + iconCache.getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG); return ai.makeWorkspaceItem(context); }); @@ -123,8 +123,7 @@ public class PredictionUpdateTask implements ModelUpdateTask { FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId, items); dataModel.extraItems.put(fci.containerId, fci); taskController.bindExtraContainerItems(fci); - usersForChangedShortcuts.forEach( - u -> dataModel.updateShortcutPinnedState(app.getContext(), u)); + usersForChangedShortcuts.forEach(u -> dataModel.updateShortcutPinnedState(context, u)); // Save to disk mPredictorState.storage.write(context, fci.items); diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java index 0a4b7c8d19..da55b40b19 100644 --- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java +++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java @@ -82,7 +82,7 @@ public final class WidgetsPredictionUpdateTask implements ModelUpdateTask { && !widgetsInWorkspace.contains(entry.getValue()) ).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - Context context = taskController.getApp().getContext(); + Context context = taskController.getContext(); List<WidgetItem> servicePredictedItems = new ArrayList<>(); List<String> addedWidgetApps = new ArrayList<>(); diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index 4c24d95462..360210b010 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -65,7 +65,7 @@ public class DepthController extends BaseDepthController implements StateHandler private void onLauncherDraw() { View view = mLauncher.getDragLayer(); ViewRootImpl viewRootImpl = view.getViewRootImpl(); - setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); + setBaseSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); view.post(() -> view.getViewTreeObserver().removeOnDrawListener(mOnDrawListener)); } @@ -127,7 +127,7 @@ public class DepthController extends BaseDepthController implements StateHandler mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener); } else { mLauncher.getDragLayer().getViewTreeObserver().removeOnDrawListener(mOnDrawListener); - setSurface(null); + setBaseSurface(null); } } @@ -189,7 +189,8 @@ public class DepthController extends BaseDepthController implements StateHandler writer.println(prefix + "DepthController"); writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); - writer.println(prefix + "\tmSurface=" + mSurface); + writer.println(prefix + "\tmBaseSurface=" + mBaseSurface); + writer.println(prefix + "\tmBaseSurfaceOverride=" + mBaseSurfaceOverride); writer.println(prefix + "\tmStateDepth=" + stateDepth.getValue()); writer.println(prefix + "\tmWidgetDepth=" + widgetDepth.getValue()); writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur); diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt index 2402a2827e..810fa6f082 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt @@ -691,8 +691,11 @@ constructor( "duration= " + transitionDuration), ) - controller.get()?.isInDesktopMode = true - controller.get()?.notifyTaskbarDesktopModeListenersForEntry(transitionDuration) + val controller = controller.get() + if (controller != null && !controller.isInDesktopMode) { + controller.isInDesktopMode = true + controller.notifyTaskbarDesktopModeListenersForEntry(transitionDuration) + } } } @@ -704,8 +707,11 @@ constructor( "duration= " + transitionDuration), ) - controller.get()?.isInDesktopMode = false - controller.get()?.notifyTaskbarDesktopModeListenersForExit(transitionDuration) + val controller = controller.get() + if (controller != null && controller.isInDesktopMode) { + controller.isInDesktopMode = false + controller.notifyTaskbarDesktopModeListenersForExit(transitionDuration) + } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java index 09a8670ddb..aa3feb7614 100644 --- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java @@ -23,6 +23,7 @@ import android.view.LayoutInflater; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.BaseContext; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Themes; import com.android.quickstep.SystemUiProxy; @@ -32,10 +33,20 @@ public abstract class BaseTaskbarContext extends BaseContext implements SystemShortcut.BubbleActivityStarter { protected final LayoutInflater mLayoutInflater; + private final boolean mIsPrimaryDisplay; - public BaseTaskbarContext(Context windowContext) { + public BaseTaskbarContext(Context windowContext, boolean isPrimaryDisplay) { super(windowContext, Themes.getActivityThemeRes(windowContext)); mLayoutInflater = LayoutInflater.from(this).cloneInContext(this); + mIsPrimaryDisplay = isPrimaryDisplay; + } + + public boolean isTransientTaskbar() { + return DisplayController.isTransientTaskbar(this) && mIsPrimaryDisplay; + } + + public boolean isPrimaryDisplay() { + return mIsPrimaryDisplay; } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java index 15be03a55b..c49029daf9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java @@ -129,7 +129,9 @@ public class KeyboardQuickSwitchTaskView extends ConstraintLayout { : resources.getDimensionPixelSize( R.dimen.keyboard_quick_switch_task_view_radius), /* borderWidthPx= */ resources.getDimensionPixelSize( - R.dimen.keyboard_quick_switch_border_width), + R.dimen.keyboard_quick_switch_border_width), + /* borderStrokePx= */ resources.getDimensionPixelSize( + R.dimen.keyboard_quick_switch_border_stroke), /* boundsBuilder= */ bounds -> { bounds.set(0, 0, getWidth(), getHeight()); return Unit.INSTANCE; diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java index 5f7a026469..b5f2532482 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java @@ -40,7 +40,6 @@ import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.desktop.DesktopAppLaunchTransition; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.GroupTask; @@ -106,8 +105,7 @@ public class KeyboardQuickSwitchViewController { boolean hasDesktopTask, boolean wasDesktopTaskFilteredOut, boolean wasOpenedFromTaskbar) { - final boolean isTransientTaskBar = DisplayController.isTransientTaskbar( - mControllers.taskbarActivityContext); + final boolean isTransientTaskBar = mControllers.taskbarActivityContext.isTransientTaskbar(); positionView(wasOpenedFromTaskbar, isTransientTaskBar); // Keep the taskbar unstashed if the KQS is opened. diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 62f546bb5f..e998388f33 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -225,9 +225,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController { if (isVisible || isPinnedTaskbar) { return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar); } else { - return DisplayController.isTransientTaskbar(mLauncher) - ? TRANSIENT_TASKBAR_TRANSITION_DURATION - : TASKBAR_TO_APP_DURATION; + return mControllers.taskbarActivityContext.isTransientTaskbar() + ? TRANSIENT_TASKBAR_TRANSITION_DURATION : TASKBAR_TO_APP_DURATION; } } @@ -337,7 +336,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } // Persistent features EDU tooltip. - if (!DisplayController.isTransientTaskbar(mLauncher)) { + if (!mControllers.taskbarActivityContext.isTransientTaskbar()) { mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu(); return; } @@ -360,7 +359,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } // Persistent features EDU tooltip. - if (!DisplayController.isTransientTaskbar(mLauncher)) { + if (!mControllers.taskbarActivityContext.isTransientTaskbar()) { return !OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.hasReachedMax(mLauncher); } diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index ee5b8d1285..33cd75966a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -42,8 +42,8 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISMISS_IME; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; @@ -487,8 +487,17 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mPropertyHolders.add( new StatePropertyHolder(mHomeButtonAlpha.get( ALPHA_INDEX_KEYGUARD_OR_DISABLE), - flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 - && (flags & FLAG_DISABLE_HOME) == 0 && !mContext.isGestureNav())); + flags -> { + /* when the keyguard is visible hide home button. Anytime we are + * occluded we want to show the home button for apps over keyguard. + * however we don't want to show when not occluded/visible. + * (visible false || occluded true) && disable false && not gnav + */ + return ((flags & FLAG_KEYGUARD_VISIBLE) == 0 + || (flags & FLAG_KEYGUARD_OCCLUDED) != 0) + && (flags & FLAG_DISABLE_HOME) == 0 + && !mContext.isGestureNav(); + })); // Recents button mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS, @@ -870,6 +879,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT if (predictiveBackThreeButtonNav() && buttonType == BUTTON_BACK) { // set up special touch listener for back button to support predictive back setBackButtonTouchListener(buttonView, navButtonController); + // Set this View clickable, so that NearestTouchFrame.java forwards closeby touches to + // this View + buttonView.setClickable(true); } else { buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType, view)); diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index 2e5bebcb1b..6bd3d855e2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -36,7 +36,6 @@ 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.util.DisplayController; import com.android.launcher3.util.Executors; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; @@ -217,7 +216,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT .getTransientTaskbarIconLayoutBounds(); float startRadius = mStashedHandleRadius; - if (DisplayController.isTransientTaskbar(mActivity)) { + if (mActivity.isTransientTaskbar()) { // Account for the full visual height of the transient taskbar. int heightDiff = (mTaskbarSize - visualBounds.height()) / 2; visualBounds.top -= heightDiff; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 6afbebf0a9..e41b2d2748 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -99,6 +99,7 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; +import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.apppairs.AppPairIcon; import com.android.launcher3.config.FeatureFlags; @@ -138,6 +139,7 @@ import com.android.launcher3.taskbar.bubbles.stashing.PersistentBubbleStashContr import com.android.launcher3.taskbar.bubbles.stashing.TransientBubbleStashController; import com.android.launcher3.taskbar.customization.TaskbarFeatureEvaluator; import com.android.launcher3.taskbar.customization.TaskbarSpecsEvaluator; +import com.android.launcher3.taskbar.growth.NudgeController; import com.android.launcher3.taskbar.navbutton.NearestTouchFrame; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; import com.android.launcher3.testing.TestLogging; @@ -255,7 +257,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider, boolean isPrimaryDisplay, SystemUiProxy sysUiProxy) { - super(windowContext); + super(windowContext, isPrimaryDisplay); mIsPrimaryDisplay = isPrimaryDisplay; mNavigationBarPanelContext = navigationBarPanelContext; mSysUiProxy = sysUiProxy; @@ -380,19 +382,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new TaskbarPinningController(this), bubbleControllersOptional, new TaskbarDesktopModeController(this, - DesktopVisibilityController.INSTANCE.get(this))); + DesktopVisibilityController.INSTANCE.get(this)), + new NudgeController(this)); mLauncherPrefs = LauncherPrefs.get(this); onViewCreated(); } - /** - * Returns whether this is a primary display. - */ - public boolean isPrimaryDisplay() { - return mIsPrimaryDisplay; - } - /** Updates {@link DeviceProfile} instances for any Taskbar windows. */ public void updateDeviceProfile(DeviceProfile launcherDp) { applyDeviceProfile(launcherDp); @@ -411,7 +407,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { /** Returns whether current taskbar is transient. */ public boolean isTransientTaskbar() { - return DisplayController.isTransientTaskbar(this) && !isPhoneMode(); + return super.isTransientTaskbar() && !isPhoneMode(); } /** @@ -432,7 +428,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mDeviceProfile = originDeviceProfile.toBuilder(this) .withDimensionsOverride(overrideProvider).build(); - if (DisplayController.isTransientTaskbar(this)) { + if (isTransientTaskbar()) { mTransientTaskbarDeviceProfile = mDeviceProfile; mPersistentTaskbarDeviceProfile = mDeviceProfile .toBuilder(this) @@ -450,7 +446,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mNavMode = (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue() && !mIsPrimaryDisplay) ? NavigationMode.THREE_BUTTONS : DisplayController.getNavigationMode(this); - } /** Called when the visibility of the bubble bar changed. */ @@ -661,8 +656,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SLIPPERY | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; - boolean watchOutside = DisplayController.isTransientTaskbar(this) - || isThreeButtonNav(); + boolean watchOutside = isTransientTaskbar() || isThreeButtonNav(); if (watchOutside && !isRunningInTestHarness()) { windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; @@ -1223,8 +1217,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { bubbleControllers.bubbleBarViewController.getBubbleBarWithFlyoutMaximumHeight() ).orElse(0); int taskbarWindowSize; - boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this) - || (enableTaskbarPinning() && !isThreeButtonNav()); + boolean shouldTreatAsTransient = + isTransientTaskbar() || (enableTaskbarPinning() && !isThreeButtonNav()); int extraHeightForTaskbarTooltips = enableCursorHoverStates() ? resources.getDimensionPixelSize(R.dimen.arrow_toast_arrow_height) @@ -1297,7 +1291,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { * Applies forcibly show flag to taskbar window iff transient taskbar is unstashed. */ public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) { - if (!DisplayController.isTransientTaskbar(this) || isPhoneMode()) { + if (!isTransientTaskbar() || isPhoneMode()) { return; } if (shouldForceShow) { @@ -1344,7 +1338,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.uiController.startSplitSelection(splitSelectSource); } - boolean areDesktopTasksVisible() { + boolean isInDesktopMode() { return mControllers != null && mControllers.taskbarDesktopModeController.isInDesktopMode(getDisplayId()); } @@ -1360,23 +1354,23 @@ public class TaskbarActivityContext extends BaseTaskbarContext { // TODO: b/316004172, b/343289567: Handle `DesktopTask` and `SplitTask`. if (tag instanceof SingleTask singleTask) { RemoteTransition remoteTransition = - (areDesktopTasksVisible() && canUnminimizeDesktopTask( + (isInDesktopMode() && canUnminimizeDesktopTask( singleTask.getTask().key.id)) ? createDesktopAppLaunchRemoteTransition(AppLaunchType.UNMINIMIZE, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON) : null; - if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) { + if (isInDesktopMode() && mControllers.uiController.isInOverviewUi()) { RunnableList runnableList = recents.launchRunningDesktopTaskView(); // Wrapping it in runnable so we post after DW is ready for the app // launch. if (runnableList != null) { runnableList.add(() -> UI_HELPER_EXECUTOR.execute( () -> handleGroupTaskLaunch(singleTask, remoteTransition, - areDesktopTasksVisible(), + isInDesktopMode(), DesktopTaskToFrontReason.TASKBAR_TAP))); } } else { - handleGroupTaskLaunch(singleTask, remoteTransition, areDesktopTasksVisible(), + handleGroupTaskLaunch(singleTask, remoteTransition, isInDesktopMode(), DesktopTaskToFrontReason.TASKBAR_TAP); } mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); @@ -1402,7 +1396,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { : null; - if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) { + if (isInDesktopMode() && mControllers.uiController.isInOverviewUi()) { RunnableList runnableList = recents.launchRunningDesktopTaskView(); if (runnableList != null) { runnableList.add(() -> @@ -1676,7 +1670,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { .launchAppPair((AppPairIcon) launchingIconView, -1 /*cuj*/))); } else { - if (areDesktopTasksVisible() + if (isInDesktopMode() && mControllers.uiController.isInOverviewUi()) { RunnableList runnableList = recents.launchRunningDesktopTaskView(); // Wrapping it in runnable so we post after DW is ready for the app @@ -1722,7 +1716,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return; } } - if (areDesktopTasksVisible() + if (isInDesktopMode() && DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) { launchDesktopApp(intent, info, displayId); } else { @@ -1887,7 +1881,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { */ @VisibleForTesting public void unstashTaskbarIfStashed() { - if (DisplayController.isTransientTaskbar(this)) { + if (isTransientTaskbar()) { mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); } } @@ -1950,6 +1944,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { // Override the alpha updates in the icon alignment animation. allAppsButton.setAlpha(0); }); + alphaOverride.addListener(AnimatorListeners.forSuccessCallback( + () -> allAppsButton.setAlpha(1f))); fullAnimation.play(alphaOverride); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index 89cc991387..5e02d81035 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -30,7 +30,6 @@ import com.android.launcher3.Utilities.mapToRange import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT -import com.android.launcher3.util.DisplayController import kotlin.math.min /** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */ @@ -43,7 +42,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { private val maxPersistentTaskbarHeight = context.persistentTaskbarDeviceProfile.taskbarHeight.toFloat() var backgroundProgress = - if (DisplayController.isTransientTaskbar(context)) { + if (context.isTransientTaskbar) { PINNING_TRANSIENT } else { PINNING_PERSISTENT @@ -102,7 +101,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { fullCornerRadius = context.cornerRadius.toFloat() cornerRadius = fullCornerRadius - if (!context.areDesktopTasksVisible()) { + if (!context.isInDesktopMode()) { setCornerRoundness(MAX_ROUNDNESS) } } @@ -124,7 +123,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { * @param cornerRoundness 0 has no round corner, 1 has complete round corner. */ fun setCornerRoundness(cornerRoundness: Float) { - if (DisplayController.isTransientTaskbar(context) && !transientBackgroundBounds.isEmpty) { + if (context.isTransientTaskbar && !transientBackgroundBounds.isEmpty) { return } @@ -146,7 +145,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { /** Draws the background with the given paint and height, on the provided canvas. */ fun draw(canvas: Canvas) { if (isInSetup) return - val isTransientTaskbar = DisplayController.isTransientTaskbar(context) + val isTransientTaskbar = context.isTransientTaskbar canvas.save() if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) { drawPersistentBackground(canvas) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 58606de9e1..9e15a60ed1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -25,6 +25,7 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.taskbar.bubbles.BubbleControllers; +import com.android.launcher3.taskbar.growth.NudgeController; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; import com.android.systemui.shared.rotation.RotationButtonController; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; @@ -67,6 +68,7 @@ public class TaskbarControllers { public final TaskbarPinningController taskbarPinningController; public final Optional<BubbleControllers> bubbleControllers; public final TaskbarDesktopModeController taskbarDesktopModeController; + public final NudgeController nudgeController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null; @@ -115,7 +117,8 @@ public class TaskbarControllers { KeyboardQuickSwitchController keyboardQuickSwitchController, TaskbarPinningController taskbarPinningController, Optional<BubbleControllers> bubbleControllers, - TaskbarDesktopModeController taskbarDesktopModeController) { + TaskbarDesktopModeController taskbarDesktopModeController, + NudgeController nudgeController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -143,6 +146,7 @@ public class TaskbarControllers { this.taskbarPinningController = taskbarPinningController; this.bubbleControllers = bubbleControllers; this.taskbarDesktopModeController = taskbarDesktopModeController; + this.nudgeController = nudgeController; } /** @@ -179,6 +183,7 @@ public class TaskbarControllers { keyboardQuickSwitchController.init(this); taskbarPinningController.init(this, mSharedState); taskbarDesktopModeController.init(this, mSharedState); + nudgeController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, @@ -189,6 +194,7 @@ public class TaskbarControllers { voiceInteractionWindowController, taskbarRecentAppsController, taskbarTranslationController, taskbarEduTooltipController, keyboardQuickSwitchController, taskbarPinningController, + nudgeController }; mBackgroundRendererControllers = new BackgroundRendererController[] { taskbarDragLayerController, taskbarScrimViewController, @@ -260,6 +266,7 @@ public class TaskbarControllers { mAreAllControllersInitialized = false; mSharedState = null; + taskbarDragController.onDestroy(); navbarButtonsViewController.onDestroy(); uiController.onDestroy(); rotationButtonController.onDestroy(); @@ -280,7 +287,6 @@ public class TaskbarControllers { taskbarStashController.onDestroy(); bubbleControllers.ifPresent(controllers -> controllers.onDestroy()); taskbarDesktopModeController.onDestroy(); - mControllersToLog = null; mBackgroundRendererControllers = null; } @@ -344,7 +350,7 @@ public class TaskbarControllers { return taskbarActivityContext; } - protected interface LoggableTaskbarController { + public interface LoggableTaskbarController { void dumpLogs(String prefix, PrintWriter pw); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt index 3f6ebe21e6..b66344413f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt @@ -35,7 +35,6 @@ import com.android.launcher3.Flags import com.android.launcher3.R import com.android.launcher3.popup.ArrowPopup import com.android.launcher3.popup.RoundedArrowDrawable -import com.android.launcher3.util.DisplayController import com.android.launcher3.util.Themes import com.android.launcher3.views.ActivityContext import kotlin.math.max @@ -70,6 +69,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 private lateinit var dividerView: View private var horizontalPosition = 0.0f + private val taskbarActivityContext: TaskbarActivityContext = + ActivityContext.lookupContext(context) private val popupCornerRadius = Themes.getDialogCornerRadius(context) private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width) @@ -78,7 +79,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 private val minPaddingFromScreenEdge = resources.getDimension(R.dimen.taskbar_pinning_popup_menu_min_padding_from_screen_edge) - private var alwaysShowTaskbarOn = !DisplayController.isTransientTaskbar(context) + // TODO: add test for isTransientTaskbar & long presses divider and ensures the popup shows up. + private var alwaysShowTaskbarOn = !taskbarActivityContext.isTransientTaskbar private var didPreferenceChange = false private var verticalOffsetForPopupView = resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_vertical_margin) @@ -113,7 +115,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 } alwaysShowTaskbarSwitch.setOnClickListener { view -> (view.parent as View).performClick() } - if (ActivityContext.lookupContext<TaskbarActivityContext>(context).isGestureNav) { + if (taskbarActivityContext.isGestureNav) { taskbarSwitchOption.setOnClickListener { alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn onClickAlwaysShowTaskbarSwitchOption() diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 1b516bef4d..142f458b3b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -80,7 +80,6 @@ import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; import com.android.launcher3.taskbar.bubbles.BubbleBarViewController; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.views.BubbleTextHolder; @@ -132,6 +131,14 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im public void init(TaskbarControllers controllers) { mControllers = controllers; + mControllers.bubbleControllers.ifPresent( + c -> c.bubbleBarViewController.addBubbleBarDropTargets(this)); + } + + /** Called when the controller is destroyed. */ + public void onDestroy() { + mControllers.bubbleControllers.ifPresent( + c -> c.bubbleBarViewController.removeBubbleBarDropTargets(this)); } public void setDisallowGlobalDrag(boolean disallowGlobalDrag) { @@ -463,7 +470,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im com.android.launcher3.logging.InstanceId launcherInstanceId = instanceIds.second; intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId); - if (DisplayController.isTransientTaskbar(mActivity)) { + if (mActivity.isTransientTaskbar()) { // Tell WM Shell to ignore drag events in the provided transient taskbar region. TaskbarDragLayer dragLayer = mControllers.taskbarActivityContext.getDragLayer(); int[] locationOnScreen = dragLayer.getLocationOnScreen(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 55ecc37fb0..1e193f6817 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -34,7 +34,6 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.util.DimensionUtils; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.TouchController; @@ -108,19 +107,18 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa if (startAnimation != null) { // set taskbar background render animation boolean - if (DisplayController.isTransientTaskbar(mActivity)) { + if (mActivity.isTransientTaskbar()) { mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true); } else { mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true); } - float desiredValue = DisplayController.isTransientTaskbar(mActivity) + float desiredValue = mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT; - float nonDesiredvalue = !DisplayController.isTransientTaskbar(mActivity) - ? PINNING_TRANSIENT - : PINNING_PERSISTENT; + float nonDesiredvalue = + !mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT; ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue( nonDesiredvalue, desiredValue); @@ -133,9 +131,8 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa })); } else { - mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity) - ? PINNING_TRANSIENT - : PINNING_PERSISTENT); + mTaskbarBackgroundProgress.updateValue( + mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT); } mBgTaskbar.value = 1; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt index d624413d60..7a23006b4f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt @@ -155,7 +155,7 @@ open class TaskbarEduTooltipController(context: Context) : fun maybeShowSwipeEdu() { if ( !isTooltipEnabled || - !DisplayController.isTransientTaskbar(activityContext) || + !activityContext.isTransientTaskbar || tooltipStep > TOOLTIP_STEP_SWIPE ) { return @@ -200,7 +200,7 @@ open class TaskbarEduTooltipController(context: Context) : suggestionsAnim.supportLightTheme() pinningAnim.supportLightTheme() handleEduAnimations(listOf(splitscreenAnim, suggestionsAnim, pinningAnim)) - if (DisplayController.isTransientTaskbar(activityContext)) { + if (activityContext.isTransientTaskbar) { splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient) suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient) pinningEdu.visibility = if (enableTaskbarPinning()) VISIBLE else GONE @@ -230,7 +230,7 @@ open class TaskbarEduTooltipController(context: Context) : // Set up layout parameters. content.updateLayoutParams { width = MATCH_PARENT } updateLayoutParams<MarginLayoutParams> { - if (DisplayController.isTransientTaskbar(activityContext)) { + if (activityContext.isTransientTaskbar) { width = resources.getDimensionPixelSize( if (enableTaskbarPinning()) @@ -263,7 +263,7 @@ open class TaskbarEduTooltipController(context: Context) : // for the original 2 edu steps) as a proxy to needing to show the separate pinning edu if ( !enableTaskbarPinning() || - !DisplayController.isTransientTaskbar(activityContext) || + !activityContext.isTransientTaskbar || !isTooltipEnabled || tooltipStep > TOOLTIP_STEP_PINNING || tooltipStep < TOOLTIP_STEP_FEATURES @@ -289,7 +289,7 @@ open class TaskbarEduTooltipController(context: Context) : pinningAnim.supportLightTheme() handleEduAnimations(listOf(pinningAnim)) updateLayoutParams<BaseDragLayer.LayoutParams> { - if (DisplayController.isTransientTaskbar(activityContext)) { + if (activityContext.isTransientTaskbar) { bottomMargin += activityContext.deviceProfile.taskbarHeight } // Unlike other tooltips, we want to align with taskbar divider rather than center. @@ -344,7 +344,7 @@ open class TaskbarEduTooltipController(context: Context) : showDisclosureText(eduSubtitle) updateLayoutParams<BaseDragLayer.LayoutParams> { - if (DisplayController.isTransientTaskbar(activityContext)) { + if (activityContext.isTransientTaskbar) { bottomMargin += activityContext.deviceProfile.taskbarHeight } // Unlike other tooltips, we want to align with the all apps button rather than diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index a8ce10f40a..3af2ab6d3c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -235,8 +235,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas context.resources, ) val isPinnedTaskbar = - context.deviceProfile.isTaskbarPresent && - !context.deviceProfile.isTransientTaskbar + context.deviceProfile.isTaskbarPresent && !context.isTransientTaskbar val mandatoryGestureHeight = if (isPinnedTaskbar) contentHeight else gestureHeight provider.insetsSize = getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity, endRotation) @@ -388,10 +387,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas bubbleBarVisible ) { // Taskbar has some touchable elements, take over the full taskbar area - if ( - controllers.uiController.isInOverviewUi && - DisplayController.isTransientTaskbar(context) - ) { + if (controllers.uiController.isInOverviewUi && context.isTransientTaskbar) { val region = controllers.taskbarActivityContext.dragLayer.lastDrawnTransientRect.toRegion() val bubbleBarBounds = diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index bee0997d16..b5e271d07f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -17,6 +17,8 @@ package com.android.launcher3.taskbar; import static android.content.Context.RECEIVER_EXPORTED; import static android.content.Context.RECEIVER_NOT_EXPORTED; +import static android.content.pm.PackageManager.FEATURE_PC; +import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; @@ -26,6 +28,7 @@ import static com.android.launcher3.Flags.enableUnfoldStateAnimation; import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION; import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate; import static com.android.launcher3.taskbar.growth.GrowthConstants.BROADCAST_SHOW_NUDGE; +import static com.android.launcher3.taskbar.growth.GrowthConstants.GROWTH_NUDGE_PERMISSION; import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE; import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; @@ -86,6 +89,7 @@ import com.android.quickstep.fallback.window.RecentsWindowManager; import com.android.quickstep.util.ContextualSearchInvoker; import com.android.quickstep.util.GroupTask; import com.android.quickstep.views.RecentsViewContainer; +import com.android.server.am.Flags; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.statusbar.phone.BarTransitions; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -166,6 +170,10 @@ public class TaskbarManager { private final SparseArray<DeviceProfile> mExternalDeviceProfiles = new SparseArray<>(); private StatefulActivity mActivity; private RecentsViewContainer mRecentsViewContainer; + /** Whether this device is a desktop android device **/ + private boolean mIsAndroidPC; + /** Whether this device supports freeform windows management. Can change dynamically **/ + private boolean mSupportsFreeformWindowsManagement; /** * Cache a copy here so we can initialize state whenever taskbar is recreated, since @@ -188,29 +196,29 @@ public class TaskbarManager { private class RecreationListener implements DisplayController.DisplayInfoChangeListener { @Override public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { + int displayId = context.getDisplayId(); if ((flags & CHANGE_DENSITY) != 0) { - debugTaskbarManager("onDisplayInfoChanged: Display density changed", - context.getDisplayId()); + debugTaskbarManager("onDisplayInfoChanged: Display density changed", displayId); } if ((flags & CHANGE_NAVIGATION_MODE) != 0) { - debugTaskbarManager("onDisplayInfoChanged: Navigation mode changed", - context.getDisplayId()); + debugTaskbarManager("onDisplayInfoChanged: Navigation mode changed", displayId); } if ((flags & CHANGE_DESKTOP_MODE) != 0) { debugTaskbarManager("onDisplayInfoChanged: Desktop mode changed", context.getDisplayId()); + handleDisplayUpdatesForPerceptibleTasks(); } if ((flags & CHANGE_TASKBAR_PINNING) != 0) { - debugTaskbarManager("onDisplayInfoChanged: Taskbar pinning changed", - context.getDisplayId()); + debugTaskbarManager("onDisplayInfoChanged: Taskbar pinning changed", displayId); } if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE | CHANGE_TASKBAR_PINNING | CHANGE_SHOW_LOCKED_TASKBAR)) != 0) { - debugTaskbarManager("onDisplayInfoChanged: Recreating Taskbar!", - context.getDisplayId()); + TaskbarActivityContext taskbarActivityContext = getCurrentActivityContext(); if ((flags & CHANGE_SHOW_LOCKED_TASKBAR) != 0) { + debugTaskbarManager("onDisplayInfoChanged: show locked taskbar changed!", + displayId); recreateTaskbars(); } else if ((flags & CHANGE_DESKTOP_MODE) != 0) { if (mShouldIgnoreNextDesktopModeChangeFromDisplayController) { @@ -234,7 +242,7 @@ public class TaskbarManager { recreateTaskbars(); }; - private final PerceptibleTaskListener mTaskStackListener; + private PerceptibleTaskListener mTaskStackListener; private class PerceptibleTaskListener implements TaskStackChangeListener { private ArraySet<Integer> mPerceptibleTasks = new ArraySet<Integer>(); @@ -288,6 +296,14 @@ public class TaskbarManager { public void onTaskRemoved(int taskId) { mPerceptibleTasks.remove(taskId); } + + public void unregisterListener() { + for (Integer taskId : mPerceptibleTasks) { + ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false); + } + TaskStackChangeListeners.getInstance().unregisterTaskStackListener( + mTaskStackListener); + } } private final DesktopVisibilityController.TaskbarDesktopModeListener @@ -297,6 +313,11 @@ public class TaskbarManager { public void onExitDesktopMode(int duration) { for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) { int displayId = mTaskbars.keyAt(taskbarIndex); + if (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue() + && !isDefaultDisplay(displayId)) { + continue; + } + TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay( displayId); if (taskbarActivityContext != null @@ -316,6 +337,11 @@ public class TaskbarManager { public void onEnterDesktopMode(int duration) { for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) { int displayId = mTaskbars.keyAt(taskbarIndex); + if (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue() + && !isDefaultDisplay(displayId)) { + continue; + } + TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay( displayId); if (taskbarActivityContext != null) { @@ -337,7 +363,6 @@ public class TaskbarManager { } }; - private boolean mUserUnlocked = false; private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver; @@ -442,7 +467,7 @@ public class TaskbarManager { mGrowthBroadcastReceiver = new SimpleBroadcastReceiver( mPrimaryWindowContext, UI_HELPER_EXECUTOR, this::showGrowthNudge); - mGrowthBroadcastReceiver.register(RECEIVER_EXPORTED, + mGrowthBroadcastReceiver.register(null, GROWTH_NUDGE_PERMISSION, RECEIVER_EXPORTED, BROADCAST_SHOW_NUDGE); } else { mGrowthBroadcastReceiver = null; @@ -457,7 +482,10 @@ public class TaskbarManager { mTaskbarBroadcastReceiver.register(RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR); }); - if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) { + mIsAndroidPC = getPrimaryWindowContext().getPackageManager().hasSystemFeature(FEATURE_PC); + mSupportsFreeformWindowsManagement = getFreeformWindowsManagementInfo(); + + if (eligibleForPerceptibleTasks()) { mTaskStackListener = new PerceptibleTaskListener(); TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); } else { @@ -467,6 +495,30 @@ public class TaskbarManager { debugPrimaryTaskbar("TaskbarManager created"); } + private void handleDisplayUpdatesForPerceptibleTasks() { + // 1. When desktop mode changes, detect eligibility for perceptible tasks. + // 2. When no longer eligible for perceptible tasks, turn off and clean up. + mSupportsFreeformWindowsManagement = getFreeformWindowsManagementInfo(); + if (eligibleForPerceptibleTasks()) { + if (mTaskStackListener == null) { + mTaskStackListener = new PerceptibleTaskListener(); + TaskStackChangeListeners.getInstance() + .registerTaskStackListener(mTaskStackListener); + } + } else { + // not eligible for perceptible tasks, so we should unregister the listener + if (mTaskStackListener != null) { + mTaskStackListener.unregisterListener(); + mTaskStackListener = null; + } + } + } + + private boolean getFreeformWindowsManagementInfo() { + return getPrimaryWindowContext().getPackageManager().hasSystemFeature( + FEATURE_FREEFORM_WINDOW_MANAGEMENT); + } + private void destroyAllTaskbars() { debugPrimaryTaskbar("destroyAllTaskbars"); for (int i = 0; i < mTaskbars.size(); i++) { @@ -504,7 +556,7 @@ public class TaskbarManager { debugPrimaryTaskbar("destroyTaskbarForDisplay"); // TODO: make this code displayId specific TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId()); - if (ACTION_SHOW_TASKBAR.equals(intent.getAction())) { + if (ACTION_SHOW_TASKBAR.equals(intent.getAction()) && taskbar != null) { taskbar.showTaskbarFromBroadcast(); } } @@ -733,8 +785,7 @@ public class TaskbarManager { displayId); taskbar.updateDeviceProfile(dp); } - mSharedState.startTaskbarVariantIsTransient = - DisplayController.isTransientTaskbar(taskbar); + mSharedState.startTaskbarVariantIsTransient = taskbar.isTransientTaskbar(); mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar; taskbar.init(mSharedState, duration); @@ -988,12 +1039,12 @@ public class TaskbarManager { displayId); removeAndUnregisterComponentCallbacks(displayId); - debugTaskbarManager("onDisplayRemoved: destroying Taskbar!", displayId); - destroyTaskbarForDisplay(displayId); - debugTaskbarManager("onDisplayRemoved: removing DeviceProfile from map!", displayId); removeDeviceProfileFromMap(displayId); + debugTaskbarManager("onDisplayRemoved: destroying Taskbar!", displayId); + destroyTaskbarForDisplay(displayId); + debugTaskbarManager("onDisplayRemoved: removing WindowContext from map!", displayId); removeWindowContextFromMap(displayId); @@ -1052,17 +1103,26 @@ public class TaskbarManager { debugPrimaryTaskbar("destroy: unregistering component callbacks"); removeAndUnregisterComponentCallbacks(getDefaultDisplayId()); mShutdownReceiver.unregisterReceiverSafely(); - if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) { - for (Integer taskId : mTaskStackListener.mPerceptibleTasks) { - ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false); - } + if (mTaskStackListener != null) { + mTaskStackListener.unregisterListener(); } - TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); + debugPrimaryTaskbar("destroy: destroying all taskbars!"); destroyAllTaskbars(); debugPrimaryTaskbar("destroy: finished!"); } + private boolean eligibleForPerceptibleTasks() { + // Perceptible tasks feature (oom boosting) is eligible for android PC devices, and + // other android devices that supports free form windows + // + // - isAndroidPC is set per device (in this case, desktop devices) + // - supportsFreeformWindowsManagement is dynamic, and is to be used for the use-case where + // user plugs in their device to external displays + return Flags.perceptibleTasks() + && (mIsAndroidPC || mSupportsFreeformWindowsManagement); + } + public @Nullable TaskbarActivityContext getCurrentActivityContext() { return getTaskbarForDisplay(getDefaultDisplayId()); } @@ -1168,7 +1228,7 @@ public class TaskbarManager { * @return The {@link TaskbarActivityContext} for the specified display, or * {@code null} if no taskbar is associated with that display. */ - private TaskbarActivityContext getTaskbarForDisplay(int displayId) { + public TaskbarActivityContext getTaskbarForDisplay(int displayId) { return mTaskbars.get(displayId); } @@ -1319,7 +1379,6 @@ public class TaskbarManager { } } } else { - getCurrentActivityContext().onConfigurationChanged(configDiff); } mOldConfig = new Configuration(newConfig); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 4a7e4f0915..bf73f02aab 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -31,7 +31,6 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.bubbles.BubbleControllers; -import com.android.launcher3.util.DisplayController; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; @@ -93,7 +92,8 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa // There is no scrim for the bar in the phone mode. return; } - if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) { + boolean isTransient = mActivity.isTransientTaskbar(); + if (isBubbleBarEnabled() && isTransient) { // These scrims aren't used if bubble bar & transient taskbar are active. return; } @@ -112,7 +112,7 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa boolean showScrimForBubbles = bubblesExpanded && !mTaskbarVisible && isBubbleControllersPresented - && !DisplayController.isTransientTaskbar(mActivity) + && !mActivity.isTransientTaskbar() && !bubbleControllers.bubbleStashController.isBubblesShowingOnHome(); return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible() && !isShadeVisible @@ -122,8 +122,8 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa } private float computeScrimAlpha() { - final boolean isPersistentTaskBarVisible = - mTaskbarVisible && !DisplayController.isTransientTaskbar(mScrimView.getContext()); + boolean isTransient = mActivity.isTransientTaskbar(); + final boolean isPersistentTaskBarVisible = mTaskbarVisible && !isTransient; final boolean manageMenuExpanded = (mSysUiStateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0; if (isPersistentTaskBarVisible && manageMenuExpanded) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java index f87c21ece0..fa35a03216 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java @@ -27,7 +27,6 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController; -import com.android.launcher3.util.DisplayController; import java.io.PrintWriter; @@ -47,7 +46,7 @@ public class TaskbarSpringOnStashController implements LoggableTaskbarController public TaskbarSpringOnStashController(TaskbarActivityContext context) { mContext = context; - mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext); + mIsTransientTaskbar = context.isTransientTaskbar(); mStartVelocityPxPerS = context.getResources() .getDimension(R.dimen.transient_taskbar_stash_spring_velocity_dp_per_s); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 95724ad6d2..5284edd620 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -346,7 +346,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba StashedHandleViewController.ALPHA_INDEX_STASHED); mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale(); - boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); + boolean isTransientTaskbar = mActivity.isTransientTaskbar(); boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible; boolean isStashedInAppAuto = isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned(); @@ -367,9 +367,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // Hide the background while stashed so it doesn't show on fast swipes home boolean shouldHideTaskbarBackground = mActivity.isPhoneMode() || - (enableScalingRevealHomeAnimation() - && DisplayController.isTransientTaskbar(mActivity) - && isStashed()); + (enableScalingRevealHomeAnimation() && isTransientTaskbar && isStashed()); mTaskbarBackgroundAlphaForStash.setValue(shouldHideTaskbarBackground ? 0 : 1); @@ -414,8 +412,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba if (DisplayController.isPinnedTaskbar(mActivity)) { return PINNED_TASKBAR_TRANSITION_DURATION; } - return DisplayController.isTransientTaskbar(mActivity) - ? TRANSIENT_TASKBAR_STASH_DURATION + return mActivity.isTransientTaskbar() ? TRANSIENT_TASKBAR_STASH_DURATION : TASKBAR_STASH_DURATION; } @@ -509,8 +506,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * @see android.view.WindowInsets.Type#systemBars() */ public int getContentHeightToReportToApps() { - if (mActivity.isUserSetupComplete() && (mActivity.isPhoneGestureNavMode() - || DisplayController.isTransientTaskbar(mActivity))) { + boolean isTransient = mActivity.isTransientTaskbar(); + if (mActivity.isUserSetupComplete() && (mActivity.isPhoneGestureNavMode() || isTransient)) { return getStashedHeight(); } @@ -577,8 +574,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba */ public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow, boolean delayTaskbarBackground) { - if (!DisplayController.isTransientTaskbar(mActivity) - || mActivity.isBubbleBarOnPhone()) { + if (!mActivity.isTransientTaskbar() || mActivity.isBubbleBarOnPhone()) { return; } @@ -646,7 +642,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** Toggles the Taskbar's stash state. */ public void toggleTaskbarStash() { - if (!DisplayController.isTransientTaskbar(mActivity) || !hasAnyFlag(FLAGS_IN_APP)) return; + if (!mActivity.isTransientTaskbar() || !hasAnyFlag(FLAGS_IN_APP)) return; updateAndAnimateTransientTaskbar(!hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)); } @@ -697,8 +693,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mAnimator = new AnimatorSet(); addJankMonitorListener( mAnimator, /* expanding= */ !isStashed, /* tag= */ jankTag); - boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); - final float stashTranslation = mActivity.isPhoneMode() || isTransientTaskbar + final float stashTranslation = mActivity.isPhoneMode() || mActivity.isTransientTaskbar() ? 0 : (mUnstashedHeight - mStashedHeight); @@ -722,7 +717,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return; } - if (isTransientTaskbar) { + if (mActivity.isTransientTaskbar()) { createTransientAnimToIsStashed(mAnimator, isStashed, duration, shouldDelayBackground, animationType); } else { @@ -1144,7 +1139,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba boolean stashForBubbles = hasAnyFlag(FLAG_IN_OVERVIEW) && hasAnyFlag(systemUiStateFlags, SYSUI_STATE_BUBBLES_EXPANDED) - && DisplayController.isTransientTaskbar(mActivity); + && mActivity.isTransientTaskbar(); updateStateForFlag(FLAG_STASHED_SYSUI, hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING) || stashForBubbles); updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, @@ -1174,7 +1169,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * <p>Do not stash if a system gesture is started. */ private boolean shouldStashForIme() { - if (DisplayController.isTransientTaskbar(mActivity)) { + if (mActivity.isTransientTaskbar()) { return false; } // Do not stash if in small screen, with 3 button nav, and in landscape. @@ -1270,7 +1265,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba */ public void setUpTaskbarSystemAction(boolean visible) { UI_HELPER_EXECUTOR.execute(() -> { - if (!visible || !DisplayController.isTransientTaskbar(mActivity) + if (!visible || !mActivity.isTransientTaskbar() || mActivity.isPhoneMode()) { mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR); mIsTaskbarSystemActionRegistered = false; @@ -1321,7 +1316,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * If false, attempts to re/start the timeout */ public void updateTaskbarTimeout(boolean isAutohideSuspended) { - if (!DisplayController.isTransientTaskbar(mActivity)) { + if (!mActivity.isTransientTaskbar()) { return; } if (isAutohideSuspended) { @@ -1335,9 +1330,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * Attempts to start timer to auto hide the taskbar based on time. */ private void tryStartTaskbarTimeout() { - if (!DisplayController.isTransientTaskbar(mActivity) - || mIsStashed - || mEnableBlockingTimeoutDuringTests) { + if (!mActivity.isTransientTaskbar() || mIsStashed || mEnableBlockingTimeoutDuringTests) { return; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt index deaf0244e9..df10d24d2a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt @@ -23,7 +23,6 @@ import com.android.launcher3.testing.shared.ResourceUtils import com.android.launcher3.touch.SingleAxisSwipeDetector import com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE import com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL -import com.android.launcher3.util.DisplayController import com.android.launcher3.util.TouchController import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer @@ -39,7 +38,7 @@ import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : TouchController { private val activity: TaskbarActivityContext = controllers.taskbarActivityContext - private val enabled = DisplayController.isTransientTaskbar(activity) + private val enabled = activity.isTransientTaskbar private val swipeDownDetector: SingleAxisSwipeDetector private val translationCallback = controllers.taskbarTranslationController.transitionCallback /** Interpolator to apply resistance as user swipes down to the bottom of the screen. */ @@ -67,7 +66,7 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc val gestureHeight: Int = ResourceUtils.getNavbarSize( ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, - activity.resources + activity.resources, ) gestureHeightYThreshold = (activity.deviceProfile.heightPx - gestureHeight).toFloat() } @@ -89,7 +88,7 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc maxTouchDisplacement, 0f, maxVisualDisplacement, - displacementInterpolator + displacementInterpolator, ) ) return false diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java index 5a5d6d0e53..13fb296498 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java @@ -29,7 +29,6 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.app.animation.Interpolators; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.SpringAnimationBuilder; -import com.android.launcher3.util.DisplayController; import java.io.PrintWriter; @@ -63,7 +62,7 @@ public class TaskbarTranslationController implements TaskbarControllers.Loggable public TaskbarTranslationController(TaskbarActivityContext context) { mContext = context; - mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext); + mIsTransientTaskbar = mContext.isTransientTaskbar(); mCallback = new TransitionCallback(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index ea0b81eeea..061a5a127e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -37,7 +37,6 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.taskbar.bubbles.BubbleBarController; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.quickstep.util.SplitTask; import com.android.quickstep.views.RecentsView; @@ -116,9 +115,8 @@ public class TaskbarUIController implements BubbleBarController.BubbleBarLocatio */ public void hideOverlayWindow() { mControllers.keyboardQuickSwitchController.closeQuickSwitchView(); - - if (!DisplayController.isTransientTaskbar(mControllers.taskbarActivityContext) - || mControllers.taskbarAllAppsController.isOpen()) { + boolean isTransientTaskbar = mControllers.taskbarActivityContext.isTransientTaskbar(); + if (!isTransientTaskbar || mControllers.taskbarAllAppsController.isOpen()) { mControllers.taskbarOverlayController.hideWindow(); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 93662cdae9..b2989cd81a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -61,7 +61,6 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.customization.TaskbarAllAppsButtonContainer; import com.android.launcher3.taskbar.customization.TaskbarDividerContainer; import com.android.launcher3.uioverrides.PredictedAppIcon; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; import com.android.quickstep.util.GroupTask; @@ -130,7 +129,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private final int mAllAppsButtonTranslationOffset; - private final int mNumStaticViews; + private int mNumStaticViews; private Set<GroupTask> mPrevRecentTasks = Collections.emptySet(); private Set<GroupTask> mPrevOverflowTasks = Collections.emptySet(); @@ -184,8 +183,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar setWillNotDraw(false); mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context); - mAllAppsButtonTranslationOffset = (int) getResources().getDimension( - mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(isTransientTaskbar())); + mAllAppsButtonTranslationOffset = (int) getResources().getDimension( + mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset( + mActivityContext.isTransientTaskbar())); if (enableTaskbarPinning() || enableRecentsInTaskbar()) { mTaskbarDividerContainer = new TaskbarDividerContainer(context); @@ -199,8 +199,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar // TODO: Disable touch events on QSB otherwise it can crash. mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); - - mNumStaticViews = ENABLE_TASKBAR_RECENTS_LAYOUT_TRANSITION.isTrue() ? addStaticViews() : 0; } /** @@ -240,7 +238,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar enableTaskbarPinning() && !mActivityContext.isThreeButtonNav(); availableWidth -= iconSize - (int) getResources().getDimension( mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset( - forceTransientTaskbarSize || isTransientTaskbar())); + forceTransientTaskbarSize || mActivityContext.isTransientTaskbar())); ++additionalIcons; return Math.floorDiv(availableWidth, iconSize) + additionalIcons; @@ -370,23 +368,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar if (!(view.getTag() instanceof CollectionInfo)) { mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view); } - if (view instanceof FolderIcon fi) { - // We should clear FolderInfo's Folder and FolderIcon to avoid memory leak. - fi.removeListeners(); - } view.setTag(null); } - /** Loop through all {@link FolderIcon} as child views and clear listeners to avoid leak. */ - public void removeFolderIconListeners() { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - if (getChildAt(i) instanceof FolderIcon fi) { - fi.removeListeners(); - } - } - } - /** Inflates/binds the hotseat items and recent tasks to the view. */ protected void updateItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) { if (mActivityContext.isDestroyed()) return; @@ -447,6 +431,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private void updateItemsWithLayoutTransition( ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) { + if (mNumStaticViews == 0) { + mNumStaticViews = addStaticViews(); + } // Skip static views and potential All Apps divider, if they are on the left. mNextViewIndex = mIsRtl ? 0 : mNumStaticViews; @@ -475,7 +462,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } // Recents divider takes priority. - if (!mAddedDividerForRecents && !mActivityContext.areDesktopTasksVisible()) { + if (!mAddedDividerForRecents && !mActivityContext.isInDesktopMode()) { updateAllAppsDivider(); } } @@ -577,6 +564,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize); hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding); addView(hotseatView, mNextViewIndex, lp); + } else if (hotseatView instanceof FolderIcon fi) { + fi.onItemsChanged(false); + fi.getFolder().reapplyItemInfo(); } // Apply the Hotseat ItemInfos, or hide the view if there is none for a given index. @@ -1098,11 +1088,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar // Ignore, we just implement Insettable to draw behind system insets. } - private boolean isTransientTaskbar() { - return DisplayController.isTransientTaskbar(mActivityContext) - && !mActivityContext.isPhoneMode(); - } - public boolean areIconsVisible() { // Consider the overall visibility return getVisibility() == VISIBLE; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index a80e2c4365..6786aed445 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -267,9 +267,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar : mActivity.getDeviceProfile().taskbarHeight; mTaskbarIconScaleForStash.updateValue(1f); - float pinningValue = DisplayController.isTransientTaskbar(mActivity) - ? PINNING_TRANSIENT - : PINNING_PERSISTENT; + float pinningValue = + mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT; mTaskbarIconScaleForPinning.updateValue(pinningValue); mTaskbarIconTranslationYForPinning.updateValue(pinningValue); mTaskbarIconTranslationXForPinning.updateValue(pinningValue); @@ -394,7 +393,6 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar if (enableTaskbarPinning()) { mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener); } - mTaskbarView.removeFolderIconListeners(); LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks); mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener); } @@ -936,7 +934,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mOnControllerPreCreateCallback.run(); DeviceProfile taskbarDp = mActivity.getDeviceProfile(); Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity); - boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); + boolean isTransientTaskbar = mActivity.isTransientTaskbar(); float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.taskbarIconSize; int borderSpacing = launcherDp.hotseatBorderSpace; diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt index c380c8d6f1..c7d42b1b90 100644 --- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt @@ -22,7 +22,6 @@ import android.view.ViewTreeObserver import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION import android.view.WindowManager import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY -import com.android.launcher3.util.DisplayController import com.android.launcher3.views.BaseDragLayer import com.android.systemui.animation.ViewRootSync import java.io.PrintWriter @@ -41,8 +40,7 @@ private const val TEMP_BACKGROUND_WINDOW_TITLE = "VoiceInteractionTaskbarBackgro class VoiceInteractionWindowController(val context: TaskbarActivityContext) : TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController { - private val isSeparateBackgroundEnabled = - !DisplayController.isTransientTaskbar(context) && !context.isPhoneMode + private val isSeparateBackgroundEnabled = !context.isTransientTaskbar && !context.isPhoneMode private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context) private val nonTouchableInsetsComputer = ViewTreeObserver.OnComputeInternalInsetsListener { @@ -97,7 +95,7 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) : separateWindowLayoutParams = context.createDefaultWindowLayoutParams( TYPE_APPLICATION_OVERLAY, - TEMP_BACKGROUND_WINDOW_TITLE + TEMP_BACKGROUND_WINDOW_TITLE, ) separateWindowLayoutParams?.isSystemApplicationOverlay = true } @@ -163,7 +161,7 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) : // First add the temporary window, then hide the overlapping taskbar background. context.addWindowView( separateWindowForTaskbarBackground, - separateWindowLayoutParams + separateWindowLayoutParams, ); { controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(true) } } else { @@ -179,7 +177,7 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) : ViewRootSync.synchronizeNextDraw( separateWindowForTaskbarBackground!!, context.dragLayer, - onWindowsSynchronized + onWindowsSynchronized, ) } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java index 5830095fa6..916b28ec0f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java @@ -15,7 +15,9 @@ */ package com.android.launcher3.taskbar.allapps; +import static com.android.app.animation.Interpolators.DECELERATED_EASE; import static com.android.app.animation.Interpolators.EMPHASIZED; +import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL; import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL; @@ -35,6 +37,7 @@ import androidx.annotation.Nullable; import com.android.app.animation.Interpolators; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Flags; import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorListeners; @@ -48,9 +51,11 @@ import com.android.launcher3.views.AbstractSlideInView; public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverlayContext> implements Insettable, DeviceProfile.OnDeviceProfileChangeListener { private final Handler mHandler; + private final int mMaxBlurRadius; private TaskbarAllAppsContainerView mAppsView; private float mShiftRange; + private int mBlurRadius; private @Nullable Runnable mShowOnFullyAttachedToWindowRunnable; // Initialized in init. @@ -64,6 +69,8 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla int defStyleAttr) { super(context, attrs, defStyleAttr); mHandler = new Handler(Looper.myLooper()); + mMaxBlurRadius = getResources().getDimensionPixelSize( + R.dimen.max_depth_blur_radius_enhanced); } void init(TaskbarAllAppsCallbacks callbacks) { @@ -99,6 +106,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla if (!animate) { mAllAppsCallbacks.onAllAppsTransitionEnd(true); setTranslationShift(TRANSLATION_SHIFT_OPENED); + mBlurRadius = mMaxBlurRadius; return; } @@ -123,6 +131,16 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla animation.setViewAlpha(mAppsView, 1 - mToTranslationShift, allAppsFadeInterpolator); } + if (Flags.allAppsBlur()) { + Interpolator blurInterpolator = isOpening ? LINEAR : DECELERATED_EASE; + animation.addOnFrameListener(a -> { + float blurProgress = + isOpening ? a.getAnimatedFraction() : 1 - a.getAnimatedFraction(); + mBlurRadius = + (int) (mMaxBlurRadius * blurInterpolator.getInterpolation(blurProgress)); + }); + } + mAllAppsCallbacks.onAllAppsAnimationPending(animation, isOpening); } @@ -219,6 +237,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla // to pass extra bottom offset to background scrim to fill the bottom gap during predictive // back swipe. mAppsView.drawOnScrimWithBottomOffset(canvas, getBottomOffsetPx()); + mActivityContext.getOverlayController().setBackgroundBlurRadius(mBlurRadius); super.dispatchDraw(canvas); } @@ -230,9 +249,13 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla @Override protected int getScrimColor(Context context) { - return mActivityContext.getDeviceProfile().isPhone - ? Themes.getAttrColor(context, R.attr.allAppsScrimColor) - : context.getColor(R.color.widgets_picker_scrim); + if (!mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) { + return Themes.getAttrColor(context, R.attr.allAppsScrimColor); + } + if (Flags.allAppsBlur()) { + return Themes.getAttrColor(context, R.attr.allAppsScrimColorOverBlur); + } + return context.getResources().getColor(R.color.widgets_picker_scrim); } @Override @@ -254,6 +277,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla public void onDeviceProfileChanged(DeviceProfile dp) { setShiftRange(dp.allAppsShiftRange); setTranslationShift(TRANSLATION_SHIFT_OPENED); + mBlurRadius = mMaxBlurRadius; } private void setShiftRange(float shiftRange) { diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java index 52f7176910..f1ccd39e4a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java @@ -31,7 +31,6 @@ import com.android.launcher3.taskbar.TaskbarSharedState; import com.android.launcher3.taskbar.TaskbarStashController; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; -import com.android.launcher3.util.DisplayController; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import java.util.Optional; @@ -90,7 +89,7 @@ final class TaskbarAllAppsViewController { } private void setUpTaskbarStashing() { - if (DisplayController.isTransientTaskbar(mContext)) { + if (mContext.isTransientTaskbar()) { mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, true); mTaskbarStashController.applyState(); } @@ -103,7 +102,7 @@ final class TaskbarAllAppsViewController { AbstractFloatingView.closeOpenContainer( mContext, AbstractFloatingView.TYPE_ACTION_POPUP); - if (DisplayController.isTransientTaskbar(mContext)) { + if (mContext.isTransientTaskbar()) { mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false); mTaskbarStashController.applyState(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt index 383f4d2020..24e7d99187 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt @@ -60,8 +60,6 @@ class BubbleBarLocationDropTarget( override fun onDrop(dragObject: DropTarget.DragObject, options: DragOptions) { val itemInfo = dragObject.dragInfo ?: return - // TODO(b/397459664) : fix task bar icon animation after drop - // TODO(b/397459664) : update bubble bar location bubbleBarDragListener.onLauncherItemDroppedOverBubbleBarDragZone( bubbleBarLocation, itemInfo, @@ -77,8 +75,6 @@ class BubbleBarLocationDropTarget( } override fun onDragExit(dragObject: DropTarget.DragObject) { - // TODO(b/397459664) : fix the issue for no bubbles, when moving task bar icon out of - // the bubble bar drag zone drag ends and swipes gesture swipes the overview if (!isShowingDropTarget) return isShowingDropTarget = false bubbleBarDragListener.onLauncherItemDraggedOutsideBubbleBarDropZone() diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 277dbbf677..7fb6480005 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -41,15 +41,16 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.app.animation.Interpolators; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; -import com.android.launcher3.taskbar.TaskbarDragController; import com.android.launcher3.taskbar.TaskbarInsetsController; import com.android.launcher3.taskbar.TaskbarSharedState; import com.android.launcher3.taskbar.TaskbarStashController; @@ -144,6 +145,7 @@ public class BubbleBarViewController { @Override public void onLauncherItemDroppedOverBubbleBarDragZone(@NonNull BubbleBarLocation location, @NonNull ItemInfo itemInfo) { + AbstractFloatingView.closeAllOpenViews(mActivity); if (itemInfo instanceof WorkspaceItemInfo) { ShortcutInfo shortcutInfo = ((WorkspaceItemInfo) itemInfo).getDeepShortcutInfo(); if (shortcutInfo != null) { @@ -193,13 +195,13 @@ public class BubbleBarViewController { private boolean mShouldShowEducation; public boolean mOverflowAdded; private boolean mIsLocationUpdatedForDropTarget = false; + private boolean mWasStashedBeforeEnteringBubbleDragZone = false; private BubbleBarViewAnimator mBubbleBarViewAnimator; private final FrameLayout mBubbleBarContainer; private BubbleBarFlyoutController mBubbleBarFlyoutController; private BubbleBarPinController mBubbleBarPinController; private TaskbarSharedState mTaskbarSharedState; - private TaskbarDragController mTaskbarDragController; private final BubbleBarLocationDropTarget mBubbleBarLeftDropTarget; private final BubbleBarLocationDropTarget mBubbleBarRightDropTarget; private final TimeSource mTimeSource = System::currentTimeMillis; @@ -236,7 +238,6 @@ public class BubbleBarViewController { /** Initializes controller. */ public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers, TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) { - mTaskbarDragController = controllers.taskbarDragController; mTaskbarSharedState = controllers.getSharedState(); mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleBarController = bubbleControllers.bubbleBarController; @@ -273,7 +274,7 @@ public class BubbleBarViewController { mBoundsChangeListener.onBoundsChanged(); } }); - float pinningValue = DisplayController.isTransientTaskbar(mActivity) + float pinningValue = mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT; mBubbleBarPinning.updateValue(pinningValue); @@ -338,8 +339,18 @@ public class BubbleBarViewController { mBubbleBarController.updateBubbleBarLocation(location, source); } }; - mTaskbarDragController.addDropTarget(mBubbleBarLeftDropTarget); - mTaskbarDragController.addDropTarget(mBubbleBarRightDropTarget); + } + + /** Adds bubble bar locations drop zones to the drag controller. */ + public void addBubbleBarDropTargets(DragController<?> dragController) { + dragController.addDropTarget(mBubbleBarLeftDropTarget); + dragController.addDropTarget(mBubbleBarRightDropTarget); + } + + /** Removes bubble bar locations drop zones to the drag controller. */ + public void removeBubbleBarDropTargets(DragController<?> dragController) { + dragController.removeDropTarget(mBubbleBarLeftDropTarget); + dragController.removeDropTarget(mBubbleBarRightDropTarget); } /** Returns animated float property responsible for pinning transition animation. */ @@ -617,14 +628,30 @@ public class BubbleBarViewController { * updated. */ public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation bubbleBarLocation) { + Log.w("BBAnimation", "onDragItemOverBubbleBarDragZone()"); mBarView.showDropTarget(/* isDropTarget = */ true); boolean isRtl = mBarView.isLayoutRtl(); mIsLocationUpdatedForDropTarget = getBubbleBarLocation().isOnLeft(isRtl) != bubbleBarLocation.isOnLeft(isRtl); - if (mIsLocationUpdatedForDropTarget) { - animateBubbleBarLocation(bubbleBarLocation); - } - if (!hasBubbles()) { + mWasStashedBeforeEnteringBubbleDragZone = hasBubbles() + && mBubbleStashController.isStashed(); + if (mWasStashedBeforeEnteringBubbleDragZone) { + if (mIsLocationUpdatedForDropTarget) { + // bubble bar is stashed an location updated + //TODO(b/399678274) add animation + mBubbleStashController.showBubbleBarImmediate(); + animateBubbleBarLocation(bubbleBarLocation); + } else { + // bubble bar is stashed and location the same - just un-stash + mBubbleStashController.showBubbleBar(/* expandBubbles = */ false); + } + } else if (hasBubbles()) { + if (mIsLocationUpdatedForDropTarget) { + // bubble bar has bubbles and location is changed - animate bar to the opposite side + animateBubbleBarLocation(bubbleBarLocation); + } + } else { + // bubble bar has no bubbles flow just show the empty drop target mBubbleBarPinController.showDropTarget(bubbleBarLocation); } } @@ -644,12 +671,27 @@ public class BubbleBarViewController { * mode and reset the value returned from {@link #isLocationUpdatedForDropTarget()} to false. */ public void onItemDraggedOutsideBubbleBarDropZone() { + Log.w("BBAnimation", "onItemDraggedOutsideBubbleBarDropZone()"); mBarView.showDropTarget(/* isDropTarget = */ false); - if (mIsLocationUpdatedForDropTarget) { - animateBubbleBarLocation(getBubbleBarLocation()); + if (mWasStashedBeforeEnteringBubbleDragZone) { + if (mIsLocationUpdatedForDropTarget) { + // bubble bar was stashed and location updated + //TODO(b/399678274) add animation + animateBubbleBarLocation(getBubbleBarLocation()); + mBubbleStashController.stashBubbleBarImmediate(); + } else { + // bubble bar was stashed and location the same - just stash it back + mBubbleStashController.stashBubbleBar(); + } + } else if (hasBubbles()) { + if (mIsLocationUpdatedForDropTarget) { + // bubble bar has bubbles and location was changed - return to the original location + animateBubbleBarLocation(getBubbleBarLocation()); + } } mBubbleBarPinController.hideDropTarget(); mIsLocationUpdatedForDropTarget = false; + mWasStashedBeforeEnteringBubbleDragZone = false; } /** @@ -657,9 +699,11 @@ public class BubbleBarViewController { * The controller will hide the drop target if there are no bubbles and exit drop target mode. */ public void onItemDroppedInBubbleBarDragZone() { + Log.w("BBAnimation", "onItemDroppedInBubbleBarDragZone()"); mBarView.showDropTarget(/* isDropTarget = */ false); mBubbleBarPinController.hideDropTarget(); mIsLocationUpdatedForDropTarget = false; + mWasStashedBeforeEnteringBubbleDragZone = false; } /** @@ -1356,20 +1400,18 @@ public class BubbleBarViewController { /** Called when the controller is destroyed. */ public void onDestroy() { adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false); - mTaskbarDragController.removeDropTarget(mBubbleBarLeftDropTarget); - mTaskbarDragController.removeDropTarget(mBubbleBarRightDropTarget); } /** * Removes the bubble from the bubble bar and notifies sysui that the bubble should move to * full screen. */ - public void moveBubbleToFullscreen(@NonNull BubbleView bubbleView) { + public void moveDraggedBubbleToFullscreen(@NonNull BubbleView bubbleView, Point dropLocation) { if (bubbleView.getBubble() == null) { return; } String key = bubbleView.getBubble().getKey(); - mSystemUiProxy.moveBubbleToFullscreen(key); + mSystemUiProxy.moveDraggedBubbleToFullscreen(key, dropLocation); onBubbleDismissed(bubbleView); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java index f77b934373..3df10c0ce0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java @@ -16,6 +16,7 @@ package com.android.launcher3.taskbar.bubbles; import android.annotation.SuppressLint; +import android.graphics.Point; import android.graphics.PointF; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -231,13 +232,14 @@ public class BubbleDragController { } @Override - void onDragEnd() { + void onDragEnd(float x, float y) { mBubbleBarController.updateBubbleBarLocation(getBubbleBarLocationDuringDrag(), BubbleBarLocation.UpdateSource.DRAG_BUBBLE); if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) { mDropTargetManager.onDragEnded(); if (mBubbleDragZoneChangedListener.isDraggedToFullscreen()) { - mBubbleBarViewController.moveBubbleToFullscreen(bubbleView); + mBubbleBarViewController.moveDraggedBubbleToFullscreen( + bubbleView, new Point((int) x, (int) y)); } } else { mBubblePinController.setListener(null); @@ -329,7 +331,7 @@ public class BubbleDragController { } @Override - void onDragEnd() { + void onDragEnd(float x, float y) { // Make sure to update location as the first thing. Pivot update causes a relayout mBubbleBarController.updateBubbleBarLocation(getBubbleBarLocationDuringDrag(), BubbleBarLocation.UpdateSource.DRAG_BAR); @@ -428,7 +430,7 @@ public class BubbleDragController { /** * Called when the dragging interaction has ended and all the animations have completed */ - abstract void onDragEnd(); + abstract void onDragEnd(float x, float y); /** * Called when the dragged bubble is released outside of the dismiss target area and will @@ -579,7 +581,7 @@ public class BubbleDragController { Runnable onComplete = () -> { mActivity.setTaskbarWindowFullscreen(false); cleanUp(view); - onDragEnd(); + onDragEnd(event.getRawX(), event.getRawY()); }; if (mBubbleDismissController.handleTouchEvent(event)) { diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt index 75bf937a87..ac87b5ee00 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt @@ -36,6 +36,8 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.animation.ArgbEvaluator import com.android.launcher3.R import com.android.launcher3.popup.RoundedArrowDrawable +import com.android.wm.shell.shared.TypefaceUtils +import com.android.wm.shell.shared.TypefaceUtils.Companion.setTypeface import kotlin.math.min /** The flyout view used to notify the user of a new bubble notification. */ @@ -163,6 +165,9 @@ class BubbleBarFlyoutView( LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true) id = R.id.bubble_bar_flyout_view + setTypeface(title, TypefaceUtils.FontFamily.GSF_LABEL_LARGE) + setTypeface(message, TypefaceUtils.FontFamily.GSF_BODY_MEDIUM) + val ta = context.obtainStyledAttributes(intArrayOf(android.R.attr.dialogCornerRadius)) cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat() ta.recycle() diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt index 493265418f..bb2acd6362 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt @@ -32,7 +32,6 @@ import com.android.launcher3.Utilities.dpToPx import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarViewCallbacks -import com.android.launcher3.util.DisplayController import com.android.launcher3.util.Executors.MAIN_EXECUTOR import com.android.launcher3.views.ActivityContext import com.android.launcher3.views.IconButtonView @@ -69,7 +68,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) backgroundTintList = ColorStateList.valueOf(TRANSPARENT) setIconDrawable(drawable) - if (!DisplayController.isTransientTaskbar(context)) { + if (!activityContext.isTransientTaskbar) { setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat())) } setForegroundTint(activityContext.getColor(R.color.all_apps_button_color)) diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt index d5f72d5b1d..060ce46619 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt @@ -26,7 +26,6 @@ import com.android.launcher3.R import com.android.launcher3.Utilities.dpToPx import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarViewCallbacks -import com.android.launcher3.util.DisplayController import com.android.launcher3.views.ActivityContext import com.android.launcher3.views.IconButtonView @@ -52,7 +51,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 backgroundTintList = ColorStateList.valueOf(TRANSPARENT) val drawable = resources.getDrawable(R.drawable.taskbar_divider_button) setIconDrawable(drawable) - if (!DisplayController.isTransientTaskbar(context)) { + if (!activityContext.isTransientTaskbar) { setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat())) } } diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt index f130d29ec1..a14c5a47e6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt @@ -19,7 +19,6 @@ package com.android.launcher3.taskbar.customization import com.android.launcher3.Flags.enableRecentsInTaskbar import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning import com.android.launcher3.taskbar.TaskbarActivityContext -import com.android.launcher3.util.DisplayController /** Evaluates all the features taskbar can have. */ class TaskbarFeatureEvaluator @@ -36,7 +35,7 @@ private constructor(private val taskbarActivityContext: TaskbarActivityContext) get() = enableTaskbarPinning() || isRecentsEnabled val isTransient: Boolean - get() = DisplayController.isTransientTaskbar(taskbarActivityContext) + get() = taskbarActivityContext.isTransientTaskbar val isLandscape: Boolean get() = taskbarActivityContext.deviceProfile.isLandscape diff --git a/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java b/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java index 78ef152601..7d760fc9bb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java +++ b/quickstep/src/com/android/launcher3/taskbar/growth/GrowthConstants.java @@ -24,5 +24,13 @@ public final class GrowthConstants { */ public static final String BROADCAST_SHOW_NUDGE = "com.android.launcher3.growth.BROADCAST_SHOW_NUDGE"; + + /** + * For filtering package of broadcast intent received. + */ + public static final String GROWTH_NUDGE_PERMISSION = + "com.android.growth.permission.GROWTH_NUDGE_PERMISSION" + + " android:protectionLevel=\"signature|preinstalled\""; + private GrowthConstants() {} } diff --git a/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt b/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt new file mode 100644 index 0000000000..04e41bc3bd --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/growth/NudgeController.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 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.growth + +import android.content.Context +import com.android.launcher3.Utilities +import com.android.launcher3.taskbar.TaskbarActivityContext +import com.android.launcher3.taskbar.TaskbarControllers +import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController +import com.android.launcher3.util.DisplayController +import com.android.launcher3.views.ActivityContext +import java.io.PrintWriter + +/** Controls nudge lifecycles. */ +class NudgeController(context: Context) : LoggableTaskbarController { + + protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context) + + private val isNudgeEnabled: Boolean + get() { + return !Utilities.isRunningInTestHarness() && + !activityContext.isPhoneMode && + !activityContext.isTinyTaskbar + } + + private lateinit var controllers: TaskbarControllers + + fun init(controllers: TaskbarControllers) { + this.controllers = controllers + } + + fun maybeShow(payload: NudgePayload) { + if (!isNudgeEnabled || !DisplayController.isTransientTaskbar(activityContext)) { + return + } + // TODO: b/398033012 - create and show nudge view based on the payload. + } + + /** Closes the current [nudgeView]. */ + fun hide() { + // TODO: b/398033012 - hide the nudge view. + } + + override fun dumpLogs(prefix: String?, pw: PrintWriter?) { + pw?.println(prefix + "NudgeController:") + pw?.println("$prefix\tisNudgeEnabled=$isNudgeEnabled") + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java index bbf08bf903..844f1af288 100644 --- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java @@ -194,6 +194,7 @@ public class NearestTouchFrame extends FrameLayout { event.offsetLocation(mTouchingChild.getWidth() / 2 - x, mTouchingChild.getHeight() / 2 - y); return mTouchingChild.getVisibility() == VISIBLE + && mTouchingChild.isAttachedToWindow() && mTouchingChild.dispatchTouchEvent(event); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java index 55bb0f94f5..dd91d17c29 100644 --- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java @@ -55,7 +55,7 @@ public class TaskbarOverlayContext extends BaseTaskbarContext { Context windowContext, TaskbarActivityContext taskbarContext, TaskbarControllers controllers) { - super(windowContext); + super(windowContext, taskbarContext.isPrimaryDisplay()); mTaskbarContext = taskbarContext; mOverlayController = controllers.taskbarOverlayController; mDragController = new TaskbarDragController(this); @@ -67,6 +67,11 @@ public class TaskbarOverlayContext extends BaseTaskbarContext { onViewCreated(); } + /** Called when the controller is destroyed. */ + public void onDestroy() { + mDragController.onDestroy(); + } + public @Nullable TaskbarSearchSessionController getSearchSessionController() { return mSearchSessionController; } diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java index 79cb748181..675d55b9a4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java @@ -26,8 +26,12 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.PixelFormat; +import android.util.Log; +import android.view.AttachedSurfaceControl; import android.view.Gravity; import android.view.MotionEvent; +import android.view.SurfaceControl; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -36,8 +40,10 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Flags; +import com.android.launcher3.R; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.systemui.shared.system.BlurUtils; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; @@ -52,12 +58,14 @@ import java.util.Optional; */ public final class TaskbarOverlayController { + private static final String TAG = "TaskbarOverlayController"; private static final String WINDOW_TITLE = "Taskbar Overlay"; private final TaskbarActivityContext mTaskbarContext; private final Context mWindowContext; private final TaskbarOverlayProxyView mProxyView; private final LayoutParams mLayoutParams; + private final int mMaxBlurRadius; private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { @Override @@ -88,6 +96,8 @@ public final class TaskbarOverlayController { private DeviceProfile mLauncherDeviceProfile; private @Nullable TaskbarOverlayContext mOverlayContext; private TaskbarControllers mControllers; // Initialized in init. + // True if we have alerted surface flinger of an expensive call for blur. + private boolean mInEarlyWakeUp; public TaskbarOverlayController( TaskbarActivityContext taskbarContext, DeviceProfile launcherDeviceProfile) { @@ -96,6 +106,8 @@ public final class TaskbarOverlayController { mProxyView = new TaskbarOverlayProxyView(); mLayoutParams = createLayoutParams(); mLauncherDeviceProfile = launcherDeviceProfile; + mMaxBlurRadius = mTaskbarContext.getResources().getDimensionPixelSize( + R.dimen.max_depth_blur_radius_enhanced); } /** Initialize the controller. */ @@ -150,9 +162,13 @@ public final class TaskbarOverlayController { /** Destroys the controller and any overlay window if present. */ public void onDestroy() { TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); - Optional.ofNullable(mOverlayContext) - .map(c -> c.getSystemService(WindowManager.class)) - .ifPresent(m -> m.removeViewImmediate(mOverlayContext.getDragLayer())); + Optional.ofNullable(mOverlayContext).ifPresent(c -> { + c.onDestroy(); + WindowManager wm = c.getSystemService(WindowManager.class); + if (wm != null) { + wm.removeViewImmediate(mOverlayContext.getDragLayer()); + } + }); mOverlayContext = null; } @@ -197,6 +213,65 @@ public final class TaskbarOverlayController { } /** + * Sets the blur radius for the overlay window. + * + * @param radius the blur radius in pixels. This will automatically change to {@code 0} if blurs + * are unsupported on the device. + */ + public void setBackgroundBlurRadius(int radius) { + if (!Flags.allAppsBlur()) { + return; + } + if (!BlurUtils.supportsBlursOnWindows()) { + Log.d(TAG, "setBackgroundBlurRadius: not supported, setting to 0"); + radius = 0; + // intentionally falling through in case a non-0 blur was previously set. + } + if (mOverlayContext == null) { + Log.w(TAG, "setBackgroundBlurRadius: no overlay context"); + return; + } + TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer(); + if (dragLayer == null) { + Log.w(TAG, "setBackgroundBlurRadius: no drag layer"); + return; + } + ViewRootImpl dragLayerViewRoot = dragLayer.getViewRootImpl(); + if (dragLayerViewRoot == null) { + Log.w(TAG, "setBackgroundBlurRadius: dragLayerViewRoot is null"); + return; + } + AttachedSurfaceControl rootSurfaceControl = dragLayer.getRootSurfaceControl(); + if (rootSurfaceControl == null) { + Log.w(TAG, "setBackgroundBlurRadius: rootSurfaceControl is null"); + return; + } + SurfaceControl surfaceControl = dragLayerViewRoot.getSurfaceControl(); + if (surfaceControl == null || !surfaceControl.isValid()) { + Log.w(TAG, "setBackgroundBlurRadius: surfaceControl is null or invalid"); + return; + } + Log.v(TAG, "setBackgroundBlurRadius: " + radius); + SurfaceControl.Transaction transaction = + new SurfaceControl.Transaction().setBackgroundBlurRadius(surfaceControl, radius); + + // Set early wake-up flags when we know we're executing an expensive operation, this way + // SurfaceFlinger will adjust its internal offsets to avoid jank. + boolean wantsEarlyWakeUp = radius > 0 && radius < mMaxBlurRadius; + if (wantsEarlyWakeUp && !mInEarlyWakeUp) { + Log.d(TAG, "setBackgroundBlurRadius: setting early wakeup"); + transaction.setEarlyWakeupStart(); + mInEarlyWakeUp = true; + } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) { + Log.d(TAG, "setBackgroundBlurRadius: clearing early wakeup"); + transaction.setEarlyWakeupEnd(); + mInEarlyWakeUp = false; + } + + rootSurfaceControl.applyTransactionOnDraw(transaction); + } + + /** * Proxy view connecting taskbar drag layer to the overlay window. * * Overlays are in a separate window and has its own drag layer, but this proxy lets its views diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java index 669850cb41..41694ecee5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java @@ -34,7 +34,6 @@ import com.android.app.viewcapture.ViewCaptureFactory; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; @@ -147,7 +146,7 @@ public class TaskbarOverlayDragLayer extends * 2) Sets tappableInsets bottom inset to 0. */ private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) { - if (!DisplayController.isTransientTaskbar(mContainer)) { + if (!mContainer.isTransientTaskbar()) { return oldInsets; } WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets); diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index cd0a4f312c..806b8ab1cc 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -86,6 +86,7 @@ import android.os.Trace; import android.os.UserHandle; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import android.view.Display; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; @@ -226,6 +227,7 @@ import java.util.stream.Stream; public class QuickstepLauncher extends Launcher implements RecentsViewContainer, SystemShortcut.BubbleActivityStarter { + private static final String TAG = "QuickstepLauncher"; private static final boolean TRACE_LAYOUTS = SystemProperties.getBoolean("persist.debug.trace_layouts", false); private static final String TRACE_RELAYOUT_CLASS = @@ -561,20 +563,35 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, @Override public void onDestroy() { + // wrap non-trivial clean up blocks in try-catch to avoid stopping clean up of rest of + // objects + if (mAppTransitionManager != null) { - mAppTransitionManager.onActivityDestroyed(); + try { + mAppTransitionManager.onActivityDestroyed(); + } catch (Exception e) { + Log.e(TAG, "Failed to destroy mAppTransitionManager", e); + } } mAppTransitionManager = null; mIsPredictiveBackToHomeInProgress = false; if (mUnfoldTransitionProgressProvider != null) { - SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null); - mUnfoldTransitionProgressProvider.destroy(); + try { + SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null); + mUnfoldTransitionProgressProvider.destroy(); + } catch (Exception e) { + Log.e(TAG, "Failed to destroy mUnfoldTransitionProgressProvider", e); + } } OverviewComponentObserver.INSTANCE.get(this) .removeOverviewChangeListener(mOverviewChangeListener); - mTISBindHelper.onDestroy(); + try { + mTISBindHelper.onDestroy(); + } catch (Exception e) { + Log.e(TAG, "Failed to destroy mTISBindHelper", e); + } if (mLauncherUnfoldAnimationController != null) { mLauncherUnfoldAnimationController.onDestroy(); @@ -584,15 +601,22 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, mSplitSelectStateController.onDestroy(); } - RecentsView recentsView = getOverviewPanel(); - if (recentsView != null) { - recentsView.destroy(); + try { + RecentsView recentsView = getOverviewPanel(); + if (recentsView != null) { + recentsView.destroy(); + } + } catch (Exception e) { + Log.e(TAG, "Failed to destroy RecentsView", e); } - super.onDestroy(); - mHotseatPredictionController.destroy(); - if (mViewCapture != null) mViewCapture.close(); - removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler()); + try { + super.onDestroy(); + } finally { // trivial close operations in finally. + mHotseatPredictionController.destroy(); + if (mViewCapture != null) mViewCapture.close(); + removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler()); + } } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index b27c6e8381..54b4fa2ccb 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -23,6 +23,7 @@ import android.content.Context; import com.android.internal.jank.Cuj; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; @@ -153,7 +154,7 @@ public class AllAppsState extends LauncherState { return new PageAlphaProvider(DECELERATE_2) { @Override public float getPageAlpha(int pageIndex) { - return launcher.getDeviceProfile().isTablet + return isWorkspaceVisible(launcher.getDeviceProfile()) ? superPageAlphaProvider.getPageAlpha(pageIndex) : 0; } @@ -163,13 +164,17 @@ public class AllAppsState extends LauncherState { @Override public int getVisibleElements(Launcher launcher) { int elements = ALL_APPS_CONTENT | FLOATING_SEARCH_BAR; - // When All Apps is presented on a bottom sheet, HOTSEAT_ICONS are visible. - if (launcher.getDeviceProfile().isTablet) { + if (isWorkspaceVisible(launcher.getDeviceProfile())) { elements |= HOTSEAT_ICONS; } return elements; } + private static boolean isWorkspaceVisible(DeviceProfile deviceProfile) { + // Currently we hide the workspace with the all apps blur flag for simplicity. + return deviceProfile.isTablet && !Flags.allAppsBlur(); + } + @Override public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) { return 0; @@ -201,8 +206,12 @@ public class AllAppsState extends LauncherState { @Override public int getWorkspaceScrimColor(Launcher launcher) { - return launcher.getDeviceProfile().shouldShowAllAppsOnSheet() - ? launcher.getResources().getColor(R.color.widgets_picker_scrim) - : Themes.getAttrColor(launcher, R.attr.allAppsScrimColor); + if (!launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) { + return Themes.getAttrColor(launcher, R.attr.allAppsScrimColor); + } + if (Flags.allAppsBlur()) { + return Themes.getAttrColor(launcher, R.attr.allAppsScrimColorOverBlur); + } + return launcher.getResources().getColor(R.color.widgets_picker_scrim); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 963504f761..3170df9571 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -17,10 +17,12 @@ package com.android.launcher3.uioverrides.states; import static com.android.app.animation.Interpolators.DECELERATE_2; import static com.android.launcher3.Flags.enableDesktopExplodedView; +import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; import android.content.Context; +import android.graphics.Color; import android.graphics.Rect; import android.os.SystemProperties; @@ -35,6 +37,7 @@ import com.android.quickstep.util.BaseDepthController; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.system.BlurUtils; /** * Definition for overview state @@ -158,7 +161,9 @@ public class OverviewState extends LauncherState { @Override public int getWorkspaceScrimColor(Launcher launcher) { - return Themes.getAttrColor(launcher, R.attr.overviewScrimColor); + return enableOverviewBackgroundWallpaperBlur() && BlurUtils.supportsBlursOnWindows() + ? Color.TRANSPARENT + : Themes.getAttrColor(launcher, R.attr.overviewScrimColor); } @Override diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 7574c7f51d..168b856b25 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -136,6 +136,7 @@ import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.WindowBounds; import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; +import com.android.quickstep.fallback.window.RecentsWindowFlags; import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActiveGestureProtoLogProxy; @@ -903,7 +904,9 @@ public abstract class AbsSwipeUpHandler< } public Intent getLaunchIntent() { - return mGestureState.getOverviewIntent(); + // todo differentiate intent based on if we are on home or in app for overview in window + boolean useHomeIntentForWindow = RecentsWindowFlags.getEnableOverviewInWindow(); + return useHomeIntentForWindow ? getHomeIntent() : mGestureState.getOverviewIntent(); } /** * Called when the value of {@link #mCurrentShift} changes diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt index 914855bf1b..4280baf21d 100644 --- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt +++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt @@ -82,6 +82,7 @@ class DesktopSystemShortcut( taskKey.numActivities, taskKey.isTopActivityNoDisplay, taskKey.isActivityStackTransparent, + taskKey.userId, ) -> null !taskContainer.task.isDockable -> null diff --git a/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt b/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt index f97cf9cd91..3b823f5e60 100644 --- a/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt +++ b/quickstep/src/com/android/quickstep/ExternalDisplaySystemShortcut.kt @@ -80,6 +80,7 @@ class ExternalDisplaySystemShortcut( taskKey.numActivities, taskKey.isTopActivityNoDisplay, taskKey.isActivityStackTransparent, + taskKey.userId, ) -> null else -> { diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java index 081ed9d517..e5cbc66425 100644 --- a/quickstep/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/src/com/android/quickstep/InputConsumer.java @@ -63,14 +63,26 @@ public interface InputConsumer { "TYPE_BUBBLE_BAR", // 16 }; - InputConsumer NO_OP = () -> TYPE_NO_OP; + InputConsumer DEFAULT_NO_OP = createNoOpInputConsumer(Display.DEFAULT_DISPLAY); - int getType(); + static InputConsumer createNoOpInputConsumer(int displayId) { + return new InputConsumer() { + @Override + public int getType() { + return TYPE_NO_OP; + } - default int getDisplayId() { - return Display.DEFAULT_DISPLAY; + @Override + public int getDisplayId() { + return displayId; + } + }; } + int getType(); + + int getDisplayId(); + /** * Returns true if the user has crossed the threshold for it to be an explicit action. */ diff --git a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt index cd3ac12c82..c8ca5344c2 100644 --- a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt +++ b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt @@ -57,7 +57,7 @@ object InputConsumerUtils { @JvmStatic fun <S : BaseState<S>, T> newConsumer( context: Context, - resetGestureInputConsumer: ResetGestureInputConsumer?, + userUnlocked: Boolean, overviewComponentObserver: OverviewComponentObserver, deviceState: RecentsAnimationDeviceState, previousGestureState: GestureState, @@ -122,7 +122,8 @@ object InputConsumerUtils { // camera). createDeviceLockedInputConsumer( context, - resetGestureInputConsumer, + userUnlocked, + taskbarManager, deviceState, gestureState, taskAnimationManager, @@ -131,7 +132,10 @@ object InputConsumerUtils { ) } else { getDefaultInputConsumer( - resetGestureInputConsumer, + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX), ) } @@ -153,7 +157,8 @@ object InputConsumerUtils { base = newBaseConsumer<S, T>( context, - resetGestureInputConsumer, + userUnlocked, + taskbarManager, overviewComponentObserver, deviceState, previousGestureState, @@ -172,7 +177,14 @@ object InputConsumerUtils { "cannot start system gesture and recents " + "animation was not running, trying to use default input consumer" ) - base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString) + base = + getDefaultInputConsumer( + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, + reasonString, + ) } if (deviceState.isGesturalNavMode || gestureState.isTrackpadGesture) { handleOrientationSetup(base) @@ -237,7 +249,14 @@ object InputConsumerUtils { SUBSTRING_PREFIX, ) // Bubbles can handle home gesture itself. - base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString) + base = + getDefaultInputConsumer( + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, + reasonString, + ) } } @@ -279,7 +298,14 @@ object InputConsumerUtils { SUBSTRING_PREFIX, ) // Bubbles can handle home gesture itself. - base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString) + base = + getDefaultInputConsumer( + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, + reasonString, + ) } } @@ -374,7 +400,14 @@ object InputConsumerUtils { "%sscreen pinning is active, trying to use default input consumer", SUBSTRING_PREFIX, ) - base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString) + base = + getDefaultInputConsumer( + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, + reasonString, + ) } if (deviceState.canTriggerOneHandedAction(event)) { @@ -411,7 +444,7 @@ object InputConsumerUtils { context, deviceState, inputMonitorCompat, - InputConsumer.NO_OP, + InputConsumer.createNoOpInputConsumer(gestureState.displayId), gestureState, motionEvent, CompoundString.NO_OP, @@ -450,7 +483,8 @@ object InputConsumerUtils { @JvmStatic fun <S : BaseState<S>, T> newBaseConsumer( context: Context, - resetGestureInputConsumer: ResetGestureInputConsumer?, + userUnlocked: Boolean, + taskbarManager: TaskbarManager, overviewComponentObserver: OverviewComponentObserver, deviceState: RecentsAnimationDeviceState, previousGestureState: GestureState, @@ -467,7 +501,8 @@ object InputConsumerUtils { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer( context, - resetGestureInputConsumer, + userUnlocked, + taskbarManager, deviceState, gestureState, taskAnimationManager, @@ -521,7 +556,9 @@ object InputConsumerUtils { return if (gestureState.getContainerInterface<S, T>().isInLiveTileMode()) { createOverviewInputConsumer<S, T>( - resetGestureInputConsumer, + userUnlocked, + taskAnimationManager, + taskbarManager, deviceState, inputMonitorCompat, previousGestureState, @@ -534,7 +571,10 @@ object InputConsumerUtils { ) } else if (runningTask == null) { getDefaultInputConsumer( - resetGestureInputConsumer, + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, reasonString.append("%srunning task == null", SUBSTRING_PREFIX), ) } else if ( @@ -543,7 +583,9 @@ object InputConsumerUtils { forceOverviewInputConsumer ) { createOverviewInputConsumer<S, T>( - resetGestureInputConsumer, + userUnlocked, + taskAnimationManager, + taskbarManager, deviceState, inputMonitorCompat, previousGestureState, @@ -565,7 +607,10 @@ object InputConsumerUtils { ) } else if (deviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) { getDefaultInputConsumer( - resetGestureInputConsumer, + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, reasonString.append( if (launcherChildActivityResumed) "%sis launcher child-task, trying to use default input consumer" @@ -592,7 +637,8 @@ object InputConsumerUtils { private fun createDeviceLockedInputConsumer( context: Context, - resetGestureInputConsumer: ResetGestureInputConsumer?, + userUnlocked: Boolean, + taskbarManager: TaskbarManager, deviceState: RecentsAnimationDeviceState, gestureState: GestureState, taskAnimationManager: TaskAnimationManager, @@ -617,7 +663,10 @@ object InputConsumerUtils { ) } else { getDefaultInputConsumer( - resetGestureInputConsumer, + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, reasonString.append( if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) "%srunning task == null, trying to use default input consumer" @@ -631,7 +680,9 @@ object InputConsumerUtils { } private fun <S : BaseState<S>, T> createOverviewInputConsumer( - resetGestureInputConsumer: ResetGestureInputConsumer?, + userUnlocked: Boolean, + taskAnimationManager: TaskAnimationManager, + taskbarManager: TaskbarManager, deviceState: RecentsAnimationDeviceState, inputMonitorCompat: InputMonitorCompat, previousGestureState: GestureState, @@ -642,7 +693,10 @@ object InputConsumerUtils { val container: T = gestureState.getContainerInterface<S, T>().getCreatedContainer() ?: return getDefaultInputConsumer( - resetGestureInputConsumer, + gestureState.displayId, + userUnlocked, + taskAnimationManager, + taskbarManager, reasonString.append( "%sactivity == null, trying to use default input consumer", SUBSTRING_PREFIX, @@ -694,24 +748,34 @@ object InputConsumerUtils { } /** Returns the [ResetGestureInputConsumer] if user is unlocked, else NO_OP. */ - private fun getDefaultInputConsumer( - resetGestureInputConsumer: ResetGestureInputConsumer?, + @JvmStatic + fun getDefaultInputConsumer( + displayId: Int, + userUnlocked: Boolean, + taskAnimationManager: TaskAnimationManager?, + taskbarManager: TaskbarManager?, reasonString: CompoundString, ): InputConsumer { - return if (resetGestureInputConsumer != null) { + return if (userUnlocked && taskAnimationManager != null && taskbarManager != null) { reasonString.append( - "%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer", + "%sResetGestureInputConsumer available, using ResetGestureInputConsumer", SUBSTRING_PREFIX, ) - resetGestureInputConsumer + ResetGestureInputConsumer(displayId, taskAnimationManager) { + taskbarManager.getTaskbarForDisplay(displayId) + } } else { reasonString.append( - "%smResetGestureInputConsumer not initialized, using no-op input consumer", + "%s${ + if (userUnlocked) "user is locked" + else if (taskAnimationManager == null) "taskAnimationManager is null" + else "taskbarManager is null" + }, using no-op input consumer", SUBSTRING_PREFIX, ) - // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to + // ResetGestureInputConsumer isn't available until onUserUnlocked(), so reset to // NO_OP until then (we never want these to be null). - InputConsumer.NO_OP + InputConsumer.createNoOpInputConsumer(displayId) } } diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index 2ff42cd991..783ec2c7da 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -220,7 +220,7 @@ public class LauncherBackAnimationController { mHandler.post(() -> { LauncherBackAnimationController controller = mControllerRef.get(); if (controller != null) { - controller.initBackMotion(backEvent); + controller.startBack(backEvent); mProgressAnimator.onBackStarted(backEvent, event -> { float backProgress = event.getProgress(); controller.mBackProgress = @@ -270,7 +270,6 @@ public class LauncherBackAnimationController { } } controller.mAnimationFinishedCallback = finishedCallback; - controller.startBack(); } @Override @@ -295,32 +294,34 @@ public class LauncherBackAnimationController { mBackCallback = null; } - private void initBackMotion(BackMotionEvent backEvent) { + private void startBack(BackMotionEvent backEvent) { // in case we're still animating an onBackCancelled event, let's remove the finish- // callback from the progress animator to prevent calling finishAnimation() before // restarting a new animation - // Side note: initBackMotion is never called during the post-commit phase if the back - // gesture was committed (not cancelled). BackAnimationController prevents that. Therefore - // we don't have to handle that case. + // Side note: startBack is never called during the post-commit phase if the back gesture + // was committed (not cancelled). BackAnimationController prevents that. Therefore we + // don't have to handle that case. mProgressAnimator.removeOnBackCancelledFinishCallback(); mBackInProgress = true; - mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY()); - } - private void startBack() { - if (mBackTarget == null) { + RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget(); + + if (appTarget == null || appTarget.leash == null || !appTarget.leash.isValid()) { return; } mTransaction - .show(mBackTarget.leash) + .show(appTarget.leash) .setAnimationTransaction(); - mStartRect.set(mBackTarget.windowConfiguration.getMaxBounds()); + mBackTarget = appTarget; + mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY()); + + mStartRect.set(appTarget.windowConfiguration.getMaxBounds()); // inset bottom in case of taskbar being present if (!predictiveBackThreeButtonNav() || mLauncher.getDeviceProfile().isTaskbarPresent || DisplayController.getNavigationMode(mLauncher) == NavigationMode.NO_BUTTON) { - mStartRect.inset(0, 0, 0, mBackTarget.contentInsets.bottom); + mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom); } mLauncherTargetView = mQuickstepTransitionManager.findLauncherView( diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index bf87291f10..152630a5a0 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -28,6 +28,7 @@ import android.window.TransitionInfo import androidx.annotation.BinderThread import androidx.annotation.UiThread import androidx.annotation.VisibleForTesting +import com.android.app.tracing.traceSection import com.android.internal.jank.Cuj import com.android.launcher3.Flags.enableAltTabKqsOnConnectedDisplays import com.android.launcher3.Flags.enableLargeDesktopWindowingTile @@ -74,7 +75,6 @@ class OverviewCommandHelper constructor( private val touchInteractionService: TouchInteractionService, private val overviewComponentObserver: OverviewComponentObserver, - private val taskAnimationManager: TaskAnimationManager, private val dispatcherProvider: DispatcherProvider = ProductionDispatchers, private val recentsDisplayModel: RecentsDisplayModel, private val focusState: FocusState, @@ -143,35 +143,38 @@ constructor( * completion (returns false). */ @UiThread - private fun processNextCommand() { - val command: CommandInfo = - commandQueue.firstOrNull() - ?: run { - Log.d(TAG, "no pending commands to be executed.") - return - } + private fun processNextCommand() = + traceSection("OverviewCommandHelper.processNextCommand") { + val command: CommandInfo? = commandQueue.firstOrNull() + if (command == null) { + Log.d(TAG, "no pending commands to be executed.") + return@traceSection + } - command.status = CommandStatus.PROCESSING - Log.d(TAG, "executing command: $command") + command.status = CommandStatus.PROCESSING + Log.d(TAG, "executing command: $command") - if (enableOverviewCommandHelperTimeout()) { - coroutineScope.launch(dispatcherProvider.main) { - withTimeout(QUEUE_WAIT_DURATION_IN_MS) { - executeCommandSuspended(command) - ensureActive() - onCommandFinished(command) + if (enableOverviewCommandHelperTimeout()) { + coroutineScope.launch(dispatcherProvider.main) { + traceSection("OverviewCommandHelper.executeCommandWithTimeout") { + withTimeout(QUEUE_WAIT_DURATION_IN_MS) { + executeCommandSuspended(command) + ensureActive() + onCommandFinished(command) + } + } } - } - } else { - val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) }) - Log.d(TAG, "command executed: $command with result: $result") - if (result) { - onCommandFinished(command) } else { - Log.d(TAG, "waiting for command callback: $command") + val result = + executeCommand(command, onCallbackResult = { onCommandFinished(command) }) + Log.d(TAG, "command executed: $command with result: $result") + if (result) { + onCommandFinished(command) + } else { + Log.d(TAG, "waiting for command callback: $command") + } } } - } /** * Executes the task and returns true if next task can be executed. If false, then the next task @@ -453,6 +456,14 @@ constructor( } } + val displayId = gestureState.displayId + val taskAnimationManager = + recentsDisplayModel.getTaskAnimationManager(displayId) + ?: run { + Log.e(TAG, "No TaskAnimationManager found for display $displayId") + ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable(displayId) + return false + } if (taskAnimationManager.isRecentsAnimationRunning) { command.setAnimationCallbacks( taskAnimationManager.continueRecentsAnimation(gestureState) diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index cc5b2dabb7..dab78c5df3 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -511,13 +511,14 @@ public class RecentTasksList implements WindowManagerProxy.DesktopVisibilityList // When the multiple desktop feature is disabled, there can only be up to a single desk // on each display, The desk ID doesn't matter and should not be used. return MapsKt.map(perDisplayTasks, - it -> new DesktopTask(DesktopVisibilityController.INACTIVE_DESK_ID, + it -> new DesktopTask(DesktopVisibilityController.INACTIVE_DESK_ID, it.getKey(), it.getValue())); } else { final int deskId = recentTaskInfo.getDeskId(); + final int displayId = recentTaskInfo.getDeskDisplayId(); List<Task> tasks = CollectionsKt.map(recentTaskInfo.getTaskInfoList(), it -> createTask(it, minimizedTaskIds)); - return List.of(new DesktopTask(deskId, tasks)); + return List.of(new DesktopTask(deskId, displayId, tasks)); } } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt index 506f85d882..cd87d93650 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt @@ -690,10 +690,10 @@ class SystemUiProxy @Inject constructor(@ApplicationContext private val context: bubbles?.showDropTarget(show, bubbleBarLocation) } - /** Tells SysUI to move the bubble to full screen. */ - fun moveBubbleToFullscreen(key: String) { - executeWithErrorLog({ "Failed to call moveBubbleToFullscreen"}) { - bubbles?.moveBubbleToFullscreen(key) + /** Tells SysUI to move the dragged bubble to full screen. */ + fun moveDraggedBubbleToFullscreen(key: String, dropLocation: Point) { + executeWithErrorLog({ "Failed to call moveDraggedBubbleToFullscreen"}) { + bubbles?.moveDraggedBubbleToFullscreen(key, dropLocation) } } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 1c7f23c25d..4f00381271 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -77,6 +77,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn private boolean mRecentsAnimationStartPending = false; private boolean mShouldIgnoreMotionEvents = false; + private final int mDisplayId; private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { @Override @@ -101,10 +102,13 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } }; - TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState) { + public TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState, + int displayId) { mCtx = ctx; mDeviceState = deviceState; + mDisplayId = displayId; } + SystemUiProxy getSystemUiProxy() { return SystemUiProxy.INSTANCE.get(mCtx); } @@ -489,6 +493,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn public void dump(String prefix, PrintWriter pw) { pw.println(prefix + "TaskAnimationManager:"); + pw.println(prefix + "\tmDisplayId=" + mDisplayId); if (enableHandleDelayedGestureCallbacks()) { pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending); diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 855ff98062..d161d452b9 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -433,9 +433,7 @@ public final class TaskViewUtils { out.addListener(new AnimationSuccessListener() { @Override public void onAnimationStart(Animator animation) { - for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) { - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false); - } + recentsView.setDrawBelowRecents(false, remoteTargetHandles); } @Override diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java index b3d9da32a9..8116a8867d 100644 --- a/quickstep/src/com/android/quickstep/TopTaskTracker.java +++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java @@ -46,6 +46,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; import com.android.launcher3.util.SplitConfigurationOptions.StageType; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.dagger.QuickstepBaseAppComponent; +import com.android.quickstep.util.DesksUtils; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -341,7 +342,8 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta ArrayList<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList); // Strip the pinned task and recents task - tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t)); + tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t) + || DesksUtils.isDesktopWallpaperTask(t)); return new CachedTaskInfo(tasks); } } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 741ae7dad5..6912ba7204 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -35,6 +35,7 @@ import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WI import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType; import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER; +import static com.android.quickstep.InputConsumer.createNoOpInputConsumer; import static com.android.quickstep.InputConsumerUtils.newConsumer; import static com.android.quickstep.InputConsumerUtils.tryCreateAssistantInputConsumer; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -98,7 +99,6 @@ import com.android.quickstep.fallback.window.RecentsWindowFlags; import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler; import com.android.quickstep.inputconsumers.BubbleBarInputConsumer; import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer; -import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActiveGestureLog.CompoundString; import com.android.quickstep.util.ActiveGestureProtoLogProxy; @@ -557,12 +557,11 @@ public class TouchInteractionService extends Service { private OverviewComponentObserver mOverviewComponentObserver; private InputConsumerController mInputConsumer; private RecentsAnimationDeviceState mDeviceState; - private TaskAnimationManager mTaskAnimationManager; - private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; - private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP; + private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.DEFAULT_NO_OP; + private @NonNull InputConsumer mConsumer = InputConsumer.DEFAULT_NO_OP; private Choreographer mMainChoreographer; - private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer; + private boolean mUserUnlocked = false; private GestureState mGestureState = DEFAULT_STATE; private InputMonitorDisplayModel mInputMonitorDisplayModel; @@ -667,7 +666,7 @@ public class TouchInteractionService extends Service { if (ENABLE_GESTURE_NAV_ON_CONNECTED_DISPLAYS.isTrue()) { mInputMonitorDisplayModel = new InputMonitorDisplayModel(this); } else { - mInputMonitorCompat = new InputMonitorCompat("swipe-up", Display.DEFAULT_DISPLAY); + mInputMonitorCompat = new InputMonitorCompat("swipe-up", DEFAULT_DISPLAY); mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), mMainChoreographer, this::onInputEvent); } @@ -687,13 +686,11 @@ public class TouchInteractionService extends Service { public void onUserUnlocked() { Log.d(TAG, "onUserUnlocked: userId=" + getUserId() + " instance=" + System.identityHashCode(this)); - mTaskAnimationManager = new TaskAnimationManager(this, mDeviceState); mOverviewComponentObserver = OverviewComponentObserver.INSTANCE.get(this); mOverviewCommandHelper = new OverviewCommandHelper(this, - mOverviewComponentObserver, mTaskAnimationManager, mRecentsDisplayModel, + mOverviewComponentObserver, mRecentsDisplayModel, SystemUiProxy.INSTANCE.get(this).getFocusState(), mTaskbarManager); - mResetGestureInputConsumer = new ResetGestureInputConsumer( - mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext); + mUserUnlocked = true; mInputConsumer.registerInputConsumer(); for (int displayId : mDeviceState.getDisplaysWithSysUIState()) { onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags(displayId), displayId); @@ -766,14 +763,18 @@ public class TouchInteractionService extends Service { if (LockedUserState.get(this).isUserUnlocked()) { long systemUiStateFlags = mDeviceState.getSystemUiStateFlags(displayId); mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags, displayId); - if (displayId == Display.DEFAULT_DISPLAY) { + if (displayId == DEFAULT_DISPLAY) { // The following don't care about non-default displays, at least for now. If they // ever will, they should be taken care of. SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); mOverviewComponentObserver.setHomeDisabled(mDeviceState.isHomeDisabled()); // TODO b/399371607 - Propagate to taskAnimationManager once overview is multi // display. - mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags); + TaskAnimationManager taskAnimationManager = + mRecentsDisplayModel.getTaskAnimationManager(displayId); + if (taskAnimationManager != null) { + taskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags); + } } } } @@ -865,11 +866,18 @@ public class TouchInteractionService extends Service { boolean isHoverActionWithoutConsumer = enableCursorHoverStates() && isHoverActionWithoutConsumer(event); + TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + displayId); + if (taskAnimationManager == null) { + Log.e(TAG, "TaskAnimationManager not available for displayId " + displayId); + ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable(displayId); + return; + } if (enableHandleDelayedGestureCallbacks()) { if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { - mTaskAnimationManager.notifyNewGestureStart(); + taskAnimationManager.notifyNewGestureStart(); } - if (mTaskAnimationManager.shouldIgnoreMotionEvents()) { + if (taskAnimationManager.shouldIgnoreMotionEvents()) { if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { ActiveGestureProtoLogProxy.logOnInputIgnoringFollowingEvents(displayId); } @@ -917,7 +925,7 @@ public class TouchInteractionService extends Service { } else { reasonString.append(" but event cannot trigger Assistant, " + "consuming gesture as no-op"); - mUncheckedConsumer = InputConsumer.NO_OP; + mUncheckedConsumer = createNoOpInputConsumer(displayId); } } else if ((!isOneHandedModeActive && isInSwipeUpTouchRegion) || isHoverActionWithoutConsumer || isOnBubbles) { @@ -934,12 +942,12 @@ public class TouchInteractionService extends Service { mGestureState = newGestureState; mConsumer = newConsumer( this, - mResetGestureInputConsumer, + mUserUnlocked, mOverviewComponentObserver, mDeviceState, prevGestureState, mGestureState, - mTaskAnimationManager, + taskAnimationManager, inputMonitorCompat, getSwipeUpHandlerFactory(), this::onConsumerInactive, @@ -968,19 +976,22 @@ public class TouchInteractionService extends Service { + "consuming gesture for one-handed action"); // Consume gesture event for triggering one handed feature. mUncheckedConsumer = new OneHandedModeInputConsumer( - this, displayId, mDeviceState, InputConsumer.NO_OP, inputMonitorCompat); + this, + displayId, + mDeviceState, + InputConsumer.createNoOpInputConsumer(displayId), inputMonitorCompat); } else { - mUncheckedConsumer = InputConsumer.NO_OP; + mUncheckedConsumer = InputConsumer.createNoOpInputConsumer(displayId); } } else { // Other events - if (mUncheckedConsumer != InputConsumer.NO_OP) { + if (mUncheckedConsumer.getType() != InputConsumer.TYPE_NO_OP) { // Only transform the event if we are handling it in a proper consumer mRotationTouchHelper.setOrientationTransformIfNeeded(event); } } - if (mUncheckedConsumer != InputConsumer.NO_OP) { + if (mUncheckedConsumer.getType() != InputConsumer.TYPE_NO_OP) { switch (action) { case ACTION_DOWN: ActiveGestureProtoLogProxy.logOnInputEventActionDown(displayId, reasonString); @@ -1053,7 +1064,9 @@ public class TouchInteractionService extends Service { GestureState.TrackpadGestureType trackpadGestureType) { final GestureState gestureState; TopTaskTracker.CachedTaskInfo taskInfo; - if (mTaskAnimationManager.isRecentsAnimationRunning()) { + TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + displayId); + if (taskAnimationManager != null && taskAnimationManager.isRecentsAnimationRunning()) { gestureState = new GestureState( mOverviewComponentObserver, displayId, ActiveGestureLog.INSTANCE.getLogId()); TopTaskTracker.CachedTaskInfo previousTaskInfo = previousGestureState.getRunningTask(); @@ -1100,7 +1113,12 @@ public class TouchInteractionService extends Service { } private void reset(int displayId) { - mConsumer = mUncheckedConsumer = getDefaultInputConsumer(); + mConsumer = mUncheckedConsumer = InputConsumerUtils.getDefaultInputConsumer( + displayId, + mUserUnlocked, + mRecentsDisplayModel.getTaskAnimationManager(displayId), + mTaskbarManager, + CompoundString.NO_OP); mGestureState = DEFAULT_STATE; // By default, use batching of the input events, but check receiver before using in the rare // case that the monitor was disposed before the swipe settled @@ -1110,29 +1128,6 @@ public class TouchInteractionService extends Service { } } - private @NonNull InputConsumer getDefaultInputConsumer() { - return getDefaultInputConsumer(CompoundString.NO_OP); - } - - /** - * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP. - */ - private @NonNull InputConsumer getDefaultInputConsumer(@NonNull CompoundString reasonString) { - if (mResetGestureInputConsumer != null) { - reasonString.append( - "%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer", - SUBSTRING_PREFIX); - return mResetGestureInputConsumer; - } else { - reasonString.append( - "%smResetGestureInputConsumer not initialized, using no-op input consumer", - SUBSTRING_PREFIX); - // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to - // NO_OP until then (we never want these to be null). - return InputConsumer.NO_OP; - } - } - @Override public void onConfigurationChanged(Configuration newConfig) { if (!LockedUserState.get(this).isUserUnlocked()) { @@ -1208,13 +1203,11 @@ public class TouchInteractionService extends Service { if (createdOverviewContainer != null) { createdOverviewContainer.getDeviceProfile().dump(this, "", pw); } + resource.getTaskAnimationManager().dump("\t", pw); } pw.println("\tmConsumer=" + mConsumer.getName()); ActiveGestureLog.INSTANCE.dump("", pw); RecentsModel.INSTANCE.get(this).dump("", pw); - if (mTaskAnimationManager != null) { - mTaskAnimationManager.dump("", pw); - } mTaskbarManager.dumpLogs("", pw); DesktopVisibilityController.INSTANCE.get(this).dumpLogs("", pw); pw.println("ContextualSearchStateManager:"); @@ -1226,22 +1219,28 @@ public class TouchInteractionService extends Service { private AbsSwipeUpHandler createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs) { - return new LauncherSwipeHandlerV2(this, mTaskAnimationManager, - gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), + TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + gestureState.getDisplayId()); + return new LauncherSwipeHandlerV2(this, taskAnimationManager, + gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } private AbsSwipeUpHandler createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs) { - return new FallbackSwipeHandler(this, mTaskAnimationManager, - gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), + TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + gestureState.getDisplayId()); + return new FallbackSwipeHandler(this, taskAnimationManager, + gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } private AbsSwipeUpHandler createRecentsWindowSwipeHandler( GestureState gestureState, long touchTimeMs) { - return new RecentsWindowSwipeHandler(this, mTaskAnimationManager, - gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), + TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + gestureState.getDisplayId()); + return new RecentsWindowSwipeHandler(this, taskAnimationManager, + gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index 8ec97edbd7..29b662659f 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -292,8 +292,7 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon // disabling this so app icons aren't drawn on top of recent tasks. if (isOverlayEnabled && !RecentsWindowFlags.Companion.getEnableOverviewInWindow()) { - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)); + mBlurUtils.setDrawLiveTileBelowRecents(true); } } @@ -303,6 +302,7 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon if (enabled) { RecentsState state = mContainer.getStateManager().getState(); setDisallowScrollToClearAll(!state.hasClearAllButton()); + setDisallowScrollToAddDesk(!state.hasAddDeskButton()); } } diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt index 12dc17775f..0f611eb6d8 100644 --- a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt +++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt @@ -18,6 +18,7 @@ package com.android.quickstep.fallback.window import android.content.Context import android.view.Display +import android.view.Display.DEFAULT_DISPLAY import androidx.core.util.valueIterator import com.android.launcher3.dagger.ApplicationContext import com.android.launcher3.dagger.LauncherAppSingleton @@ -26,6 +27,8 @@ import com.android.launcher3.util.DaggerSingletonTracker import com.android.launcher3.util.WallpaperColorHints import com.android.quickstep.DisplayModel import com.android.quickstep.FallbackWindowInterface +import com.android.quickstep.RecentsAnimationDeviceState +import com.android.quickstep.TaskAnimationManager import com.android.quickstep.dagger.QuickstepBaseAppComponent import com.android.quickstep.fallback.window.RecentsDisplayModel.RecentsDisplayResource import com.android.quickstep.fallback.window.RecentsWindowFlags.Companion.enableOverviewInWindow @@ -55,8 +58,11 @@ constructor( init { if (enableOverviewInWindow) { registerDisplayListener() - tracker.addCloseable { destroy() } + } else { + // Always create resource for default display + storeDisplayResource(DEFAULT_DISPLAY) } + tracker.addCloseable { destroy() } } override fun createDisplayResource(display: Display): RecentsDisplayResource { @@ -75,6 +81,10 @@ constructor( return getDisplayResource(displayId)?.fallbackWindowInterface } + fun getTaskAnimationManager(displayId: Int): TaskAnimationManager? { + return getDisplayResource(displayId)?.taskAnimationManager + } + val activeDisplayResources: Iterable<RecentsDisplayResource> get() = object : Iterable<RecentsDisplayResource> { @@ -86,12 +96,20 @@ constructor( val displayContext: Context, val wallpaperColorHints: Int, ) : DisplayResource() { - val recentsWindowManager = RecentsWindowManager(displayContext, wallpaperColorHints) - val fallbackWindowInterface: FallbackWindowInterface = - FallbackWindowInterface(recentsWindowManager) + val recentsWindowManager = + if (enableOverviewInWindow) RecentsWindowManager(displayContext, wallpaperColorHints) + else null + val fallbackWindowInterface = + if (enableOverviewInWindow) FallbackWindowInterface(recentsWindowManager) else null + val taskAnimationManager = + TaskAnimationManager( + displayContext, + RecentsAnimationDeviceState.INSTANCE.get(displayContext), + displayId, + ) override fun cleanup() { - recentsWindowManager.destroy() + recentsWindowManager?.destroy() } override fun dump(prefix: String, writer: PrintWriter) { diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt index 99531546f5..d88077429e 100644 --- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt +++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFlags.kt @@ -29,8 +29,15 @@ class RecentsWindowFlags { val enableFallbackOverviewInWindow: DesktopModeFlag = DesktopModeFlag(Flags::enableFallbackOverviewInWindow, false) + @JvmField + val enableOverviewOnConnectedDisplays: DesktopModeFlag = + DesktopModeFlag(Flags::enableOverviewOnConnectedDisplays, false) + @JvmStatic val enableOverviewInWindow - get() = enableLauncherOverviewInWindow.isTrue || enableFallbackOverviewInWindow.isTrue + get() = + enableLauncherOverviewInWindow.isTrue || + enableFallbackOverviewInWindow.isTrue || + enableOverviewOnConnectedDisplays.isTrue } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index c8cf58c1f9..2db75738f4 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -58,7 +58,6 @@ import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RotationTouchHelper; import com.android.quickstep.TaskAnimationManager; -import com.android.quickstep.fallback.window.RecentsWindowFlags; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; @@ -437,9 +436,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); notifyGestureStarted(true /*isLikelyToStartNewTask*/); } else { - // todo differentiate intent based on if we are on home or in app for overview in window - Intent intent = new Intent(RecentsWindowFlags.Companion.getEnableOverviewInWindow() - ? mInteractionHandler.getHomeIntent() : mInteractionHandler.getLaunchIntent()); + Intent intent = new Intent(mInteractionHandler.getLaunchIntent()); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mInteractionHandler); diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java deleted file mode 100644 index 349f4d2f2f..0000000000 --- a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.quickstep.inputconsumers; - -import android.view.MotionEvent; - -import com.android.launcher3.taskbar.TaskbarActivityContext; -import com.android.quickstep.InputConsumer; -import com.android.quickstep.TaskAnimationManager; - -import java.util.function.Supplier; - -/** - * A NO_OP input consumer which also resets any pending gesture - */ -public class ResetGestureInputConsumer implements InputConsumer { - - private final TaskAnimationManager mTaskAnimationManager; - private final Supplier<TaskbarActivityContext> mActivityContextSupplier; - - public ResetGestureInputConsumer( - TaskAnimationManager taskAnimationManager, - Supplier<TaskbarActivityContext> activityContextSupplier) { - mTaskAnimationManager = taskAnimationManager; - mActivityContextSupplier = activityContextSupplier; - } - - @Override - public int getType() { - return TYPE_RESET_GESTURE; - } - - @Override - public void onMotionEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN - && mTaskAnimationManager.isRecentsAnimationRunning()) { - TaskbarActivityContext tac = mActivityContextSupplier.get(); - mTaskAnimationManager.finishRunningRecentsAnimation( - /* toHome= */ tac != null && !tac.isInApp()); - } - } -} diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt new file mode 100644 index 0000000000..96e7943061 --- /dev/null +++ b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.inputconsumers + +import android.view.MotionEvent +import com.android.launcher3.taskbar.TaskbarActivityContext +import com.android.quickstep.InputConsumer +import com.android.quickstep.TaskAnimationManager +import java.util.function.Supplier + +/** A NO_OP input consumer which also resets any pending gesture */ +class ResetGestureInputConsumer( + private val displayId: Int, + private val taskAnimationManager: TaskAnimationManager, + private val activityContextSupplier: Supplier<TaskbarActivityContext?>, +) : InputConsumer { + override fun getType() = InputConsumer.TYPE_RESET_GESTURE + + override fun getDisplayId() = displayId + + override fun onMotionEvent(ev: MotionEvent) { + if ( + ev.action == MotionEvent.ACTION_DOWN && taskAnimationManager.isRecentsAnimationRunning + ) { + val tac = activityContextSupplier.get() + taskAnimationManager.finishRunningRecentsAnimation( + /* toHome= */ tac != null && !tac.isInApp + ) + } + } +} diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt index c4e343e1d0..b8f43a4c36 100644 --- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt @@ -661,7 +661,7 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { ): SplitIconPositions { return if (Flags.enableOverviewIconMenu()) { if (isRtl) { - SplitIconPositions(0, -(totalThumbnailHeight - primarySnapshotHeight)) + SplitIconPositions(-(totalThumbnailHeight - primarySnapshotHeight), 0) } else { SplitIconPositions(0, primarySnapshotHeight + dividerSize) } diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt index 67358bbb45..80b50cbd83 100644 --- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt @@ -248,14 +248,14 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { val iconCenter = iconAppChipView.getHeight() / 2f if (isRtl) { - iconMenuParams.gravity = Gravity.TOP or Gravity.END + iconMenuParams.gravity = Gravity.TOP or Gravity.START iconMenuParams.topMargin = iconMenuMargin iconMenuParams.marginEnd = thumbnailTopMargin // Use half menu height to place the pivot within the X/Y center of icon in the menu. iconAppChipView.pivotX = iconMenuParams.width / 2f iconAppChipView.pivotY = iconMenuParams.width / 2f } else { - iconMenuParams.gravity = Gravity.BOTTOM or Gravity.START + iconMenuParams.gravity = Gravity.BOTTOM or Gravity.END iconMenuParams.topMargin = 0 iconMenuParams.marginEnd = 0 iconAppChipView.pivotX = iconCenter @@ -409,7 +409,7 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { if (Flags.enableOverviewIconMenu()) { val appChipView = iconView as IconAppChipView layoutParams.gravity = - if (isRtl) Gravity.TOP or Gravity.END else Gravity.BOTTOM or Gravity.START + if (isRtl) Gravity.TOP or Gravity.START else Gravity.BOTTOM or Gravity.END appChipView.layoutParams = layoutParams appChipView.setSplitTranslationX(0f) appChipView.setSplitTranslationY(translationY.toFloat()) diff --git a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt index aa1c236e1d..679daf8ef6 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt @@ -17,6 +17,7 @@ package com.android.quickstep.recents.ui.mapper import android.view.View.OnClickListener +import com.android.launcher3.Flags.enableDesktopExplodedView import com.android.quickstep.recents.ui.viewmodel.TaskData import com.android.quickstep.task.thumbnail.TaskHeaderUiState import com.android.quickstep.task.thumbnail.TaskThumbnailUiState @@ -99,7 +100,8 @@ object TaskUiStateMapper { hasHeader: Boolean, clickCloseListener: OnClickListener?, ) = - hasHeader && + enableDesktopExplodedView() && + hasHeader && taskData.icon != null && taskData.titleDescription != null && clickCloseListener != null diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt index 2dbd8117eb..a40929c5f0 100644 --- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt +++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskContentView.kt @@ -26,7 +26,6 @@ import android.view.View import android.view.ViewOutlineProvider import android.widget.LinearLayout import androidx.core.view.isInvisible -import com.android.launcher3.Flags.enableDesktopExplodedView import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.R import com.android.launcher3.util.ViewPool @@ -65,7 +64,6 @@ class TaskContentView @JvmOverloads constructor(context: Context, attrs: Attribu override fun onFinishInflate() { super.onFinishInflate() - maybeCreateHeader() createTaskThumbnailView() } @@ -122,12 +120,12 @@ class TaskContentView @JvmOverloads constructor(context: Context, attrs: Attribu invalidateOutline() } - private fun maybeCreateHeader() { - if (enableDesktopExplodedView() && taskHeaderView == null) { + private fun createHeaderView(taskHeaderState: TaskHeaderUiState) { + if (taskHeaderView == null && taskHeaderState is TaskHeaderUiState.ShowHeader) { taskHeaderView = LayoutInflater.from(context).inflate(R.layout.task_header_view, this, false) as TaskHeaderView - addView(taskHeaderView) + addView(taskHeaderView, 0) } } @@ -153,6 +151,7 @@ class TaskContentView @JvmOverloads constructor(context: Context, attrs: Attribu taskThumbnailUiState: TaskThumbnailUiState, taskId: Int?, ) { + createHeaderView(taskHeaderState) taskHeaderView?.setState(taskHeaderState) taskThumbnailView?.setState(taskThumbnailUiState, taskId) } diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java index 5d6bb1d2e6..89f1e33d6e 100644 --- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java +++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.util; +import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import android.app.WallpaperManager; @@ -24,6 +25,9 @@ import android.util.Log; import android.view.AttachedSurfaceControl; import android.view.SurfaceControl; +import androidx.annotation.Nullable; + +import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -74,11 +78,14 @@ public class BaseDepthController { /** * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. + * * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ private float mDepth; - protected SurfaceControl mSurface; + protected SurfaceControl mBaseSurface; + + protected SurfaceControl mBaseSurfaceOverride; // Hints that there is potentially content behind Launcher and that we shouldn't optimize by // marking the launcher surface as opaque. Only used in certain Launcher states. @@ -99,15 +106,29 @@ public class BaseDepthController { protected boolean mWaitingOnSurfaceValidity; + private SurfaceControl mBlurSurface = null; + public BaseDepthController(Launcher activity) { mLauncher = activity; - mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius); + if (Flags.allAppsBlur()) { + mMaxBlurRadius = activity.getResources().getDimensionPixelSize( + R.dimen.max_depth_blur_radius_enhanced); + } else { + mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius); + } mWallpaperManager = activity.getSystemService(WallpaperManager.class); MultiPropertyFactory<BaseDepthController> depthProperty = new MultiPropertyFactory<>(this, DEPTH, DEPTH_INDEX_COUNT, Float::max); stateDepth = depthProperty.get(DEPTH_INDEX_STATE_TRANSITION); widgetDepth = depthProperty.get(DEPTH_INDEX_WIDGET); + if (enableOverviewBackgroundWallpaperBlur()) { + mBlurSurface = new SurfaceControl.Builder() + .setName("Overview Blur") + .setHidden(false) + .build(); + } + } protected void setCrossWindowBlursEnabled(boolean isEnabled) { @@ -145,11 +166,11 @@ public class BaseDepthController { if (!BlurUtils.supportsBlursOnWindows()) { return; } - if (mSurface == null) { + if (mBaseSurface == null) { Log.d(TAG, "mSurface is null and mCurrentBlur is: " + mCurrentBlur); return; } - if (!mSurface.isValid()) { + if (!mBaseSurface.isValid()) { Log.d(TAG, "mSurface is not valid"); mWaitingOnSurfaceValidity = true; onInvalidSurface(); @@ -168,10 +189,21 @@ public class BaseDepthController { mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg || mPauseBlurs ? 0 : (int) (blurAmount * mMaxBlurRadius); - SurfaceControl.Transaction transaction = new SurfaceControl.Transaction() - .setBackgroundBlurRadius(mSurface, mCurrentBlur) - .setOpaque(mSurface, isSurfaceOpaque); - + SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); + if (enableOverviewBackgroundWallpaperBlur() && mBlurSurface != null) { + // Reparent to launcher for full screen blur. + transaction.setBackgroundBlurRadius(mBlurSurface, mCurrentBlur) + .reparent(mBlurSurface, mBaseSurface); + // Set mBlurSurface to be 1 layer behind mBaseSurface or mBaseSurfaceOverride. + if (mBaseSurfaceOverride != null && mBaseSurfaceOverride.isValid()) { + transaction.setRelativeLayer(mBlurSurface, mBaseSurfaceOverride, -1); + } else { + transaction.setRelativeLayer(mBlurSurface, mBaseSurface, -1); + } + } else { + transaction.setBackgroundBlurRadius(mBaseSurface, mCurrentBlur); + } + transaction.setOpaque(mBaseSurface, isSurfaceOpaque); // Set early wake-up flags when we know we're executing an expensive operation, this way // SurfaceFlinger will adjust its internal offsets to avoid jank. boolean wantsEarlyWakeUp = depth > 0 && depth < 1; @@ -203,13 +235,26 @@ public class BaseDepthController { } /** + * Sets the lowest surface that should not be blurred. + * <p> + * Blur is applied to below {@link #mBaseSurfaceOverride}. When set to {@code null}, blur is + * applied + * to below {@link #mBaseSurface}. + * </p> + */ + public void setBaseSurfaceOverride(@Nullable SurfaceControl baseSurfaceOverride) { + this.mBaseSurfaceOverride = baseSurfaceOverride; + applyDepthAndBlur(); + } + + /** * Sets the specified app target surface to apply the blur to. */ - protected void setSurface(SurfaceControl surface) { - if (mSurface != surface || mWaitingOnSurfaceValidity) { - mSurface = surface; + protected void setBaseSurface(SurfaceControl baseSurface) { + if (mBaseSurface != baseSurface || mWaitingOnSurfaceValidity) { + mBaseSurface = baseSurface; Log.d(TAG, "setSurface:\n\tmWaitingOnSurfaceValidity: " + mWaitingOnSurfaceValidity - + "\n\tmSurface: " + mSurface); + + "\n\tmBaseSurface: " + mBaseSurface); applyDepthAndBlur(); } } diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt index 7e51fcfedc..d1d47b9fa5 100644 --- a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt +++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt @@ -114,6 +114,8 @@ private constructor( * * @param borderRadiusPx the radius of the border's corners, in pixels * @param borderWidthPx the width of the border, in pixels + * @param borderStrokePx the stroke width used to paint the border, in pixels. If smaller + * than border width, it gets drawn at the outside edge of the border. * @param boundsBuilder callback to update the border bounds * @param targetView the view that will be drawing the border * @param contentView the view around which the border will be drawn. this view will be @@ -128,6 +130,7 @@ private constructor( fun createScalingBorderAnimator( @Px borderRadiusPx: Int, @Px borderWidthPx: Int, + @Px borderStrokePx: Int, boundsBuilder: (rect: Rect?) -> Unit, targetView: View, contentView: View, @@ -139,7 +142,13 @@ private constructor( return BorderAnimator( borderRadiusPx, borderColor, - ScalingParams(borderWidthPx, boundsBuilder, targetView, contentView), + ScalingParams( + borderWidthPx, + borderStrokePx, + boundsBuilder, + targetView, + contentView, + ), appearanceDurationMs, disappearanceDurationMs, interpolator, @@ -151,7 +160,7 @@ private constructor( val interpolatedProgress = interpolator.getInterpolation(borderAnimationProgress.value) borderAnimationParams.animationProgress = interpolatedProgress borderPaint.alpha = (255 * interpolatedProgress).roundToInt() - borderPaint.strokeWidth = borderAnimationParams.borderWidth + borderPaint.strokeWidth = borderAnimationParams.borderStroke borderAnimationParams.targetView.invalidate() } @@ -170,7 +179,7 @@ private constructor( /* bottom= */ borderBounds.bottom - alignmentAdjustment, /* rx= */ radius, /* ry= */ radius, - /* paint= */ borderPaint + /* paint= */ borderPaint, ) } } @@ -212,6 +221,7 @@ private constructor( /** Params for handling different target view layout situations. */ private abstract class BorderAnimationParams( @field:Px @param:Px val borderWidthPx: Int, + @field:Px @param:Px val borderStrokePx: Int, private val boundsBuilder: (rect: Rect) -> Unit, val targetView: View, ) { @@ -222,12 +232,12 @@ private constructor( abstract val alignmentAdjustmentInset: Int abstract val radiusAdjustment: Float - val borderWidth: Float - get() = borderWidthPx * animationProgress + val borderStroke: Float + get() = borderStrokePx * animationProgress val alignmentAdjustment: Float // Outset the border by half the width to create an outwards-growth animation - get() = -borderWidth / 2f + alignmentAdjustmentInset + get() = -borderStroke / 2f + alignmentAdjustmentInset open fun onShowBorder() { if (layoutChangeListener == null) { @@ -253,7 +263,7 @@ private constructor( @Px borderWidthPx: Int, boundsBuilder: (Rect) -> Unit, targetView: View, - ) : BorderAnimationParams(borderWidthPx, boundsBuilder, targetView) { + ) : BorderAnimationParams(borderWidthPx, borderWidthPx, boundsBuilder, targetView) { override val alignmentAdjustmentInset = 0 override val radiusAdjustment: Float get() = -alignmentAdjustment @@ -265,12 +275,13 @@ private constructor( */ private class ScalingParams( @Px borderWidthPx: Int, + @Px borderStrokePx: Int, boundsBuilder: (rect: Rect?) -> Unit, targetView: View, private val contentView: View, - ) : BorderAnimationParams(borderWidthPx, boundsBuilder, targetView) { + ) : BorderAnimationParams(borderWidthPx, borderStrokePx, boundsBuilder, targetView) { // Inset the border since we are scaling the container up - override val alignmentAdjustmentInset = borderWidthPx + override val alignmentAdjustmentInset = borderStrokePx override val radiusAdjustment: Float // Increase the radius since we are scaling the container up get() = alignmentAdjustment diff --git a/quickstep/src/com/android/quickstep/util/DesksUtils.kt b/quickstep/src/com/android/quickstep/util/DesksUtils.kt index ccfdbb9f32..a10f7711fc 100644 --- a/quickstep/src/com/android/quickstep/util/DesksUtils.kt +++ b/quickstep/src/com/android/quickstep/util/DesksUtils.kt @@ -16,28 +16,37 @@ package com.android.quickstep.util -import android.content.Context +import android.app.TaskInfo +import android.content.ComponentName +import android.content.res.Resources +import android.util.Log import android.window.DesktopExperienceFlags import com.android.systemui.shared.recents.model.Task class DesksUtils { companion object { + val sysUiPackage = + Resources.getSystem().getString(com.android.internal.R.string.config_systemUi) + @JvmStatic fun areMultiDesksFlagsEnabled() = - DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue() && - DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_FRONTEND.isTrue() + DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && + DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_FRONTEND.isTrue /** Returns true if this [task] contains the [DesktopWallpaperActivity]. */ @JvmStatic - fun isDesktopWallpaperTask(context: Context, task: Task): Boolean { - val sysUiPackage = - context.getResources().getString(com.android.internal.R.string.config_systemUi) - val component = task.key.component - if (component != null) { - return component.className.contains("DesktopWallpaperActivity") && - component.packageName.contains(sysUiPackage) - } - return false + fun isDesktopWallpaperTask(task: Task) = + task.key.component?.let(::isDesktopWallpaperComponent) == true + + @JvmStatic + fun isDesktopWallpaperTask(taskInfo: TaskInfo): Boolean { + Log.d("b/403118101", "isDesktopWallpaperTask: $taskInfo") + return taskInfo.baseIntent.component?.let(::isDesktopWallpaperComponent) == true } + + @JvmStatic + fun isDesktopWallpaperComponent(component: ComponentName) = + component.className.contains("DesktopWallpaperActivity") && + component.packageName.contains(sysUiPackage) } } diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.kt b/quickstep/src/com/android/quickstep/util/DesktopTask.kt index fbe3bc64d0..7c2729346c 100644 --- a/quickstep/src/com/android/quickstep/util/DesktopTask.kt +++ b/quickstep/src/com/android/quickstep/util/DesktopTask.kt @@ -17,22 +17,27 @@ package com.android.quickstep.util import com.android.quickstep.views.TaskViewType import com.android.systemui.shared.recents.model.Task +import java.util.Objects /** * A [Task] container that can contain N number of tasks that are part of the desktop in recent - * tasks list. Note that desktops can be empty with no tasks in them. The [deskId] makes sense only - * when the multiple desks feature is enabled. + * tasks list. Note that desktops can be empty with no tasks in them. The [deskId], [displayId] + * makes sense only when the multiple desks feature is enabled. */ -class DesktopTask(val deskId: Int, tasks: List<Task>) : GroupTask(tasks, TaskViewType.DESKTOP) { +class DesktopTask(val deskId: Int, val displayId: Int, tasks: List<Task>) : + GroupTask(tasks, TaskViewType.DESKTOP) { - override fun copy() = DesktopTask(deskId, tasks) + override fun copy() = DesktopTask(deskId, displayId, tasks) - override fun toString() = "type=$taskViewType deskId=$deskId tasks=$tasks" + override fun toString() = "type=$taskViewType deskId=$deskId displayId=$displayId tasks=$tasks" override fun equals(o: Any?): Boolean { if (this === o) return true if (o !is DesktopTask) return false if (deskId != o.deskId) return false + if (displayId != o.displayId) return false return super.equals(o) } + + override fun hashCode() = Objects.hash(super.hashCode(), deskId, displayId) } diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.kt b/quickstep/src/com/android/quickstep/util/GroupTask.kt index add8821b06..2b754e2e0d 100644 --- a/quickstep/src/com/android/quickstep/util/GroupTask.kt +++ b/quickstep/src/com/android/quickstep/util/GroupTask.kt @@ -86,6 +86,8 @@ class SingleTask(task: Task) : GroupTask(listOf(task), TaskViewType.SINGLE) { return TaskItemInfo(task.task.key.id, wii) } } + + override fun hashCode() = super.hashCode() } /** diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java index 843619de78..9aded898dc 100644 --- a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java +++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java @@ -35,8 +35,8 @@ public class InputProxyHandlerFactory implements Supplier<InputConsumer> { private final GestureState mGestureState; @UiThread - public InputProxyHandlerFactory(BaseContainerInterface activityInterface, - GestureState gestureState) { + public InputProxyHandlerFactory( + BaseContainerInterface activityInterface, GestureState gestureState) { mContainerInterface = activityInterface; mGestureState = gestureState; } @@ -47,7 +47,8 @@ public class InputProxyHandlerFactory implements Supplier<InputConsumer> { @Override public InputConsumer get() { RecentsViewContainer container = mContainerInterface.getCreatedContainer(); - return container == null ? InputConsumer.NO_OP + return container == null + ? InputConsumer.createNoOpInputConsumer(mGestureState.getDisplayId()) : new OverviewInputConsumer(mGestureState, container, null, true); } } diff --git a/quickstep/src/com/android/quickstep/views/BlurUtils.kt b/quickstep/src/com/android/quickstep/views/BlurUtils.kt new file mode 100644 index 0000000000..d6b2a055b7 --- /dev/null +++ b/quickstep/src/com/android/quickstep/views/BlurUtils.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.quickstep.views + +import com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur +import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle + +/** Applies blur either behind launcher surface or live tile app. */ +class BlurUtils(private val recentsView: RecentsView<*, *>) { + + fun setDrawLiveTileBelowRecents(drawBelowRecents: Boolean) { + val liveTileRemoteTargetHandles = + if ( + recentsView.remoteTargetHandles != null && + recentsView.recentsAnimationController != null + ) + recentsView.remoteTargetHandles + else null + setDrawBelowRecents(drawBelowRecents, liveTileRemoteTargetHandles) + } + + /** + * Set surface in [remoteTargetHandles] to be above or below Recents layer, and update the base + * layer to apply blur to in BaseDepthController. + */ + fun setDrawBelowRecents( + drawBelowRecents: Boolean, + remoteTargetHandles: Array<RemoteTargetHandle>? = null, + ) { + remoteTargetHandles?.forEach { it.taskViewSimulator.setDrawsBelowRecents(drawBelowRecents) } + if (enableOverviewBackgroundWallpaperBlur()) { + recentsView.depthController?.setBaseSurfaceOverride( + // Blurs behind launcher layer. + if (!drawBelowRecents || remoteTargetHandles == null) { + null + } else { + // Blurs behind live tile. blur will be applied behind window + // which farthest from user in case of desktop and split apps. + remoteTargetHandles + .maxByOrNull { it.transformParams.targetSet.firstAppTarget.leash.layerId } + ?.transformParams + ?.targetSet + ?.firstAppTarget + ?.leash + } + ) + } + } +} diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 27657b4c0f..8876633bd3 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -25,6 +25,7 @@ import android.graphics.RectF import android.util.AttributeSet import android.util.Log import android.util.Size +import android.view.Display.INVALID_DISPLAY import android.view.Gravity import android.view.View import android.view.ViewStub @@ -59,6 +60,7 @@ import com.android.quickstep.task.thumbnail.TaskContentView import com.android.quickstep.task.thumbnail.TaskThumbnailView import com.android.quickstep.util.DesktopTask import com.android.quickstep.util.RecentsOrientedState +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.enableMultipleDesktops import kotlin.math.roundToInt /** TaskView that contains all tasks that are part of the desktop. */ @@ -69,7 +71,10 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu type = TaskViewType.DESKTOP, thumbnailFullscreenParams = DesktopFullscreenDrawParams(context), ) { - var deskId = DesktopVisibilityController.INACTIVE_DESK_ID + val deskId + get() = desktopTask?.deskId ?: DesktopVisibilityController.INACTIVE_DESK_ID + + private var desktopTask: DesktopTask? = null private val contentViewFullscreenParams = FullscreenDrawParams(context) @@ -112,6 +117,14 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu positionTaskWindows() } + override val displayId: Int + get() = + if (enableMultipleDesktops(context)) { + desktopTask?.displayId ?: INVALID_DISPLAY + } else { + super.displayId + } + private fun getRemoteTargetHandle(taskId: Int): RemoteTargetHandle? = remoteTargetHandles?.firstOrNull { it.transformParams.targetSet.firstAppTargetTaskId == taskId @@ -284,7 +297,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu orientedState: RecentsOrientedState, taskOverlayFactory: TaskOverlayFactory, ) { - deskId = desktopTask.deskId + this.desktopTask = desktopTask // TODO(b/370495260): Minimized tasks should not be filtered with desktop exploded view // support. // Minimized tasks should not be shown in Overview. @@ -336,7 +349,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu override fun onRecycle() { super.onRecycle() - deskId = DesktopVisibilityController.INACTIVE_DESK_ID + desktopTask = null explodeProgress = 0.0f viewModel = null visibility = VISIBLE diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt index 71a4dde395..10a2e902cb 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt @@ -182,7 +182,6 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val splitBoundsConfig = splitBoundsConfig ?: return val deviceProfile = container.deviceProfile val taskIconHeight = deviceProfile.overviewTaskIconSizePx - val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID var oneIconHiddenDueToSmallWidth = false @@ -211,6 +210,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } if (enableOverviewIconMenu()) { + val isDeviceRtl = Utilities.isRtl(resources) val groupedTaskViewSizes = pagedOrientationHandler.getGroupedTaskViewSizes( deviceProfile, @@ -226,7 +226,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu groupedTaskViewSizes.first.y, layoutParams.height, layoutParams.width, - isRtl, + isDeviceRtl, deviceProfile, splitBoundsConfig, inSplitSelection, @@ -241,7 +241,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu leftTopTaskContainer.taskContentView.measuredHeight, measuredHeight, measuredWidth, - isRtl, + isLayoutRtl, deviceProfile, splitBoundsConfig, inSplitSelection, diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.kt b/quickstep/src/com/android/quickstep/views/IconAppChipView.kt index c20aa11599..7683a1500a 100644 --- a/quickstep/src/com/android/quickstep/views/IconAppChipView.kt +++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.kt @@ -122,6 +122,9 @@ constructor( field = max(value, minMaxWidth) } + var isExpanded: Boolean = false + private set + override fun onFinishInflate() { super.onFinishInflate() iconView = findViewById(R.id.icon_view) @@ -356,6 +359,7 @@ constructor( ObjectAnimator.ofFloat(iconArrowView, SCALE_Y, -1f), ) animator!!.setDuration(MENU_BACKGROUND_REVEAL_DURATION.toLong()) + isExpanded = true } else { // Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu val expandedTextClipAnim = @@ -390,6 +394,7 @@ constructor( ObjectAnimator.ofFloat(iconArrowView, SCALE_Y, 1f), ) animator!!.setDuration(MENU_BACKGROUND_HIDE_DURATION.toLong()) + isExpanded = false } if (!animated) animator!!.duration = 0 @@ -416,6 +421,17 @@ constructor( } } + override fun focusSearch(direction: Int): View? { + if (mParent == null) return null + return when (direction) { + FOCUS_RIGHT, + FOCUS_DOWN -> mParent.focusSearch(this, View.FOCUS_FORWARD) + FOCUS_UP, + FOCUS_LEFT -> mParent.focusSearch(this, View.FOCUS_BACKWARD) + else -> super.focusSearch(direction) + } + } + override fun asView(): View = this private companion object { diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 0f1c2941b3..74de2aca7b 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -19,6 +19,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY; import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON; +import static com.android.launcher3.LauncherState.ADD_DESK_BUTTON; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; @@ -184,10 +185,8 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher if (finalState.isRecentsViewVisible && finalState != OVERVIEW_MODAL_TASK) { setTaskBorderEnabled(true); } - if (isOverlayEnabled) { - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)); + mBlurUtils.setDrawLiveTileBelowRecents(true); } } @@ -198,7 +197,10 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher LauncherState state = getStateManager().getState(); boolean hasClearAllButton = (state.getVisibleElements(mContainer) & CLEAR_ALL_BUTTON) != 0; + boolean hasAddDeskButton = (state.getVisibleElements(mContainer) + & ADD_DESK_BUTTON) != 0; setDisallowScrollToClearAll(!hasClearAllButton); + setDisallowScrollToAddDesk(!hasAddDeskButton); } } @@ -276,7 +278,7 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher GestureState.GestureEndTarget endTarget = mCurrentGestureEndTarget; if (endTarget == GestureState.GestureEndTarget.LAST_TASK && desktopVisibilityController.isInDesktopModeAndNotInOverview( - mContainer.getDisplayId())) { + mContainer.getDisplayId())) { // Recents gesture was cancelled and we are returning to the previous task. // After super class has handled clean up, show desktop apps on top again showDesktopApps = true; diff --git a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt index 4ce18f50a1..d39b52848c 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt @@ -96,64 +96,87 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { onEndRunnable() } if (!isDismissing) { - addNeighboringSpringAnimationsForDismissCancel( + addNeighborSettlingSpringAnimations( draggedTaskView, draggedTaskViewSpringAnimation, + driverProgressThreshold = 0f, + isSpringDirectionVertical = true, ) } return draggedTaskViewSpringAnimation } - private fun addNeighboringSpringAnimationsForDismissCancel( + private fun addNeighborSettlingSpringAnimations( draggedTaskView: TaskView, - draggedTaskViewSpringAnimation: SpringAnimation, + springAnimationDriver: SpringAnimation, + tasksToExclude: List<TaskView> = emptyList(), + driverProgressThreshold: Float, + isSpringDirectionVertical: Boolean, ) { // Empty spring animation exists for conditional start, and to drive neighboring springs. val neighborsToSettle = SpringAnimation(FloatValueHolder()).setSpring(createExpressiveDismissSpringForce()) + addThresholdSpringAnimationTrigger( + springAnimationDriver, + progressThreshold = driverProgressThreshold, + neighborsToSettle, + ) + + // Add tasks before dragged index, fanning out from the dragged task. + // The order they are added matters, as each spring drives the next. + var previousNeighbor = neighborsToSettle + getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = true) + .filter { (taskView, _) -> !tasksToExclude.contains(taskView) } + .forEach { (taskView, offset) -> + previousNeighbor = + createNeighboringTaskViewSpringAnimation( + taskView, + offset * ADDITIONAL_DISMISS_DAMPING_RATIO, + previousNeighbor, + isSpringDirectionVertical, + ) + } + // Add tasks after dragged index, fanning out from the dragged task. + // The order they are added matters, as each spring drives the next. + previousNeighbor = neighborsToSettle + getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = false) + .filter { (taskView, _) -> !tasksToExclude.contains(taskView) } + .forEach { (taskView, offset) -> + previousNeighbor = + createNeighboringTaskViewSpringAnimation( + taskView, + offset * ADDITIONAL_DISMISS_DAMPING_RATIO, + previousNeighbor, + isSpringDirectionVertical, + ) + } + } + + /** As spring passes threshold for the first time, run conditional spring with velocity. */ + private fun addThresholdSpringAnimationTrigger( + springAnimationDriver: SpringAnimation, + progressThreshold: Float, + conditionalSpring: SpringAnimation, + ) { var lastPosition = 0f var startSettling = false - draggedTaskViewSpringAnimation.addUpdateListener { _, value, velocity -> - // Start the settling animation the first time the dragged task passes the origin (from - // negative displacement to positive displacement). We do not check for an exact value - // to compare to, as the update listener does not necessarily hit every value (e.g. a - // value of zero). Do not check again once it has started settling, as a spring can - // bounce past the origin multiple times depending on the stiffness and damping ratio. + springAnimationDriver.addUpdateListener { _, value, velocity -> + // We do not compare to the threshold directly, as the update listener + // does not necessarily hit every value. Do not check again once it has started + // settling, as a spring can bounce past the end value multiple times. if (startSettling) return@addUpdateListener - if (lastPosition < 0 && value >= 0) { + if ( + lastPosition < progressThreshold && value >= progressThreshold || + lastPosition > progressThreshold && value <= progressThreshold + ) { startSettling = true } lastPosition = value if (startSettling) { - neighborsToSettle.setStartVelocity(velocity).animateToFinalPosition(0f) + conditionalSpring.setStartVelocity(velocity).animateToFinalPosition(0f) playDismissSettlingHaptic(velocity) } } - - // Add tasks before dragged index, fanning out from the dragged task. - // The order they are added matters, as each spring drives the next. - var previousNeighbor = neighborsToSettle - getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = true).forEach { - (taskView, offset) -> - previousNeighbor = - createNeighboringTaskViewSpringAnimation( - taskView, - offset * ADDITIONAL_DISMISS_DAMPING_RATIO, - previousNeighbor, - ) - } - // Add tasks after dragged index, fanning out from the dragged task. - // The order they are added matters, as each spring drives the next. - previousNeighbor = neighborsToSettle - getTasksOffsetPairAdjacentToDraggedTask(draggedTaskView, towardsStart = false).forEach { - (taskView, offset) -> - previousNeighbor = - createNeighboringTaskViewSpringAnimation( - taskView, - offset * ADDITIONAL_DISMISS_DAMPING_RATIO, - previousNeighbor, - ) - } } /** @@ -208,21 +231,25 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { taskView: TaskView, dampingOffsetRatio: Float, previousNeighborSpringAnimation: SpringAnimation, + springingDirectionVertical: Boolean, ): SpringAnimation { + val springProperty = + if (springingDirectionVertical) taskView.secondaryDismissTranslationProperty + else taskView.primaryDismissTranslationProperty val neighboringTaskViewSpringAnimation = - SpringAnimation( - taskView, - FloatPropertyCompat.createFloatPropertyCompat( - taskView.secondaryDismissTranslationProperty - ), - ) + SpringAnimation(taskView, FloatPropertyCompat.createFloatPropertyCompat(springProperty)) .setSpring(createExpressiveDismissSpringForce(dampingOffsetRatio)) // Update live tile on spring animation. if (taskView.isRunningTask && recentsView.enableDrawingLiveTile) { neighboringTaskViewSpringAnimation.addUpdateListener { _, _, _ -> recentsView.runActionOnRemoteHandles { remoteTargetHandle -> - remoteTargetHandle.taskViewSimulator.taskSecondaryTranslation.value = - taskView.secondaryDismissTranslationProperty.get(taskView) + val taskTranslation = + if (springingDirectionVertical) { + remoteTargetHandle.taskViewSimulator.taskSecondaryTranslation + } else { + remoteTargetHandle.taskViewSimulator.taskPrimaryTranslation + } + taskTranslation.value = springProperty.get(taskView) } recentsView.redrawLiveTile() } @@ -271,7 +298,7 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { .playToken( MSDLToken.CANCEL, InteractionProperties.DynamicVibrationScale( - boundToRange(velocity / maxDismissSettlingVelocity, 0f, 1f), + boundToRange(abs(velocity) / maxDismissSettlingVelocity, 0f, 1f), VibrationAttributes.Builder() .setUsage(VibrationAttributes.USAGE_TOUCH) .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT) @@ -319,32 +346,39 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { .setSpring(createExpressiveGridReflowSpringForce(finalPosition = dismissedTaskGap)) val towardsStart = if (recentsView.isRtl) dismissedTaskGap < 0 else dismissedTaskGap > 0 + var tasksToReflow: List<TaskView> // Build the chains of Spring Animations when { !recentsView.showAsGrid() -> { - buildDismissReflowSpringAnimationChain( + tasksToReflow = getTasksToReflow( recentsView.mUtils.taskViews.toList(), dismissedTaskView, towardsStart, - ), + ) + buildDismissReflowSpringAnimationChain( + tasksToReflow, dismissedTaskGap, previousSpring = springAnimationDriver, ) } dismissedTaskView.isLargeTile -> { + tasksToReflow = + getTasksToReflow( + recentsView.mUtils.getLargeTaskViews(), + dismissedTaskView, + towardsStart, + ) val lastSpringAnimation = buildDismissReflowSpringAnimationChain( - getTasksToReflow( - recentsView.mUtils.getLargeTaskViews(), - dismissedTaskView, - towardsStart, - ), + tasksToReflow, dismissedTaskGap, previousSpring = springAnimationDriver, ) // Add all top and bottom grid tasks when animating towards the end of the grid. if (!towardsStart) { + tasksToReflow += recentsView.mUtils.getTopRowTaskViews() + tasksToReflow += recentsView.mUtils.getBottomRowTaskViews() buildDismissReflowSpringAnimationChain( recentsView.mUtils.getTopRowTaskViews(), dismissedTaskGap, @@ -358,29 +392,43 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { } } recentsView.isOnGridBottomRow(dismissedTaskView) -> { - buildDismissReflowSpringAnimationChain( + tasksToReflow = getTasksToReflow( recentsView.mUtils.getBottomRowTaskViews(), dismissedTaskView, towardsStart, - ), + ) + buildDismissReflowSpringAnimationChain( + tasksToReflow, dismissedTaskGap, previousSpring = springAnimationDriver, ) } else -> { - buildDismissReflowSpringAnimationChain( + tasksToReflow = getTasksToReflow( recentsView.mUtils.getTopRowTaskViews(), dismissedTaskView, towardsStart, - ), + ) + buildDismissReflowSpringAnimationChain( + tasksToReflow, dismissedTaskGap, previousSpring = springAnimationDriver, ) } } + if (tasksToReflow.isNotEmpty()) { + addNeighborSettlingSpringAnimations( + dismissedTaskView, + springAnimationDriver, + tasksToExclude = tasksToReflow, + driverProgressThreshold = dismissedTaskGap, + isSpringDirectionVertical = false, + ) + } + // Start animations and remove the dismissed task at the end, dismiss immediately if no // neighboring tasks exist. val runGridEndAnimationAndRelayout = { @@ -429,8 +477,8 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { else -> 1f } * (if (recentsView.isRtl) 1f else -1f) - return (dismissedTaskView.layoutParams.width + recentsView.pageSpacing) * - dismissHorizontalFactor + return (recentsView.pagedOrientationHandler.getPrimarySize(dismissedTaskView) + + recentsView.pageSpacing) * dismissHorizontalFactor } private fun getTasksToReflow( diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index bb2aa758eb..8c7fe26f3c 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -17,6 +17,8 @@ package com.android.quickstep.views; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.os.Trace.traceBegin; +import static android.os.Trace.traceEnd; import static android.view.Surface.ROTATION_0; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.makeMeasureSpec; @@ -32,14 +34,13 @@ import static com.android.app.animation.Interpolators.FINAL_FRAME; import static com.android.app.animation.Interpolators.LINEAR; import static com.android.app.animation.Interpolators.clampToProgress; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; -import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU; -import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.Flags.enableAdditionalHomeAnimations; import static com.android.launcher3.Flags.enableDesktopExplodedView; import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation; import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile; +import static com.android.launcher3.Flags.enableOverviewBackgroundWallpaperBlur; import static com.android.launcher3.Flags.enableRefactorTaskThumbnail; import static com.android.launcher3.Flags.enableSeparateExternalDisplayTasks; import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS; @@ -56,6 +57,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; +import static com.android.launcher3.statehandlers.DesktopVisibilityController.INACTIVE_DESK_ID; import static com.android.launcher3.testing.shared.TestProtocol.DISMISS_ANIMATION_ENDS_MESSAGE; import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -64,6 +66,7 @@ import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VAL import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; import static com.android.quickstep.BaseContainerInterface.getTaskDimension; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; +import static com.android.quickstep.util.DesksUtils.areMultiDesksFlagsEnabled; import static com.android.quickstep.util.LogUtils.splitFailureMessage; import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU; @@ -102,6 +105,7 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.os.VibrationEffect; import android.text.Layout; @@ -212,7 +216,6 @@ import com.android.quickstep.recents.viewmodel.RecentsViewData; import com.android.quickstep.recents.viewmodel.RecentsViewModel; import com.android.quickstep.util.ActiveGestureProtoLogProxy; import com.android.quickstep.util.AnimUtils; -import com.android.quickstep.util.DesksUtils; import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.LayoutUtils; @@ -584,6 +587,8 @@ public abstract class RecentsView< private final TaskOverlayFactory mTaskOverlayFactory; protected boolean mDisallowScrollToClearAll; + // True if it is not allowed to scroll to [AddDesktopButton]. + protected boolean mDisallowScrollToAddDesk; private boolean mOverlayEnabled; protected boolean mFreezeViewVisibility; private boolean mOverviewGridEnabled; @@ -827,7 +832,7 @@ public abstract class RecentsView< mOrientationState.setMultiWindowMode(inMultiWindowMode); setLayoutRotation(mOrientationState.getTouchRotation(), mOrientationState.getDisplayRotation()); - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); if (!inMultiWindowMode && mOverviewStateEnabled) { // TODO: Re-enable layout transitions for addition of the unpinned task reloadIfNeeded(); @@ -863,6 +868,9 @@ public abstract class RecentsView< private final Matrix mTmpMatrix = new Matrix(); private int mTaskViewCount = 0; + + protected final BlurUtils mBlurUtils = new BlurUtils(this); + @Nullable public TaskView getFirstTaskView() { return mUtils.getFirstTaskView(); @@ -1291,6 +1299,7 @@ public abstract class RecentsView< @Override public void onViewRemoved(View child) { + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewRemoved"); super.onViewRemoved(child); // Clear the task data for the removed child if it was visible unless: // - It's the initial taskview for entering split screen, we only pretend to dismiss the @@ -1302,6 +1311,7 @@ public abstract class RecentsView< clearAndRecycleTaskView((TaskView) child); } } + traceEnd(Trace.TRACE_TAG_APP); } private void clearAndRecycleTaskView(TaskView taskView) { @@ -1320,6 +1330,7 @@ public abstract class RecentsView< @Override public void onViewAdded(View child) { + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewAdded"); super.onViewAdded(child); if (child instanceof TaskView) { mTaskViewCount++; @@ -1330,6 +1341,7 @@ public abstract class RecentsView< child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL); mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false); updateEmptyMessage(); + traceEnd(Trace.TRACE_TAG_APP); } @Override @@ -1926,14 +1938,19 @@ public abstract class RecentsView< return; } - // TODO: b/400532675 - The use of `currentTaskIds`, `runningTaskIds`, and `focusedTaskIds` - // needs to be audited so that they can work with empty desks that have no tasks. - int[] currentTaskIds; + // Start here to avoid early returns and empty cases which have special logic + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan"); + TaskView currentTaskView = getTaskViewAt(mCurrentPage); - if (currentTaskView != null) { + int[] currentTaskIds = null; + // Track the current DesktopTaskView through [deskId] as a desk can be empty without any + // tasks. + int currentTaskViewDeskId = INACTIVE_DESK_ID; + if (areMultiDesksFlagsEnabled() + && currentTaskView instanceof DesktopTaskView desktopTaskView) { + currentTaskViewDeskId = desktopTaskView.getDeskId(); + } else if (currentTaskView != null) { currentTaskIds = currentTaskView.getTaskIds(); - } else { - currentTaskIds = new int[0]; } // Unload existing visible task data @@ -1945,9 +1962,19 @@ public abstract class RecentsView< // Save running task ID if it exists before rebinding all taskViews, otherwise the task from // the runningTaskView currently bound could get assigned to another TaskView - int[] runningTaskIds = getTaskIdsForTaskViewId(mRunningTaskViewId); - int[] focusedTaskIds = getTaskIdsForTaskViewId(mFocusedTaskViewId); + TaskView runningTaskView = getRunningTaskView(); + int[] runningTaskIds = null; + // Track the running TaskView through [deskId] as a desk can be empty without any tasks. + int runningTaskViewDeskId = INACTIVE_DESK_ID; + if (areMultiDesksFlagsEnabled() + && runningTaskView instanceof DesktopTaskView desktopTaskView) { + runningTaskViewDeskId = desktopTaskView.getDeskId(); + } else if (runningTaskView != null) { + runningTaskIds = runningTaskView.getTaskIds(); + } + + int[] focusedTaskIds = getTaskIdsForTaskViewId(mFocusedTaskViewId); // Reset the focused task to avoiding initializing TaskViews layout as focused task during // binding. The focused task view will be updated after all the TaskViews are bound. setFocusedTaskViewId(INVALID_TASK_ID); @@ -1959,8 +1986,9 @@ public abstract class RecentsView< // TaskIds will no longer be valid after remove and re-add, clearing mTopRowIdSet. mAnyTaskHasBeenDismissed = false; mTopRowIdSet.clear(); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.removeAllViews"); removeAllViews(); - + traceEnd(Trace.TRACE_TAG_APP); // If we are entering Overview as a result of initiating a split from somewhere else // (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail. int stagedTaskIdToBeRemoved; @@ -1987,6 +2015,7 @@ public abstract class RecentsView< // Add `mAddDesktopButton` as the first child. addView(mAddDesktopButton); } + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop"); // Add views as children based on whether it's grouped or single task. Looping through // taskGroups backwards populates the thumbnail grid from least recent to most recent. @@ -2006,8 +2035,11 @@ public abstract class RecentsView< // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE // to be a temporary container for the remaining task. + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.createTaskView"); TaskView taskView = getTaskViewFromPool( containsStagedTask ? TaskViewType.SINGLE : groupTask.taskViewType); + traceEnd(Trace.TRACE_TAG_APP); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.bind"); if (taskView instanceof GroupedTaskView groupedTaskView) { var splitTask = (SplitTask) groupTask; groupedTaskView.bind(splitTask.getTopLeftTask(), @@ -2025,13 +2057,18 @@ public abstract class RecentsView< taskView.bind(((SingleTask) groupTask).getTask(), mOrientationState, mTaskOverlayFactory); } + traceEnd(Trace.TRACE_TAG_APP); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.addTaskView"); addView(taskView); + traceEnd(Trace.TRACE_TAG_APP); // enables instance filtering if the feature flag for it is on if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) { taskView.setUpShowAllInstancesListener(); } } + // For loop end trace + traceEnd(Trace.TRACE_TAG_APP); addView(mClearAllButton); @@ -2051,27 +2088,29 @@ public abstract class RecentsView< setFocusedTaskViewId( newFocusedTaskView != null ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.layouts"); updateTaskSize(); - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); + traceEnd(Trace.TRACE_TAG_APP); - TaskView newRunningTaskView = null; - if (hasAllValidTaskIds(runningTaskIds)) { + TaskView newRunningTaskView = mUtils.getDesktopTaskViewForDeskId(runningTaskViewDeskId); + if (newRunningTaskView == null) { // Update mRunningTaskViewId to be the new TaskView that was assigned by binding // the full list of tasks to taskViews newRunningTaskView = getTaskViewByTaskIds(runningTaskIds); - if (newRunningTaskView != null) { - setRunningTaskViewId(newRunningTaskView.getTaskViewId()); + } + if (newRunningTaskView != null) { + setRunningTaskViewId(newRunningTaskView.getTaskViewId()); + } else { + if (mActiveGestureRunningTasks != null) { + // This will update mRunningTaskViewId and create a stub view if necessary. + // We try to avoid this because it can cause a scroll jump, but it is needed + // for cases where the running task isn't included in this load plan (e.g. if + // the current running task is excludedFromRecents.) + showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan"); + newRunningTaskView = getRunningTaskView(); } else { - if (mActiveGestureRunningTasks != null) { - // This will update mRunningTaskViewId and create a stub view if necessary. - // We try to avoid this because it can cause a scroll jump, but it is needed - // for cases where the running task isn't included in this load plan (e.g. if - // the current running task is excludedFromRecents.) - showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan"); - newRunningTaskView = getRunningTaskView(); - } else { - setRunningTaskViewId(INVALID_TASK_ID); - } + setRunningTaskViewId(INVALID_TASK_ID); } } @@ -2079,11 +2118,12 @@ public abstract class RecentsView< if (mNextPage != INVALID_PAGE) { // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll. mCurrentPage = previousCurrentPage; - if (hasAllValidTaskIds(currentTaskIds)) { + currentTaskView = mUtils.getDesktopTaskViewForDeskId(currentTaskViewDeskId); + if (currentTaskView == null) { currentTaskView = getTaskViewByTaskIds(currentTaskIds); - if (currentTaskView != null) { - targetPage = indexOfChild(currentTaskView); - } + } + if (currentTaskView != null) { + targetPage = indexOfChild(currentTaskView); } } else if (previousFocusedPage != INVALID_PAGE) { targetPage = previousFocusedPage; @@ -2106,6 +2146,7 @@ public abstract class RecentsView< }); } + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.cleanupStates"); if (mIgnoreResetTaskId != INVALID_TASK_ID && getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) { // If the taskView mapping is changing, do not preserve the visuals. Since we are @@ -2120,6 +2161,10 @@ public abstract class RecentsView< if (isPageScrollsInitialized()) { onPageScrollsInitialized(); } + traceEnd(Trace.TRACE_TAG_APP); + + // applyLoadPlan end trace + traceEnd(Trace.TRACE_TAG_APP); } private boolean isModal() { @@ -2297,7 +2342,7 @@ public abstract class RecentsView< updateSizeAndPadding(); // Update TaskView's DeviceProfile dependent layout. - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); requestLayout(); // Reapply the current page to update page scrolls. @@ -2705,9 +2750,7 @@ public abstract class RecentsView< } setEnableDrawingLiveTile(false); } - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false)); - + mBlurUtils.setDrawLiveTileBelowRecents(false); // These are relatively expensive and don't need to be done this frame (RecentsView isn't // visible anyway), so defer by a frame to get off the critical path, e.g. app to home. post(this::onReset); @@ -2907,22 +2950,6 @@ public abstract class RecentsView< return as; } - private void updateChildTaskOrientations() { - for (TaskView taskView : getTaskViews()) { - taskView.setOrientationState(mOrientationState); - } - boolean shouldRotateMenuForFakeRotation = - !mOrientationState.isRecentsActivityRotationAllowed(); - if (!shouldRotateMenuForFakeRotation) { - return; - } - AbstractFloatingView floatingView = getTopOpenViewWithType(mContainer, TYPE_TASK_MENU); - if (floatingView instanceof TaskMenuView taskMenuView) { - // Rotation is supported on phone (details at b/254198019#comment4) - taskMenuView.onRotationChanged(); - } - } - /** * Called when a gesture from an app has finished, and an end target has been determined. */ @@ -3079,7 +3106,8 @@ public abstract class RecentsView< // TODO: b/401582344 - Implement a way to exclude the `DesktopWallpaperActivity`. desktopTaskView.bind( - new DesktopTask(activeDeskId, Arrays.asList(runningTasks)), + new DesktopTask(activeDeskId, mContainer.getDisplayId(), + Arrays.asList(runningTasks)), mOrientationState, mTaskOverlayFactory); return desktopTaskView; } @@ -3159,7 +3187,7 @@ public abstract class RecentsView< setRunningTaskHidden(runningTaskTileHidden); // Update task size after setting current task. updateTaskSize(); - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); // Reload the task list reloadIfNeeded(); @@ -4312,7 +4340,7 @@ public abstract class RecentsView< finalNextFocusedTaskView.getDismissIconFadeInAnimator().start(); } updateTaskSize(); - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); // Update scroll and snap to page. updateScrollSynchronously(); @@ -4565,7 +4593,7 @@ public abstract class RecentsView< } private void removeDesktopTaskView(DesktopTaskView desktopTaskView) { - if (DesksUtils.areMultiDesksFlagsEnabled()) { + if (areMultiDesksFlagsEnabled()) { SystemUiProxy.INSTANCE .get(getContext()) .removeDesk(desktopTaskView.getDeskId()); @@ -4738,6 +4766,11 @@ public abstract class RecentsView< if (isHandlingTouch() || event.getAction() != KeyEvent.ACTION_DOWN) { return super.dispatchKeyEvent(event); } + + if (mUtils.shouldInterceptKeyEvent(event)) { + return super.dispatchKeyEvent(event); + } + switch (event.getKeyCode()) { case KeyEvent.KEYCODE_TAB: return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */, @@ -5772,12 +5805,10 @@ public abstract class RecentsView< // above RecentsView to avoid wallpaper blur from being applied to it. if (!taskView.isRunningTask()) { runActionOnRemoteHandles( - remoteTargetHandle -> { - remoteTargetHandle.getTaskViewSimulator().setPivotOverride( - mTempPointF); - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents( - false); - }); + remoteTargetHandle -> + remoteTargetHandle.getTaskViewSimulator() + .setPivotOverride(mTempPointF)); + mBlurUtils.setDrawLiveTileBelowRecents(false); } } @@ -5912,8 +5943,7 @@ public abstract class RecentsView< mPendingAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false)); + mBlurUtils.setDrawLiveTileBelowRecents(false); } }); mPendingAnimation.addEndListener(isSuccess -> { @@ -5951,8 +5981,7 @@ public abstract class RecentsView< // If launch animation didn't complete i.e. user dragged live tile down and then // back up and returned to Overview, then we need to ensure we reset the // view to draw below recents so that it can't be interacted with. - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)); + mBlurUtils.setDrawLiveTileBelowRecents(true); redrawLiveTile(); } return Unit.INSTANCE; @@ -6031,6 +6060,7 @@ public abstract class RecentsView< }); } + @Nullable public RemoteTargetHandle[] getRemoteTargetHandles() { return mRemoteTargetHandles; } @@ -6184,6 +6214,9 @@ public abstract class RecentsView< mRecentsAnimationController = null; mSplitSelectStateController.setRecentsAnimationRunning(false); executeSideTaskLaunchCallback(); + if (enableOverviewBackgroundWallpaperBlur()) { + mBlurUtils.setDrawLiveTileBelowRecents(false); + } } public void setDisallowScrollToClearAll(boolean disallowScrollToClearAll) { @@ -6192,6 +6225,17 @@ public abstract class RecentsView< updateMinAndMaxScrollX(); } } + /** + * Update the value of [mDisallowScrollToAddDesk] + */ + public void setDisallowScrollToAddDesk(boolean disallowScrollToAddDesk) { + if (mDisallowScrollToAddDesk != disallowScrollToAddDesk) { + mDisallowScrollToAddDesk = disallowScrollToAddDesk; + updateMinAndMaxScrollX(); + } + } + + /** * Updates page scroll synchronously after measure and layout child views. @@ -6337,7 +6381,20 @@ public abstract class RecentsView< if (addDesktopButtonIndex >= 0 && addDesktopButtonIndex < outPageScrolls.length) { int firstViewIndex = getFirstViewIndex(); if (firstViewIndex >= 0 && firstViewIndex < outPageScrolls.length) { - outPageScrolls[addDesktopButtonIndex] = outPageScrolls[firstViewIndex]; + // If we can scroll to [AddDesktopButton], make its page scroll equal to + // the first [TaskView]. Otherwise, make its page scroll out of range of + // [minScroll, maxScroll]. + if (!mDisallowScrollToAddDesk) { + outPageScrolls[addDesktopButtonIndex] = outPageScrolls[firstViewIndex]; + } else { + outPageScrolls[addDesktopButtonIndex] = + outPageScrolls[firstViewIndex] + (mIsRtl ? 1 : -1); + } + } + + if (DEBUG) { + Log.d(TAG, "getPageScrolls - addDesktopButtonScroll: " + + outPageScrolls[addDesktopButtonIndex]); } } if (DEBUG) { @@ -6979,7 +7036,7 @@ public abstract class RecentsView< // `AddNewDesktopButton`. DesktopTaskView desktopTaskView = (DesktopTaskView) getTaskViewFromPool(TaskViewType.DESKTOP); - desktopTaskView.bind(new DesktopTask(deskId, new ArrayList<>()), + desktopTaskView.bind(new DesktopTask(deskId, displayId, new ArrayList<>()), mOrientationState, mTaskOverlayFactory); Objects.requireNonNull(mAddDesktopButton); @@ -6987,7 +7044,7 @@ public abstract class RecentsView< addView(desktopTaskView, insertionIndex); updateTaskSize(); - updateChildTaskOrientations(); + mUtils.updateChildTaskOrientations(); // TODO: b/401002178 - Recalculate the new current page such that the addition of the new // desk does not result in a change in the current scroll page. @@ -7139,4 +7196,15 @@ public abstract class RecentsView< public interface TaskLaunchListener { void onTaskLaunched(); } + + /** + * Sets whether the remote animation targets should draw below the recents view. + * + * @param drawBelowRecents whether the surface should draw below Recents. + * @param remoteTargetHandles collection of remoteTargetHandles in Recents. + */ + public void setDrawBelowRecents(boolean drawBelowRecents, + RemoteTargetHandle[] remoteTargetHandles) { + mBlurUtils.setDrawBelowRecents(drawBelowRecents, remoteTargetHandles); + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt index 037bef6848..9c35913841 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt @@ -18,14 +18,20 @@ package com.android.quickstep.views import android.graphics.Rect import android.util.FloatProperty +import android.view.KeyEvent import android.view.View +import android.view.View.LAYOUT_DIRECTION_LTR +import android.view.View.LAYOUT_DIRECTION_RTL import androidx.core.view.children +import com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU +import com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType import com.android.launcher3.Flags.enableLargeDesktopWindowingTile +import com.android.launcher3.Flags.enableOverviewIconMenu import com.android.launcher3.Flags.enableSeparateExternalDisplayTasks import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.statehandlers.DesktopVisibilityController.Companion.INACTIVE_DESK_ID import com.android.launcher3.util.IntArray -import com.android.quickstep.util.DesksUtils +import com.android.quickstep.util.DesksUtils.Companion.areMultiDesksFlagsEnabled import com.android.quickstep.util.DesktopTask import com.android.quickstep.util.GroupTask import com.android.quickstep.util.isExternalDisplay @@ -57,7 +63,7 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { */ fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> { var (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP } - if (DesksUtils.areMultiDesksFlagsEnabled()) { + if (areMultiDesksFlagsEnabled()) { // Desk IDs of newer desks are larger than those of older desks, hence we can use them // to sort desks from old to new. desktopTasks = desktopTasks.sortedBy { (it as DesktopTask).deskId } @@ -165,6 +171,17 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { private fun getDeviceProfile() = (recentsView.mContainer as RecentsViewContainer).deviceProfile fun getRunningTaskExpectedIndex(runningTaskView: TaskView): Int { + if (areMultiDesksFlagsEnabled() && runningTaskView is DesktopTaskView) { + // Use the [deskId] to keep desks in the order of their creation, as a newer desk + // always has a larger [deskId] than the older desks. + val desktopTaskView = + taskViews.firstOrNull { + it is DesktopTaskView && + it.deskId != INACTIVE_DESK_ID && + it.deskId <= runningTaskView.deskId + } + if (desktopTaskView != null) return recentsView.indexOfChild(desktopTaskView) + } val firstTaskViewIndex = recentsView.indexOfChild(getFirstTaskView()) return if (getDeviceProfile().isTablet) { var index = firstTaskViewIndex @@ -343,6 +360,33 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { } } + private fun getTaskMenu(): TaskMenuView? = + getTopOpenViewWithType(recentsView.mContainer, TYPE_TASK_MENU) as? TaskMenuView + + fun shouldInterceptKeyEvent(event: KeyEvent): Boolean { + if (enableOverviewIconMenu()) { + return getTaskMenu()?.isOpen == true || event.keyCode == KeyEvent.KEYCODE_TAB + } + return false + } + + fun updateChildTaskOrientations() { + with(recentsView) { + taskViews.forEach { it.setOrientationState(mOrientationState) } + if (enableOverviewIconMenu()) { + children.forEach { + it.layoutDirection = if (isRtl) LAYOUT_DIRECTION_LTR else LAYOUT_DIRECTION_RTL + } + } + + // Return when it's not fake landscape + if (mOrientationState.isRecentsActivityRotationAllowed) return@with + + // Rotation is supported on phone (details at b/254198019#comment4) + getTaskMenu()?.onRotationChanged() + } + } + var deskExplodeProgress: Float = 0f set(value) { field = value diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index ec6d1c4432..afe7e928ad 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -21,6 +21,7 @@ import android.graphics.Matrix import android.util.Log import android.view.View import android.view.View.OnClickListener +import com.android.app.tracing.traceSection import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.model.data.TaskViewItemInfo import com.android.launcher3.util.SplitConfigurationOptions @@ -100,26 +101,28 @@ class TaskContainer( val itemInfo: TaskViewItemInfo get() = TaskViewItemInfo(taskView, this) - fun bind() { - digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) - if (!enableRefactorTaskThumbnail()) { - thumbnailViewDeprecated.bind(task, overlay, taskView) + fun bind() = + traceSection("TaskContainer.bind") { + digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) + if (!enableRefactorTaskThumbnail()) { + thumbnailViewDeprecated.bind(task, overlay, taskView) + } } - } - fun destroy() { - digitalWellBeingToast?.destroy() - taskContentView.scaleX = 1f - taskContentView.scaleY = 1f - overlay.reset() - if (enableRefactorTaskThumbnail()) { - isThumbnailValid = false - thumbnailData = null - thumbnailView.onRecycle() - } else { - thumbnailViewDeprecated.setShowSplashForSplitSelection(false) + fun destroy() = + traceSection("TaskContainer.destroy") { + digitalWellBeingToast?.destroy() + taskContentView.scaleX = 1f + taskContentView.scaleY = 1f + overlay.reset() + if (enableRefactorTaskThumbnail()) { + isThumbnailValid = false + thumbnailData = null + thumbnailView.onRecycle() + } else { + thumbnailViewDeprecated.setShowSplashForSplitSelection(false) + } } - } fun setOverlayEnabled(enabled: Boolean) { if (!enableRefactorTaskThumbnail()) { @@ -137,23 +140,24 @@ class TaskContainer( } } - fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) { - this.thumbnailPosition = thumbnailPosition - when { - !overlayEnabledStatus -> overlay.reset() - thumbnailPosition == null -> { - Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception()) - overlay.reset() + fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) = + traceSection("TaskContainer.refreshOverlay") { + this.thumbnailPosition = thumbnailPosition + when { + !overlayEnabledStatus -> overlay.reset() + thumbnailPosition == null -> { + Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception()) + overlay.reset() + } + else -> + overlay.initOverlay( + task, + thumbnailData?.thumbnail, + thumbnailPosition.matrix, + thumbnailPosition.isRotated, + ) } - else -> - overlay.initOverlay( - task, - thumbnailData?.thumbnail, - thumbnailPosition.matrix, - thumbnailPosition.isRotated, - ) } - } fun addChildForAccessibility(outChildren: ArrayList<View>) { addAccessibleChildToList(iconView.asView(), outChildren) @@ -168,15 +172,16 @@ class TaskContainer( liveTile: Boolean, hasHeader: Boolean, clickCloseListener: OnClickListener?, - ) { - taskContentView.setState( - TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener), - TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile), - state?.taskId, - ) - thumbnailData = if (state is TaskData.Data) state.thumbnailData else null - overlay.setThumbnailState(thumbnailData) - } + ) = + traceSection("TaskContainer.setState") { + taskContentView.setState( + TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener), + TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile), + state?.taskId, + ) + thumbnailData = if (state is TaskData.Data) state.thumbnailData else null + overlay.setThumbnailState(thumbnailData) + } fun updateTintAmount(tintAmount: Float) { thumbnailView.updateTintAmount(tintAmount) diff --git a/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt b/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt index 04274022e8..1fda5a3ace 100644 --- a/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskHeaderView.kt @@ -18,16 +18,16 @@ package com.android.quickstep.views import android.content.Context import android.util.AttributeSet -import android.widget.FrameLayout import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isGone import com.android.launcher3.R import com.android.quickstep.task.thumbnail.TaskHeaderUiState class TaskHeaderView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FrameLayout(context, attrs) { + ConstraintLayout(context, attrs) { private val headerTitleView: TextView by lazy { findViewById(R.id.header_app_title) } private val headerIconView: ImageView by lazy { findViewById(R.id.header_app_icon) } diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.kt b/quickstep/src/com/android/quickstep/views/TaskMenuView.kt index 7c762f4bea..696f934701 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.kt @@ -22,11 +22,11 @@ import android.animation.ValueAnimator import android.content.Context import android.graphics.Outline import android.graphics.Rect -import android.graphics.drawable.GradientDrawable import android.graphics.drawable.ShapeDrawable import android.graphics.drawable.shapes.RectShape import android.util.AttributeSet import android.view.Gravity +import android.view.KeyEvent import android.view.MotionEvent import android.view.View import android.view.ViewOutlineProvider @@ -165,7 +165,18 @@ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : recentsViewContainer.layoutInflater.inflate(R.layout.task_view_menu_option, this, false) as LinearLayout if (enableOverviewIconMenu()) { - (menuOptionView.background as GradientDrawable).cornerRadius = 0f + menuOptionView.background = + ResourcesCompat.getDrawable( + resources, + R.drawable.app_chip_menu_item_bg, + context.theme, + ) + menuOptionView.foreground = + ResourcesCompat.getDrawable( + resources, + R.drawable.app_chip_menu_item_fg, + context.theme, + ) } menuOption.setIconAndLabelFor( menuOptionView.findViewById(R.id.icon), @@ -366,13 +377,10 @@ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : deviceProfile = recentsViewContainer.deviceProfile, taskMenuX = translationX, taskMenuY = - when { - !enableOverviewIconMenu() -> translationY - // Bottom menu can translate up to show more options. So we use the min - // translation allowed to calculate its max height. - taskView.isOnGridBottomRow() -> minMenuTop - else -> menuTranslationYBeforeOpen - }, + // Bottom menu can translate up to show more options. So we use the min + // translation allowed to calculate its max height. + if (enableOverviewIconMenu() && taskView.isOnGridBottomRow()) minMenuTop + else translationY, ) private fun setOnClosingStartCallback(onClosingStartCallback: Runnable?) { @@ -458,6 +466,24 @@ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : animatorBuilder.with(menuTranslationXAnim) } + override fun dispatchKeyEvent(event: KeyEvent): Boolean { + if (enableOverviewIconMenu()) { + if (event.action != KeyEvent.ACTION_DOWN) return super.dispatchKeyEvent(event) + + val isFirstMenuOptionFocused = optionLayout.indexOfChild(optionLayout.focusedChild) == 0 + val isLastMenuOptionFocused = + optionLayout.indexOfChild(optionLayout.focusedChild) == optionLayout.childCount - 1 + if ( + (isLastMenuOptionFocused && event.keyCode == KeyEvent.KEYCODE_DPAD_DOWN) + || (isFirstMenuOptionFocused && event.keyCode == KeyEvent.KEYCODE_DPAD_UP) + ) { + iconView.requestFocus() + return true + } + } + return super.dispatchKeyEvent(event) + } + companion object { private val REVEAL_OPEN_DURATION = if (enableOverviewIconMenu()) 417L else 150L private val REVEAL_CLOSE_DURATION = if (enableOverviewIconMenu()) 333L else 100L diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 55432b8b54..3d1643cefe 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -42,6 +42,8 @@ import androidx.annotation.IntDef import androidx.annotation.VisibleForTesting import androidx.core.view.updateLayoutParams import com.android.app.animation.Interpolators +import com.android.app.tracing.traceSection +import com.android.launcher3.AbstractFloatingView import com.android.launcher3.Flags.enableCursorHoverStates import com.android.launcher3.Flags.enableDesktopExplodedView import com.android.launcher3.Flags.enableGridOnlyOverview @@ -75,6 +77,7 @@ import com.android.launcher3.util.rects.set import com.android.quickstep.FullscreenDrawParams import com.android.quickstep.RecentsModel import com.android.quickstep.RemoteAnimationTargets +import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle import com.android.quickstep.TaskOverlayFactory import com.android.quickstep.TaskViewUtils import com.android.quickstep.orientation.RecentsPagedOrientationHandler @@ -141,11 +144,10 @@ constructor( /** Returns whether the task is part of overview grid and not being focused. */ get() = container.deviceProfile.isTablet && !isLargeTile - // TODO: b/400532675 - This will not work for empty desks until b/400532675 is fixed. val isRunningTask: Boolean get() = this === recentsView?.runningTaskView - val displayId: Int + open val displayId: Int get() = taskContainers.firstOrNull()?.task.displayId val isExternalDisplay: Boolean @@ -614,6 +616,16 @@ constructor( super.draw(canvas) } + override fun setLayoutDirection(layoutDirection: Int) { + super.setLayoutDirection(layoutDirection) + if (enableOverviewIconMenu()) { + val deviceLayoutDirection = resources.configuration.layoutDirection + taskContainers.forEach { + (it.iconView as IconAppChipView).layoutDirection = deviceLayoutDirection + } + } + } + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) val thumbnailTopMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx @@ -734,61 +746,63 @@ constructor( ?.inflate() } - override fun onAttachedToWindow() { - super.onAttachedToWindow() - if (enableRefactorTaskThumbnail()) { - // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in - // onRecycle. So it should be initialized at this point. TaskView Lifecycle: - // `bind` -> `onBind` -> onAttachedToWindow() -> onDetachFromWindow -> onRecycle - coroutineJobs += - coroutineScope.launch(dispatcherProvider.main) { - viewModel!!.state.collectLatest(::updateTaskViewState) - } + override fun onAttachedToWindow() = + traceSection("TaskView.onAttachedToWindow") { + super.onAttachedToWindow() + if (enableRefactorTaskThumbnail()) { + // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in + // onRecycle. So it should be initialized at this point. TaskView Lifecycle: + // `bind` -> `onBind` -> onAttachedToWindow() -> onDetachFromWindow -> onRecycle + coroutineJobs += + coroutineScope.launch(dispatcherProvider.main) { + viewModel!!.state.collectLatest(::updateTaskViewState) + } + } } - } - private fun updateTaskViewState(state: TaskTileUiState) { - sysUiStatusNavFlags = state.sysUiStatusNavFlags - - // Updating containers - val mapOfTasks = state.tasks.associateBy { it.taskId } - taskContainers.forEach { container -> - val taskId = container.task.key.id - val containerState = mapOfTasks[taskId] - val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView() - container.setState( - state = containerState, - liveTile = state.isLiveTile, - hasHeader = shouldHaveHeader, - clickCloseListener = - if (shouldHaveHeader) { - { - // Update the layout UI to remove this task from the layout grid, and - // remove the task from ActivityManager afterwards. - recentsView?.dismissTask( - taskId, - /* animate= */ true, - /* removeTask= */ true, - ) - } - } else { - null - }, - ) - updateThumbnailValidity(container) - val thumbnailPosition = - updateThumbnailMatrix( - container = container, - width = container.thumbnailView.width, - height = container.thumbnailView.height, + private fun updateTaskViewState(state: TaskTileUiState) = + traceSection("TaskView.updateTaskViewState") { + sysUiStatusNavFlags = state.sysUiStatusNavFlags + + // Updating containers + val mapOfTasks = state.tasks.associateBy { it.taskId } + taskContainers.forEach { container -> + val taskId = container.task.key.id + val containerState = mapOfTasks[taskId] + val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView() + container.setState( + state = containerState, + liveTile = state.isLiveTile, + hasHeader = shouldHaveHeader, + clickCloseListener = + if (shouldHaveHeader) { + { + // Update the layout UI to remove this task from the layout grid, + // and remove the task from ActivityManager afterwards. + recentsView?.dismissTask( + taskId, + /* animate= */ true, + /* removeTask= */ true, + ) + } + } else { + null + }, ) - container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition) + updateThumbnailValidity(container) + val thumbnailPosition = + updateThumbnailMatrix( + container = container, + width = container.thumbnailView.width, + height = container.thumbnailView.height, + ) + container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition) - if (enableOverviewIconMenu()) { - setIconState(container, containerState) + if (enableOverviewIconMenu()) { + setIconState(container, containerState) + } } } - } private fun updateThumbnailValidity(container: TaskContainer) { container.isThumbnailValid = @@ -815,27 +829,33 @@ constructor( container: TaskContainer, width: Int, height: Int, - ): ThumbnailPosition? { - val thumbnailPosition = - viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl) - ?: return null - container.updateThumbnailMatrix(thumbnailPosition.matrix) - return thumbnailPosition - } + ): ThumbnailPosition? = + traceSection("TaskView.updateThumbnailMatrix") { + val thumbnailPosition = + viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl) + ?: return null + container.updateThumbnailMatrix(thumbnailPosition.matrix) + return thumbnailPosition + } - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - if (enableRefactorTaskThumbnail()) { - // The jobs are being cancelled in the background thread. So we make a copy of the list - // to prevent cleaning a new job that might be added to this list during onAttach - // or another moment in the lifecycle. - val coroutineJobsToCancel = coroutineJobs.toList() - coroutineJobs.clear() - coroutineScope.launch(dispatcherProvider.background) { - coroutineJobsToCancel.forEach { it.cancel("TaskView detaching from window") } + override fun onDetachedFromWindow() = + traceSection("TaskView.onDetachedFromWindow") { + super.onDetachedFromWindow() + if (enableRefactorTaskThumbnail()) { + // The jobs are being cancelled in the background thread. So we make a copy of the + // list to prevent cleaning a new job that might be added to this list during + // onAttach or another moment in the lifecycle. + val coroutineJobsToCancel = coroutineJobs.toList() + coroutineJobs.clear() + coroutineScope.launch(dispatcherProvider.background) { + traceSection("TaskView.onDetachedFromWindow.cancellingJobs") { + coroutineJobsToCancel.forEach { + it.cancel("TaskView detaching from window") + } + } + } } } - } /** Updates this task view to the given {@param task}. */ open fun bind( @@ -861,37 +881,40 @@ constructor( onBind(orientedState) } - protected open fun onBind(orientedState: RecentsOrientedState) { - if (enableRefactorTaskThumbnail()) { - val scopeId = context - Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}") - viewModel = - TaskViewModel( - taskViewType = type, - recentsViewData = RecentsDependencies.get(scopeId), - getTaskUseCase = RecentsDependencies.get(scopeId), - getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId), - isThumbnailValidUseCase = RecentsDependencies.get(scopeId), - getThumbnailPositionUseCase = RecentsDependencies.get(scopeId), - dispatcherProvider = RecentsDependencies.get(scopeId), - ) - .apply { bind(*taskIds) } - } + protected open fun onBind(orientedState: RecentsOrientedState) = + traceSection("TaskView.onBind") { + traceSection("TaskView.onBind.createViewModel") { + if (enableRefactorTaskThumbnail()) { + val scopeId = context + Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}") + viewModel = + TaskViewModel( + taskViewType = type, + recentsViewData = RecentsDependencies.get(scopeId), + getTaskUseCase = RecentsDependencies.get(scopeId), + getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId), + isThumbnailValidUseCase = RecentsDependencies.get(scopeId), + getThumbnailPositionUseCase = RecentsDependencies.get(scopeId), + dispatcherProvider = RecentsDependencies.get(scopeId), + ) + .apply { bind(*taskIds) } + } + } - taskContainers.forEach { container -> - container.bind() - if (enableRefactorTaskThumbnail()) { - container.taskContentView.cornerRadius = - thumbnailFullscreenParams.currentCornerRadius - container.taskContentView.doOnSizeChange { width, height -> - updateThumbnailValidity(container) - val thumbnailPosition = updateThumbnailMatrix(container, width, height) - container.refreshOverlay(thumbnailPosition) + taskContainers.forEach { container -> + container.bind() + if (enableRefactorTaskThumbnail()) { + container.taskContentView.cornerRadius = + thumbnailFullscreenParams.currentCornerRadius + container.taskContentView.doOnSizeChange { width, height -> + updateThumbnailValidity(container) + val thumbnailPosition = updateThumbnailMatrix(container, width, height) + container.refreshOverlay(thumbnailPosition) + } } } + setOrientationState(orientedState) } - setOrientationState(orientedState) - } private fun applyThumbnailSplashAlpha() { val alpha = getSplashAlphaProgress() @@ -917,22 +940,23 @@ constructor( @IdRes digitalWellbeingBannerId: Int, @StagePosition stagePosition: Int, taskOverlayFactory: TaskOverlayFactory, - ): TaskContainer { - val iconView = findViewById<View>(iconViewId) as TaskViewIcon - val taskContentView = findViewById<TaskContentView>(taskContentViewId) - return TaskContainer( - this, - task, - taskContentView, - taskContentView.findViewById(thumbnailViewId), - iconView, - TransformingTouchDelegate(iconView.asView()), - stagePosition, - findViewById(digitalWellbeingBannerId)!!, - findViewById(showWindowViewId)!!, - taskOverlayFactory, - ) - } + ): TaskContainer = + traceSection("TaskView.createTaskContainer") { + val iconView = findViewById<View>(iconViewId) as TaskViewIcon + val taskContentView = findViewById<TaskContentView>(taskContentViewId) + return TaskContainer( + this, + task, + taskContentView, + taskContentView.findViewById(thumbnailViewId), + iconView, + TransformingTouchDelegate(iconView.asView()), + stagePosition, + findViewById(digitalWellbeingBannerId)!!, + findViewById(showWindowViewId)!!, + taskOverlayFactory, + ) + } fun containsMultipleTasks() = taskContainers.size > 1 @@ -945,11 +969,12 @@ constructor( /** Check if given `taskId` is tracked in this view */ fun containsTaskId(taskId: Int) = getTaskContainerById(taskId) != null - open fun setOrientationState(orientationState: RecentsOrientedState) { - this.orientedState = orientationState - taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) } - setThumbnailOrientation(orientationState) - } + open fun setOrientationState(orientationState: RecentsOrientedState) = + traceSection("TaskView.setOrientationState") { + this.orientedState = orientationState + taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) } + setThumbnailOrientation(orientationState) + } protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) { taskContainers.forEach { @@ -1096,25 +1121,27 @@ constructor( protected open fun needsUpdate(@TaskDataChanges dataChange: Int, @TaskDataChanges flag: Int) = (dataChange and flag) == flag - protected open fun cancelPendingLoadTasks() { - pendingThumbnailLoadRequests.forEach { it.cancel() } - pendingThumbnailLoadRequests.clear() - pendingIconLoadRequests.forEach { it.cancel() } - pendingIconLoadRequests.clear() - } + protected open fun cancelPendingLoadTasks() = + traceSection("TaskView.cancelPendingLoadTasks") { + pendingThumbnailLoadRequests.forEach { it.cancel() } + pendingThumbnailLoadRequests.clear() + pendingIconLoadRequests.forEach { it.cancel() } + pendingIconLoadRequests.clear() + } - protected open fun setIconState(container: TaskContainer, state: TaskData?) { - if (enableOverviewIconMenu()) { - if (state is TaskData.Data) { - setIcon(container.iconView, state.icon) - container.iconView.setText(state.title) - container.digitalWellBeingToast?.initialize() - } else { - setIcon(container.iconView, null) - container.iconView.setText(null) + protected open fun setIconState(container: TaskContainer, state: TaskData?) = + traceSection("TaskView.setIconState") { + if (enableOverviewIconMenu()) { + if (state is TaskData.Data) { + setIcon(container.iconView, state.icon) + container.iconView.setText(state.title) + container.digitalWellBeingToast?.initialize() + } else { + setIcon(container.iconView, null) + container.iconView.setText(null) + } } } - } protected open fun onIconLoaded(taskContainer: TaskContainer) { setIcon(taskContainer.iconView, taskContainer.task.icon) @@ -1194,15 +1221,14 @@ constructor( /** Launch of the current task (both live and inactive tasks) with an animation. */ fun launchWithAnimation(): RunnableList? { return if (isRunningTask && recentsView?.remoteTargetHandles != null) { - launchAsLiveTile() + launchAsLiveTile(recentsView?.remoteTargetHandles!!) } else { launchAsStaticTile() } } - private fun launchAsLiveTile(): RunnableList? { + private fun launchAsLiveTile(remoteTargetHandles: Array<RemoteTargetHandle>): RunnableList? { val recentsView = recentsView ?: return null - val remoteTargetHandles = recentsView.remoteTargetHandles if (!isClickableAsLiveTile) { Log.e( TAG, @@ -1212,21 +1238,27 @@ constructor( } isClickableAsLiveTile = false val targets = - if (remoteTargetHandles.size == 1) { - remoteTargetHandles[0].transformParams.targetSet + if (remoteTargetHandles.isNotEmpty()) { + if (remoteTargetHandles.size == 1) { + remoteTargetHandles[0].transformParams.targetSet + } else { + val apps = + remoteTargetHandles.flatMap { + it.transformParams.targetSet.apps.asIterable() + } + val wallpapers = + remoteTargetHandles.flatMap { + it.transformParams.targetSet.wallpapers.asIterable() + } + RemoteAnimationTargets( + apps.toTypedArray(), + wallpapers.toTypedArray(), + remoteTargetHandles[0].transformParams.targetSet.nonApps, + remoteTargetHandles[0].transformParams.targetSet.targetMode, + ) + } } else { - val apps = - remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() } - val wallpapers = - remoteTargetHandles.flatMap { - it.transformParams.targetSet.wallpapers.asIterable() - } - RemoteAnimationTargets( - apps.toTypedArray(), - wallpapers.toTypedArray(), - remoteTargetHandles[0].transformParams.targetSet.nonApps, - remoteTargetHandles[0].transformParams.targetSet.targetMode, - ) + null } if (targets == null) { // If the recents animation is cancelled somehow between the parent if block and @@ -1467,6 +1499,20 @@ constructor( return showTaskMenuWithContainer(menuContainer) } + private fun closeTaskMenu(): Boolean { + val floatingView: AbstractFloatingView? = + AbstractFloatingView.getTopOpenViewWithType( + container, + AbstractFloatingView.TYPE_TASK_MENU, + ) + if (floatingView?.isOpen == true) { + floatingView.close(true) + return true + } else { + return false + } + } + private fun showTaskMenuWithContainer(menuContainer: TaskContainer): Boolean { val recentsView = recentsView ?: return false if (enableHoverOfChildElementsInTaskview()) { @@ -1474,12 +1520,16 @@ constructor( recentsView.setTaskBorderEnabled(false) } return if (enableOverviewIconMenu() && menuContainer.iconView is IconAppChipView) { - menuContainer.iconView.revealAnim(/* isRevealing= */ true) - TaskMenuView.showForTask(menuContainer) { - val isAnimated = !recentsView.isSplitSelectionActive - menuContainer.iconView.revealAnim(/* isRevealing= */ false, isAnimated) - if (enableHoverOfChildElementsInTaskview()) { - recentsView.setTaskBorderEnabled(true) + if (menuContainer.iconView.isExpanded) { + closeTaskMenu() + } else { + menuContainer.iconView.revealAnim(/* isRevealing= */ true) + TaskMenuView.showForTask(menuContainer) { + val isAnimated = !recentsView.isSplitSelectionActive + menuContainer.iconView.revealAnim(/* isRevealing= */ false, isAnimated) + if (enableHoverOfChildElementsInTaskview()) { + recentsView.setTaskBorderEnabled(true) + } } } } else if (container.deviceProfile.isTablet) { diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java index 18a533842d..773a039cf3 100644 --- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java +++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java @@ -551,4 +551,13 @@ public class ActiveGestureProtoLogProxy { displayRotation, displaySize.flattenToString(), swipeRegion.toShortString(), ohmRegion.toShortString(), gesturalHeight, largerGesturalHeight, reason); } + + public static void logOnTaskAnimationManagerNotAvailable(int displayId) { + ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( + "TaskAnimationManager not available for displayId=%d", + displayId)); + if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return; + ProtoLog.d(ACTIVE_GESTURE_LOG, "TaskAnimationManager not available for displayId=%d", + displayId); + } } diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt index d36faa2ec5..7b1e445e7a 100644 --- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt +++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskContentViewScreenshotTest.kt @@ -18,11 +18,15 @@ package com.android.quickstep.task.thumbnail import android.content.Context import android.graphics.Color import android.graphics.drawable.BitmapDrawable +import android.platform.test.flag.junit.SetFlagsRule import android.view.LayoutInflater +import com.android.launcher3.Flags import com.android.launcher3.R +import com.android.launcher3.util.rule.setFlags import com.android.quickstep.task.thumbnail.SplashHelper.createSplash import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -37,13 +41,20 @@ import platform.test.screenshot.getEmulatedDevicePathConfig @RunWith(ParameterizedAndroidJunit4::class) class TaskContentViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { - @get:Rule + @get:Rule(order = 0) val setFlagsRule = SetFlagsRule() + + @get:Rule(order = 1) val screenshotRule = ViewScreenshotTestRule( emulationSpec, ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)), ) + @Before + fun setUp() { + setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + } + @Test fun taskContentView_recyclesToUninitialized() { screenshotRule.screenshotTest("taskContentView_uninitialized") { activity -> diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt index 09c62aae1a..1c7af14667 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt @@ -64,7 +64,7 @@ class QuickstepModelDelegateTest { underTest.mHotseatState.predictor = hotseatPredictor underTest.mWidgetsRecommendationState.predictor = widgetRecommendationPredictor underTest.mModel = modelHelper.model - underTest.mDataModel = BgDataModel() + underTest.mDataModel = BgDataModel(WidgetsModel(modelHelper.sandboxContext)) } @After diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt index 26f1197f7e..52d288a723 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt @@ -17,6 +17,7 @@ package com.android.launcher3.taskbar import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController import com.android.launcher3.taskbar.bubbles.BubbleControllers +import com.android.launcher3.taskbar.growth.NudgeController import com.android.launcher3.taskbar.overlay.TaskbarOverlayController import com.android.systemui.shared.rotation.RotationButtonController import java.util.Optional @@ -58,6 +59,7 @@ abstract class TaskbarBaseTestCase { @Mock lateinit var taskbarPinningController: TaskbarPinningController @Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers> @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController + @Mock lateinit var nudgeController: NudgeController lateinit var taskbarControllers: TaskbarControllers @@ -100,6 +102,7 @@ abstract class TaskbarBaseTestCase { taskbarPinningController, optionalBubbleControllers, taskbarDesktopModeController, + nudgeController, ) } } diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt index 37610444b5..c589415196 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt @@ -23,6 +23,7 @@ import android.os.Process import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule +import android.view.Display.DEFAULT_DISPLAY import androidx.test.core.app.ApplicationProvider import com.android.launcher3.Flags.FLAG_ENABLE_MULTI_INSTANCE_MENU_TASKBAR import com.android.launcher3.Flags.FLAG_TASKBAR_OVERFLOW @@ -446,7 +447,7 @@ class TaskbarOverflowTest { ) }) - recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, tasks))) + recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, DEFAULT_DISPLAY, tasks))) for (task in 1..tasks.size) { desktopTaskListener?.onTasksVisibilityChanged( context.virtualDisplay.display.displayId, diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt index 8376bc183c..8758d7cd6d 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt @@ -25,6 +25,7 @@ import android.graphics.Rect import android.os.Process import android.os.UserHandle import android.platform.test.annotations.EnableFlags +import android.view.Display.DEFAULT_DISPLAY import androidx.test.annotation.UiThreadTest import com.android.internal.R import com.android.launcher3.BubbleTextView.RunningAppState @@ -877,7 +878,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val allTasks = ArrayList<GroupTask>().apply { if (!runningTasks.isEmpty()) { - add(DesktopTask(deskId = 0, ArrayList(runningTasks))) + add(DesktopTask(deskId = 0, DEFAULT_DISPLAY, ArrayList(runningTasks))) } addAll(recentTasks) } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java index 6fbbd597d0..78240000c3 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java @@ -49,6 +49,7 @@ import android.os.SystemClock; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; +import android.view.Display; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.ViewTreeObserver; @@ -189,7 +190,7 @@ public abstract class AbsSwipeUpHandlerTestCase< @Before public void setUpRecentsContainer() { mTaskAnimationManager = new TaskAnimationManager(mContext, - RecentsAnimationDeviceState.INSTANCE.get(mContext)); + RecentsAnimationDeviceState.INSTANCE.get(mContext), Display.DEFAULT_DISPLAY); RecentsViewContainer recentsContainer = getRecentsContainer(); RECENTS_VIEW recentsView = getRecentsView(); diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt index 56c01f94a5..381ac6876a 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt @@ -67,7 +67,6 @@ class OverviewCommandHelperTest { OverviewCommandHelper( touchInteractionService = mock(), overviewComponentObserver = mock(), - taskAnimationManager = mock(), dispatcherProvider = TestDispatcherProvider(dispatcher), recentsDisplayModel = mock(), focusState = mock(), diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java index 9722e9dd99..1e4315a040 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java @@ -52,6 +52,7 @@ import com.android.internal.R; import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.util.DaggerSingletonTracker; import com.android.launcher3.util.LooperExecutor; +import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; import com.android.quickstep.views.TaskViewType; import com.android.systemui.shared.recents.model.Task; @@ -148,6 +149,66 @@ public class RecentTasksListTest { } @Test + @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + public void loadTasksInBackground_freeformTask_multiDesksInMultiDisplays() throws Exception { + List<TaskInfo> tasksInDefaultDesk1 = Arrays.asList( + createRecentTaskInfo(/* taskId = */ 1, DEFAULT_DISPLAY), + createRecentTaskInfo(/* taskId = */ 4, DEFAULT_DISPLAY)); + List<TaskInfo> tasksInDefaultDesk2 = Arrays.asList( + createRecentTaskInfo(/* taskId = */ 2, DEFAULT_DISPLAY), + createRecentTaskInfo(/* taskId = */ 3, DEFAULT_DISPLAY)); + List<TaskInfo> tasksInExtend = Arrays.asList( + createRecentTaskInfo(/* taskId = */ 5, /* displayId = */ 1), + createRecentTaskInfo(/* taskId = */ 6, /* displayId = */ 1)); + GroupedTaskInfo recentTaskInfosOfDesk1 = GroupedTaskInfo.forDeskTasks(/* deskId = */1, + DEFAULT_DISPLAY, tasksInDefaultDesk1, /* minimizedTaskIds = */ + Collections.emptySet()); + GroupedTaskInfo recentTaskInfosOfDesk2 = GroupedTaskInfo.forDeskTasks(/* deskId = */2, + DEFAULT_DISPLAY, tasksInDefaultDesk2, /* minimizedTaskIds = */ + Collections.emptySet()); + GroupedTaskInfo recentTaskInfosOfDesk3 = GroupedTaskInfo.forDeskTasks(/* deskId = */3, + /* displayId = */ 1, tasksInExtend, /* minimizedTaskIds = */ + Collections.emptySet()); + when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt())).thenReturn( + new ArrayList<>(Arrays.asList(recentTaskInfosOfDesk1, recentTaskInfosOfDesk2, + recentTaskInfosOfDesk3))); + + List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, + false); + + assertThat(taskList).hasSize(3); + assertThat(taskList.get(2).taskViewType).isEqualTo(TaskViewType.DESKTOP); + List<Task> actualFreeformTasksInDesk1 = taskList.get(2).getTasks(); + assertThat(actualFreeformTasksInDesk1).hasSize(2); + assertThat(actualFreeformTasksInDesk1.get(0).key.id).isEqualTo(1); + assertThat(actualFreeformTasksInDesk1.get(0).isMinimized).isFalse(); + assertThat(actualFreeformTasksInDesk1.get(1).key.id).isEqualTo(4); + assertThat(actualFreeformTasksInDesk1.get(1).isMinimized).isFalse(); + assertThat(((DesktopTask) taskList.get(2)).getDeskId()).isEqualTo(1); + assertThat(((DesktopTask) taskList.get(2)).getDisplayId()).isEqualTo(DEFAULT_DISPLAY); + + assertThat(taskList.get(1).taskViewType).isEqualTo(TaskViewType.DESKTOP); + List<Task> actualFreeformTasksInDesk2 = taskList.get(1).getTasks(); + assertThat(actualFreeformTasksInDesk2).hasSize(2); + assertThat(actualFreeformTasksInDesk2.get(0).key.id).isEqualTo(2); + assertThat(actualFreeformTasksInDesk2.get(0).isMinimized).isFalse(); + assertThat(actualFreeformTasksInDesk2.get(1).key.id).isEqualTo(3); + assertThat(actualFreeformTasksInDesk2.get(1).isMinimized).isFalse(); + assertThat(((DesktopTask) taskList.get(1)).getDeskId()).isEqualTo(2); + assertThat(((DesktopTask) taskList.get(1)).getDisplayId()).isEqualTo(DEFAULT_DISPLAY); + + assertThat(taskList.get(0).taskViewType).isEqualTo(TaskViewType.DESKTOP); + List<Task> actualFreeformTasksInDesk3 = taskList.get(0).getTasks(); + assertThat(actualFreeformTasksInDesk3).hasSize(2); + assertThat(actualFreeformTasksInDesk3.get(0).key.id).isEqualTo(5); + assertThat(actualFreeformTasksInDesk3.get(0).isMinimized).isFalse(); + assertThat(actualFreeformTasksInDesk3.get(1).key.id).isEqualTo(6); + assertThat(actualFreeformTasksInDesk3.get(1).isMinimized).isFalse(); + assertThat(((DesktopTask) taskList.get(0)).getDeskId()).isEqualTo(3); + assertThat(((DesktopTask) taskList.get(0)).getDisplayId()).isEqualTo(1); + } + + @Test public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() throws Exception { String taskDescription = "Wheeee!"; RecentTaskInfo task1 = new RecentTaskInfo(); @@ -175,7 +236,8 @@ public class RecentTasksListTest { } @Test - @DisableFlags(FLAG_ENABLE_SEPARATE_EXTERNAL_DISPLAY_TASKS) + @DisableFlags({FLAG_ENABLE_SEPARATE_EXTERNAL_DISPLAY_TASKS, + FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND}) public void loadTasksInBackground_freeformTask_createsDesktopTask() throws Exception { List<TaskInfo> tasks = Arrays.asList( createRecentTaskInfo(1 /* taskId */, DEFAULT_DISPLAY), @@ -183,7 +245,8 @@ public class RecentTasksListTest { createRecentTaskInfo(5 /* taskId */, 1 /* displayId */), createRecentTaskInfo(6 /* taskId */, 1 /* displayId */)); GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks( - 0 /* deskId */, tasks, Collections.emptySet() /* minimizedTaskIds */); + 0 /* deskId */, DEFAULT_DISPLAY, tasks, + Collections.emptySet() /* minimizedTaskIds */); when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt())) .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos))); @@ -214,7 +277,8 @@ public class RecentTasksListTest { createRecentTaskInfo(5 /* taskId */, 1 /* displayId */), createRecentTaskInfo(6 /* taskId */, 1 /* displayId */)); GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks( - 0 /* deskId */, tasks, Collections.emptySet() /* minimizedTaskIds */); + 0 /* deskId */, DEFAULT_DISPLAY, tasks, + Collections.emptySet() /* minimizedTaskIds */); when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt())) .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos))); @@ -248,7 +312,7 @@ public class RecentTasksListTest { Set<Integer> minimizedTaskIds = Arrays.stream(new Integer[]{1, 4, 5}).collect(Collectors.toSet()); GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forDeskTasks( - 0 /* deskId */, tasks, minimizedTaskIds); + 0 /* deskId */, DEFAULT_DISPLAY, tasks, minimizedTaskIds); when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt())) .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos))); diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java index 6e9885ad43..fd88a5cb27 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; +import android.view.Display; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -54,7 +55,7 @@ public class TaskAnimationManagerTest { public void setUp() { MockitoAnnotations.initMocks(this); mTaskAnimationManager = new TaskAnimationManager(mContext, - RecentsAnimationDeviceState.INSTANCE.get(mContext)) { + RecentsAnimationDeviceState.INSTANCE.get(mContext), Display.DEFAULT_DISPLAY) { @Override SystemUiProxy getSystemUiProxy() { return mSystemUiProxy; diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt index 0570c26eed..66b3b047d7 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt @@ -43,12 +43,12 @@ class LandscapePagedViewHandlerTest { if (isEnabled) { setFlagsRule.enableFlags( Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW, - Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU + Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU, ) } else { setFlagsRule.disableFlags( Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW, - Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU + Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU, ) } } @@ -108,14 +108,8 @@ class LandscapePagedViewHandlerTest { val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true) - // TODO(b/326377497): When started in fake seascape and rotated to landscape, - // the icon chips are in RTL and wrongly positioned at the right side of the snapshot. - // Top-Left app chip should be placed at the top left of the first snapshot, but because - // this issue, it's displayed at the top-right of the second snapshot. - // The Bottom-Right app chip is displayed at the top-right of the first snapshot because - // of this issue. - assertThat(topLeftY).isEqualTo(0) - assertThat(bottomRightY).isEqualTo(-316) + assertThat(topLeftY).isEqualTo(-316) + assertThat(bottomRightY).isEqualTo(0) } /** Test updateSplitIconsPosition */ diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt index 37886888ea..d455b0d1e9 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt @@ -43,12 +43,12 @@ class SeascapePagedViewHandlerTest { if (isEnabled) { setFlagsRule.enableFlags( Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW, - Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU + Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU, ) } else { setFlagsRule.disableFlags( Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW, - Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU + Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU, ) } } @@ -110,12 +110,6 @@ class SeascapePagedViewHandlerTest { val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true) - // TODO(b/326377497): When started in fake seascape and rotated to landscape, - // the icon chips are in RTL and wrongly positioned at the right side of the snapshot. - // Top-Left app chip should be placed at the top left of the first snapshot, but because - // this issue, it's displayed at the top-right of the second snapshot. - // The Bottom-Right app chip is displayed at the top-right of the first snapshot because - // of this issue. assertThat(topLeftY).isEqualTo(316) assertThat(bottomRightY).isEqualTo(0) } @@ -167,7 +161,7 @@ class SeascapePagedViewHandlerTest { `when`(iconView.layoutParams).thenReturn(frameLayout) sut.updateSplitIconsPosition(iconView, expectedTranslationY, false) - assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START) + assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.END) verify(iconView).setSplitTranslationX(0f) verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat()) } @@ -182,7 +176,7 @@ class SeascapePagedViewHandlerTest { `when`(iconView.layoutParams).thenReturn(frameLayout) sut.updateSplitIconsPosition(iconView, expectedTranslationY, true) - assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END) + assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.START) verify(iconView).setSplitTranslationX(0f) verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat()) } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt index 6790567a85..e22892c9cc 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.graphics.Bitmap import android.graphics.Rect import android.graphics.drawable.Drawable +import android.view.Display.DEFAULT_DISPLAY import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.launcher3.util.SplitConfigurationOptions import com.android.launcher3.util.TestDispatcherProvider @@ -64,7 +65,7 @@ class TasksRepositoryTest { /* snapPosition = */ SNAP_TO_2_50_50, ), ), - DesktopTask(deskId = 0, tasks.subList(3, 6)), + DesktopTask(deskId = 0, DEFAULT_DISPLAY, tasks.subList(3, 6)), ) private val recentsModel = FakeRecentTasksDataSource() private val taskThumbnailDataSource = FakeTaskThumbnailDataSource() diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt index b49923f33d..6c0d0ed9ea 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt @@ -19,7 +19,9 @@ package com.android.quickstep.recents.ui.mapper import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.ShapeDrawable +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import android.view.Surface import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -31,12 +33,15 @@ import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot import com.android.systemui.shared.recents.model.ThumbnailData import com.google.common.truth.Truth.assertThat +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class TaskUiStateMapperTest { + @get:Rule val mSetFlagsRule = SetFlagsRule() + /** TaskHeaderUiState */ @Test fun taskData_isNull_returns_HideHeader() { @@ -49,6 +54,29 @@ class TaskUiStateMapperTest { assertThat(result).isEqualTo(TaskHeaderUiState.HideHeader) } + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW) + @Test + fun explodedFlagDisabled_returnsHideHeader() { + val inputs = + listOf( + TASK_DATA, + TASK_DATA.copy(thumbnailData = null), + TASK_DATA.copy(isLocked = true), + TASK_DATA.copy(title = null), + ) + val closeCallback = View.OnClickListener {} + val expected = TaskHeaderUiState.HideHeader + inputs.forEach { taskData -> + val result = + TaskUiStateMapper.toTaskHeaderState( + taskData = taskData, + hasHeader = true, + clickCloseListener = closeCallback, + ) + assertThat(result).isEqualTo(expected) + } + } + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW) @Test fun taskData_hasHeader_and_taskData_returnsShowHeader() { diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt index 6fbf4823b7..15da4d4def 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt @@ -18,6 +18,7 @@ package com.android.quickstep.util import android.content.ComponentName import android.content.Intent +import android.view.Display.DEFAULT_DISPLAY import com.android.launcher3.util.LauncherMultivalentJUnit import com.android.systemui.shared.recents.model.Task import com.google.common.truth.Truth.assertThat @@ -29,42 +30,42 @@ class DesktopTaskTest { @Test fun testDesktopTask_sameInstance_isEqual() { - val task = DesktopTask(deskId = 0, createTasks(1)) + val task = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) assertThat(task).isEqualTo(task) } @Test fun testDesktopTask_identicalConstructor_isEqual() { - val task1 = DesktopTask(deskId = 0, createTasks(1)) - val task2 = DesktopTask(deskId = 0, createTasks(1)) + val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) + val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) assertThat(task1).isEqualTo(task2) } @Test fun testDesktopTask_copy_isEqual() { - val task1 = DesktopTask(deskId = 0, createTasks(1)) + val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) val task2 = task1.copy() assertThat(task1).isEqualTo(task2) } @Test fun testDesktopTask_differentDeskIds_isNotEqual() { - val task1 = DesktopTask(deskId = 0, createTasks(1)) - val task2 = DesktopTask(deskId = 1, createTasks(1)) + val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) + val task2 = DesktopTask(deskId = 1, DEFAULT_DISPLAY, createTasks(1)) assertThat(task1).isNotEqualTo(task2) } @Test fun testDesktopTask_differentTaskIds_isNotEqual() { - val task1 = DesktopTask(deskId = 0, createTasks(1)) - val task2 = DesktopTask(deskId = 0, createTasks(2)) + val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) + val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(2)) assertThat(task1).isNotEqualTo(task2) } @Test fun testDesktopTask_differentLength_isNotEqual() { - val task1 = DesktopTask(deskId = 0, createTasks(1)) - val task2 = DesktopTask(deskId = 0, createTasks(1, 2)) + val task1 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1)) + val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, createTasks(1, 2)) assertThat(task1).isNotEqualTo(task2) } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt index 67fc62f772..9f491717c4 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt @@ -19,6 +19,7 @@ package com.android.quickstep.util import android.content.ComponentName import android.content.Intent import android.graphics.Rect +import android.view.Display.DEFAULT_DISPLAY import com.android.launcher3.util.LauncherMultivalentJUnit import com.android.launcher3.util.SplitConfigurationOptions import com.android.systemui.shared.recents.model.Task @@ -98,7 +99,7 @@ class GroupTaskTest { @Test fun testGroupTask_differentType_isNotEqual() { val task1 = SingleTask(createTask(1)) - val task2 = DesktopTask(deskId = 0, listOf(createTask(1))) + val task2 = DesktopTask(deskId = 0, DEFAULT_DISPLAY, listOf(createTask(1))) assertThat(task1).isNotEqualTo(task2) } diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java index ef6f55e24f..93b979cc32 100644 --- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java +++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java @@ -27,7 +27,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.Looper; import android.view.Choreographer; import android.view.Display; @@ -100,12 +99,13 @@ public class InputConsumerUtilsTest { @Rule public final SandboxApplication mContext = new SandboxApplication(); + private final int mDisplayId = Display.DEFAULT_DISPLAY; @NonNull private final InputMonitorCompat mInputMonitorCompat = - new InputMonitorCompat("", Display.DEFAULT_DISPLAY); + new InputMonitorCompat("", mDisplayId); private TaskAnimationManager mTaskAnimationManager; private InputChannelCompat.InputEventReceiver mInputEventReceiver; - @Nullable private ResetGestureInputConsumer mResetGestureInputConsumer; + private boolean mUserUnlocked = true; @NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null; @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext; @@ -126,8 +126,7 @@ public class InputConsumerUtilsTest { @Before public void setupTaskAnimationManager() { - mTaskAnimationManager = new TaskAnimationManager( - mContext, mDeviceState); + mTaskAnimationManager = new TaskAnimationManager(mContext, mDeviceState, mDisplayId); } @Before @@ -164,12 +163,6 @@ public class InputConsumerUtilsTest { } @Before - public void setUpResetGestureInputConsumer() { - mResetGestureInputConsumer = new ResetGestureInputConsumer( - mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext); - } - - @Before public void setupLockedUserState() { when(mLockedUserState.isUserUnlocked()).thenReturn(true); } @@ -314,8 +307,6 @@ public class InputConsumerUtilsTest { @Test public void testNewBaseConsumer_containsOtherActivityInputConsumer() { - // OtherActivityInputConsumer needs to be initialized on the main thread because of - // MotionPauseDetector.mForcePauseTimeout assertCorrectInputConsumer( this::createBaseInputConsumer, OtherActivityInputConsumer.class, @@ -486,7 +477,7 @@ public class InputConsumerUtilsTest { MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); InputConsumer inputConsumer = newConsumer( mContext, - mResetGestureInputConsumer, + mUserUnlocked, mOverviewComponentObserver, mDeviceState, mPreviousGestureState, @@ -510,7 +501,8 @@ public class InputConsumerUtilsTest { MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); InputConsumer inputConsumer = newBaseConsumer( mContext, - mResetGestureInputConsumer, + mUserUnlocked, + mTaskbarManager, mOverviewComponentObserver, mDeviceState, mPreviousGestureState, @@ -535,12 +527,15 @@ public class InputConsumerUtilsTest { ResetGestureInputConsumer.class, InputConsumer.TYPE_RESET_GESTURE); - mResetGestureInputConsumer = null; + mUserUnlocked = false; - runOnMainSync(() -> assertThat(inputConsumerProvider.get()).isEqualTo(InputConsumer.NO_OP)); + assertCorrectInputConsumer( + inputConsumerProvider, + InputConsumer.class, + InputConsumer.TYPE_NO_OP); } - private static void assertCorrectInputConsumer( + private void assertCorrectInputConsumer( @NonNull Provider<InputConsumer> inputConsumerProvider, @NonNull Class<? extends InputConsumer> expectedOutputConsumer, int expectedType) { @@ -551,11 +546,13 @@ public class InputConsumerUtilsTest { expectedType); } - private static void assertCorrectInputConsumer( + private void assertCorrectInputConsumer( @NonNull Provider<InputConsumer> inputConsumerProvider, @NonNull Class<? extends InputConsumer> expectedOutputConsumer, @NonNull Class<? extends InputConsumer> expectedActiveConsumer, int expectedType) { + when(mCurrentGestureState.getDisplayId()).thenReturn(mDisplayId); + runOnMainSync(() -> { InputConsumer inputConsumer = inputConsumerProvider.get(); @@ -563,7 +560,14 @@ public class InputConsumerUtilsTest { assertThat(inputConsumer.getActiveConsumerInHierarchy()) .isInstanceOf(expectedActiveConsumer); assertThat(inputConsumer.getType()).isEqualTo(expectedType); + assertThat(inputConsumer.getDisplayId()).isEqualTo(mDisplayId); }); + int expectedDisplayId = mDisplayId + 1; + + when(mCurrentGestureState.getDisplayId()).thenReturn(expectedDisplayId); + + runOnMainSync(() -> assertThat(inputConsumerProvider.get().getDisplayId()) + .isEqualTo(expectedDisplayId)); } private static void runOnMainSync(@NonNull Runnable runnable) { diff --git a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt b/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt index 47108e0572..daa77d2a31 100644 --- a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt +++ b/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchAnimatorHelperTest.kt @@ -32,7 +32,9 @@ import android.util.DisplayMetrics import android.view.SurfaceControl import android.view.WindowManager import android.window.TransitionInfo +import android.window.TransitionInfo.Change import androidx.core.util.Supplier +import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread import com.android.app.animation.Interpolators import com.android.internal.jank.Cuj import com.android.launcher3.desktop.DesktopAppLaunchAnimatorHelper @@ -45,6 +47,7 @@ import org.junit.Rule import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever class DesktopAppLaunchAnimatorHelperTest { @@ -70,6 +73,10 @@ class DesktopAppLaunchAnimatorHelperTest { whenever(transactionSupplier.get()).thenReturn(transaction) whenever(transaction.setCrop(any(), any())).thenReturn(transaction) whenever(transaction.setCornerRadius(any(), any())).thenReturn(transaction) + whenever(transaction.setScale(any(), any(), any())).thenReturn(transaction) + whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction) + whenever(transaction.setAlpha(any(), any())).thenReturn(transaction) + whenever(transaction.setFrameTimeline(any())).thenReturn(transaction) whenever(context.resources).thenReturn(resources) whenever(resources.displayMetrics).thenReturn(DisplayMetrics()) @@ -77,14 +84,8 @@ class DesktopAppLaunchAnimatorHelperTest { } @Test - fun launchTransition_returnsLaunchAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) + fun launchTransition_returnsLaunchAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -93,14 +94,27 @@ class DesktopAppLaunchAnimatorHelperTest { } @Test - fun noLaunchTransition_returnsEmptyAnimatorsList() { + fun launchTransition_callsAnimationEndListener() = runOnUiThread { + val finishCallback = mock<Function1<Animator, Unit>>() + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE)) + + val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback) + + animators.forEach { animator -> + animator.start() + animator.end() + verify(finishCallback).invoke(animator) + } + } + + @Test + fun noLaunchTransition_returnsEmptyAnimatorsList() = runOnUiThread { val pipChange = TransitionInfo.Change(mock(), mock()).apply { mode = WindowManager.TRANSIT_PIP taskInfo = TASK_INFO_FREEFORM } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(pipChange) + val transitionInfo = createTransitionInfo(listOf(pipChange)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -108,20 +122,8 @@ class DesktopAppLaunchAnimatorHelperTest { } @Test - fun minimizeTransition_returnsLaunchAndMinimizeAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val minimizeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_TO_BACK - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) - transitionInfo.addChange(minimizeChange) + fun minimizeTransition_returnsLaunchAndMinimizeAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, MINIMIZE_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -131,21 +133,23 @@ class DesktopAppLaunchAnimatorHelperTest { } @Test + fun minimizeTransition_callsAnimationEndListener() = runOnUiThread { + val finishCallback = mock<Function1<Animator, Unit>>() + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, MINIMIZE_CHANGE)) + + val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback) + + animators.forEach { animator -> + animator.start() + animator.end() + verify(finishCallback).invoke(animator) + } + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX) - fun trampolineTransition_flagEnabled_returnsLaunchAndCloseAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val closeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_CLOSE - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) - transitionInfo.addChange(closeChange) + fun trampolineTransition_flagEnabled_returnsLaunchAndCloseAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -155,21 +159,24 @@ class DesktopAppLaunchAnimatorHelperTest { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX) + fun trampolineTransition_flagEnabled_callsAnimationEndListener() = runOnUiThread { + val finishCallback = mock<Function1<Animator, Unit>>() + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE)) + + val animators = helper.createAnimators(transitionInfo, finishCallback = finishCallback) + + animators.forEach { animator -> + animator.start() + animator.end() + verify(finishCallback).invoke(animator) + } + } + + @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX) - fun trampolineTransition_flagDisabled_returnsLaunchAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val closeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_CLOSE - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) - transitionInfo.addChange(closeChange) + fun trampolineTransition_flagDisabled_returnsLaunchAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo(listOf(OPEN_CHANGE, CLOSE_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -179,26 +186,9 @@ class DesktopAppLaunchAnimatorHelperTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX) - fun trampolineTransition_flagEnabled_hitDesktopWindowLimit_returnsLaunchMinimizeCloseAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val minimizeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_TO_BACK - taskInfo = TASK_INFO_FREEFORM - } - val closeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_CLOSE - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) - transitionInfo.addChange(minimizeChange) - transitionInfo.addChange(closeChange) + fun trampolineTransition_flagEnabled_hitDesktopWindowLimit_returnsLaunchMinimizeCloseAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo( + listOf(OPEN_CHANGE, MINIMIZE_CHANGE, CLOSE_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -210,26 +200,9 @@ class DesktopAppLaunchAnimatorHelperTest { @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX) - fun trampolineTransition_flagDisabled_hitDesktopWindowLimit_returnsLaunchMinimizeAnimator() { - val openChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_OPEN - taskInfo = TASK_INFO_FREEFORM - } - val minimizeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_TO_BACK - taskInfo = TASK_INFO_FREEFORM - } - val closeChange = - TransitionInfo.Change(mock(), mock()).apply { - mode = WindowManager.TRANSIT_CLOSE - taskInfo = TASK_INFO_FREEFORM - } - val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) - transitionInfo.addChange(openChange) - transitionInfo.addChange(minimizeChange) - transitionInfo.addChange(closeChange) + fun trampolineTransition_flagDisabled_hitDesktopWindowLimit_returnsLaunchMinimizeAnimator() = runOnUiThread { + val transitionInfo = createTransitionInfo( + listOf(OPEN_CHANGE, MINIMIZE_CHANGE, CLOSE_CHANGE)) val actual = helper.createAnimators(transitionInfo, finishCallback = {}) @@ -280,6 +253,12 @@ class DesktopAppLaunchAnimatorHelperTest { assertThat(animator.duration).isEqualTo(100) } + private fun createTransitionInfo(changes: List<Change>): TransitionInfo { + val transitionInfo = TransitionInfo(WindowManager.TRANSIT_NONE, 0) + changes.forEach { transitionInfo.addChange(it) } + return transitionInfo + } + private companion object { val TASK_INFO_FREEFORM = ActivityManager.RunningTaskInfo().apply { @@ -290,5 +269,23 @@ class DesktopAppLaunchAnimatorHelperTest { configuration.windowConfiguration.windowingMode = WindowConfiguration.WINDOWING_MODE_FREEFORM } + + val OPEN_CHANGE = + TransitionInfo.Change(mock(), mock()).apply { + mode = WindowManager.TRANSIT_OPEN + taskInfo = TASK_INFO_FREEFORM + } + + val CLOSE_CHANGE = + TransitionInfo.Change(mock(), mock()).apply { + mode = WindowManager.TRANSIT_CLOSE + taskInfo = TASK_INFO_FREEFORM + } + + val MINIMIZE_CHANGE = + TransitionInfo.Change(mock(), mock()).apply { + mode = WindowManager.TRANSIT_TO_BACK + taskInfo = TASK_INFO_FREEFORM + } } } diff --git a/quickstep/res/drawable/ic_chevron_end.xml b/res/drawable/ic_chevron_end.xml index 9ca4f3a3b4..9ca4f3a3b4 100644 --- a/quickstep/res/drawable/ic_chevron_end.xml +++ b/res/drawable/ic_chevron_end.xml diff --git a/quickstep/res/drawable/ic_chevron_start.xml b/res/drawable/ic_chevron_start.xml index 913da026da..913da026da 100644 --- a/quickstep/res/drawable/ic_chevron_start.xml +++ b/res/drawable/ic_chevron_start.xml diff --git a/res/layout/work_mode_utility_view.xml b/res/layout/work_mode_utility_view.xml index b68ff3eace..568c2c3b6e 100644 --- a/res/layout/work_mode_utility_view.xml +++ b/res/layout/work_mode_utility_view.xml @@ -26,6 +26,7 @@ android:layout_height="@dimen/work_scheduler_size" android:layout_marginBottom="@dimen/work_scheduler_bottom_margin" android:contentDescription="@string/work_scheduler_button_content_description" + android:elevation="@dimen/work_fab_elevation" android:src="@drawable/ic_schedule" android:layout_gravity="end" android:background="@drawable/work_scheduler_background" /> diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index a2a1cf230d..c8ab8ff89f 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Bladsy %1$d van %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Tuisskerm %1$d van %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nuwe tuisskermbladsy"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktief"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Geminimeer"</string> <string name="folder_opened" msgid="94695026776264709">"Vouer oopgemaak, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Tik om die vouer toe te maak"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tik om nuwe naam te stoor"</string> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index ac462ac63e..56e4d56568 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"ገፅ %1$d ከ%2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"መነሻ ማያ ገፅ %1$d ከ%2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"አዲስ የመነሻ ማያ ገፅ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"ገቢር"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"አንሷል"</string> <string name="folder_opened" msgid="94695026776264709">"አቃፊ ተከፍቷል፣ <xliff:g id="WIDTH">%1$d</xliff:g> በ<xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"አቃፊን ለመዝጋት መታ ያድርጉ"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"ዳግም የተሰጠውን ስም ለማስቀመጥ መታ ያድርጉ"</string> diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index 6db0ffb680..1e4861c731 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$dৰ %1$d পৃষ্ঠা"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"গৃহ স্ক্ৰীন %2$dৰ %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"গৃহ স্ক্ৰীনৰ নতুন পৃষ্ঠা"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"সক্ৰিয়"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"মিনিমাইজ কৰা হৈছে"</string> <string name="folder_opened" msgid="94695026776264709">"ফ’ল্ডাৰ খোলা হ’ল, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ফ\'ল্ডাৰ বন্ধ কৰিবলৈ টিপক"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"সলনি কৰা নাম ছেভ কৰিবলৈ টিপক"</string> diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 28035df5c4..916b7381a4 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Səhifə %1$d of %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Əsas Səhifə ekranı %1$d of %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Yeni əsas ekran səhifəsi"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Kiçildildi"</string> <string name="folder_opened" msgid="94695026776264709">"Qovluq açıldı, <xliff:g id="HEIGHT">%2$d</xliff:g> hündürlük ilə <xliff:g id="WIDTH">%1$d</xliff:g> enində"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Qovluq bağlamaq üçün toxunun"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ad dəyişikliyini yadda saxlamaq üçün toxunun"</string> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index ffb3d91412..671cb6dd2f 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Старонка %1$d з %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Галоўны экран %1$d з %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Новая старонка галоўнага экрана"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Актыўна"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Згорнута"</string> <string name="folder_opened" msgid="94695026776264709">"Папка адкрыта, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Краніце, каб закрыць папку"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Краніце, каб захаваць новую назву"</string> diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 6bc248333b..296f0884de 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dটির %1$d নম্বর হোম স্ক্রিন"</string> <string name="workspace_new_page" msgid="257366611030256142">"নতুন হোম স্ক্রীনের পৃষ্ঠা"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"অ্যাক্টিভ"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ছোট করা হয়েছে"</string> <string name="folder_opened" msgid="94695026776264709">"ফোল্ডার খোলা হয়েছে, <xliff:g id="WIDTH">%1$d</xliff:g> বাই <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ফোল্ডার বন্ধ করতে আলতো চাপ দিন"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"পুনঃনামকরণ সংরক্ষণ করতে আলতো চাপ দিন"</string> diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 394e30f733..9ab5c4cc38 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d od %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni ekran %1$d od %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktivno"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizirano"</string> <string name="folder_opened" msgid="94695026776264709">"Folder je otvoren, (š) <xliff:g id="WIDTH">%1$d</xliff:g> (v) <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da zatvorite folder"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da sačuvate promjenu naziva"</string> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 82bbd121a4..693c6e5f5b 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d z %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktivní"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimalizováno"</string> <string name="folder_opened" msgid="94695026776264709">"Složka otevřena, rozměry <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Klepnutím složku zavřete"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Klepnutím změnu názvu uložíte"</string> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 1485f75155..bd2bf5a9e9 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d ud af %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskærm %1$d ud af %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Ny startskærm"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimeret"</string> <string name="folder_opened" msgid="94695026776264709">"Mappen er åben, <xliff:g id="WIDTH">%1$d</xliff:g> gange <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Tryk for at lukke mappen"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tryk for at gemme omdøbningen"</string> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 4a7fb7f089..ecdc73ab2b 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Seite %1$d von %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Startbildschirm %1$d von %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Neue Startbildschirmseite"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimiert"</string> <string name="folder_opened" msgid="94695026776264709">"Ordner geöffnet, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Ordner zum Schließen antippen"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Neuen Namen zum Speichern antippen"</string> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index de2bdc7eed..330c23e624 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Σελίδα %1$d από %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Αρχική οθόνη %1$d από %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Νέα σελίδα αρχικής οθόνης"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Ενεργό"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Ελαχιστοποιήθηκε"</string> <string name="folder_opened" msgid="94695026776264709">"Άνοιγμα φακέλου, <xliff:g id="WIDTH">%1$d</xliff:g> επί <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Πατήστε για να κλείσετε το φάκελο"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Πατήστε για να αποθηκεύσετε τη νέα ονομασία"</string> diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 7ce9c0cf74..6825d8025a 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -135,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string> <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string> diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index 71fd15ad60..f383e3f973 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"Close"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Personal apps tab"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Work apps tab"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Work apps are badged and visible to your IT admin"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"Got it"</string> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 7ce9c0cf74..6825d8025a 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -135,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string> <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string> diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 7ce9c0cf74..6825d8025a 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -135,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone into landscape mode"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"Set phone to landscape mode"</string> <string name="notification_dots_title" msgid="9062440428204120317">"Notification dots"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index ef5d48351f..a287135180 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Pestaña de apps personales"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Pestaña de apps de trabajo"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"Entendido"</string> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index a1ed2ed94b..e3ab38d34d 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nueva página de pantalla de inicio"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Activa"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizada"</string> <string name="folder_opened" msgid="94695026776264709">"Carpeta abierta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Toca para cerrar la carpeta"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toca para guardar el nuevo nombre"</string> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 5300ec8d58..3df323d737 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Leht %1$d/%2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Avakuva %1$d/%2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Uus avakuva leht"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Ühendatud"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimeeritud"</string> <string name="folder_opened" msgid="94695026776264709">"Kaust on avatud, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Puudutage kausta sulgemiseks"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Puudutage ümbernimetamise salvestamiseks"</string> diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 013c88e662..0b30b38477 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d orri nagusi"</string> <string name="workspace_new_page" msgid="257366611030256142">"Orri nagusiaren orri berria"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktibo"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizatuta"</string> <string name="folder_opened" msgid="94695026776264709">"Karpeta ireki da: <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Karpeta ixteko, sakatu hau"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Izen berria gordetzeko, sakatu hau"</string> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 578d35da58..671c7f2abb 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"صفحه %1$d از %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"صفحه اصلی %1$d از %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"صفحه اصلی جدید"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"فعال"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"کوچکشده"</string> <string name="folder_opened" msgid="94695026776264709">"پوشه باز شده، <xliff:g id="WIDTH">%1$d</xliff:g> در <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"برای بستن پوشه، تکضرب بزنید"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"برای ذخیره تغییر نام، تکضرب بزنید"</string> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 29d04b2dfb..49b2b57600 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Sivu %1$d / %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Aloitusruutu %1$d/%2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Uusi aloitusnäytön sivu"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiivinen"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Pienennetty"</string> <string name="folder_opened" msgid="94695026776264709">"Kansio avattu, koko <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Sulje kansio koskettamalla."</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tallenna uusi nimi koskettamalla."</string> diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index eb9360f15e..6c39282020 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Actif"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Réduit"</string> <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Touchez pour fermer le dossier"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Touchez pour enregistrer le nouveau nom"</string> @@ -137,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"Autoriser la rotation de l\'écran d\'accueil"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"Mode paysage"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"Configurer le téléphone en mode paysage"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"Configurez le téléphone en mode paysage"</string> <string name="notification_dots_title" msgid="9062440428204120317">"Pastilles de notification"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activé"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"Désactivé"</string> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index fea7ff1604..73902b41b2 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Actif"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimisé"</string> <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Appuyez pour fermer le dossier."</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Appuyez pour enregistrer le nouveau nom du dossier."</string> diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 513083a6f4..1619b1455d 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nova páxina da pantalla de inicio"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Activa"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizada"</string> <string name="folder_opened" msgid="94695026776264709">"Abriuse o cartafol, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Toca fóra para pechar o cartafol"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toca fóra para cambiar o nome do cartafol"</string> diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index d31f291a5f..bd40d1968f 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d માંથી %1$d પૃષ્ઠ"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d માંથી %1$d હોમ સ્ક્રીન"</string> <string name="workspace_new_page" msgid="257366611030256142">"નવું હોમ સ્ક્રીન પૃષ્ઠ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"સક્રિય"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ન્યૂનતમ"</string> <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> બાય <xliff:g id="HEIGHT">%2$d</xliff:g> નું ફોલ્ડર ખોલ્યું"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ફોલ્ડર બંધ કરવા માટે ટૅપ કરો"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"નામ બદલવાનું સાચવવા માટે ટૅપ કરો"</string> diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 360ef330f3..15485a24e7 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"पेज %2$d में से %1$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"होम स्क्रीन %2$d में से %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"नया होम स्क्रीन पेज"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"चालू है"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"छोटा किया गया"</string> <string name="folder_opened" msgid="94695026776264709">"फ़ोल्डर खोला गया, <xliff:g id="WIDTH">%1$d</xliff:g> गुणा <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"फ़ोल्डर बंद करने के लिए टैप करें"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"नाम बदलना सहेजने के लिए टैप करें"</string> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index db82c46388..48069a2fd4 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Stranica %1$d od %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni zaslon %1$d od %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog zaslona"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktivno"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizirano"</string> <string name="folder_opened" msgid="94695026776264709">"Mapa je otvorena, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da biste zatvorili mapu"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da biste spremili promijenjeni naziv"</string> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 04e43a7b77..a298738965 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d/%1$d. oldal"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d/%1$d. kezdőképernyő"</string> <string name="workspace_new_page" msgid="257366611030256142">"Új kezdőképernyő oldal"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktív"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Kis méret"</string> <string name="folder_opened" msgid="94695026776264709">"Mappa megnyitva – szélesség: <xliff:g id="WIDTH">%1$d</xliff:g>; magasság: <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Érintse meg a mappa bezárásához"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Koppintson ide az átnevezés mentéséhez"</string> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 28a01ac1f0..047c074b09 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Halaman layar utama baru"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktif"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Diperkecil"</string> <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Ketuk untuk menutup folder"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketuk untuk menyimpan ganti nama"</string> diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index a87df931f0..19b967f287 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"Loka"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persónulegt"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Flipi forrita til einkanota"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Flipi vinnuforrita"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Vinnuforrit eru merkt og kerfisstjórinn getur séð þau"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"Ég skil"</string> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index ffe74364f7..fd747d1201 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"Esci"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personali"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Scheda App personali"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Scheda App di lavoro"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Le app di lavoro sono contrassegnate con un badge e visibili all\'amministratore IT"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index dd496c8083..e82973837b 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"דף %1$d מתוך %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"מסך הבית %1$d מתוך %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"מסך הבית חדש"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"פעיל"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ממוזער"</string> <string name="folder_opened" msgid="94695026776264709">"תיקייה פתוחה, <xliff:g id="WIDTH">%1$d</xliff:g> על <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"יש ללחוץ כדי לסגור את התיקייה"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"יש ללחוץ כדי לשמור שינוי שם"</string> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 9000081cfc..1e530cd3ad 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -135,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"ホーム画面の回転を許可"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"スマートフォンの向きに合わせます"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"横表示"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"スマートフォンを横表示にしてください"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"スマートフォンを横表示にします"</string> <string name="notification_dots_title" msgid="9062440428204120317">"通知ドット"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"ON"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"OFF"</string> @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"閉じる"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人用"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"仕事用"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"個人用アプリのタブ"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"仕事用アプリのタブ"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"仕事用アプリはバッジ付きで表示され、IT 管理者に公開されます"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string> diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index 2fd6b777db..4cd473b583 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"დახურვა"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"პირადი"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"სამსახური"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"პირადი აპების ჩანართი"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"სამსახურის აპების ჩანართი"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"სამსახურის აპები ბეჯით არის მონიშნული და ხილულია თქვენი IT ადმინისტრატორისთვის"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"გასაგებია"</string> diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index fee3a9a573..c60376b1cd 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%1$d бет, барлығы %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d негізгі экран, барлығы %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Жаңа негізгі экран беті"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Белсенді"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Кішірейтілген"</string> <string name="folder_opened" msgid="94695026776264709">"Қалта ашылды, <xliff:g id="WIDTH">%1$d</xliff:g> және <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Қалтаны жабу үшін түртіңіз"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Қайта атауды сақтау үшін түртіңіз"</string> diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index cc8539ea8c..5dbae5f890 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"ទំព័រ %1$d នៃ %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"អេក្រង់ដើម %1$d នៃ %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"ទំព័រអេក្រង់ដើមថ្មី"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"សកម្ម"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"បានបង្រួម"</string> <string name="folder_opened" msgid="94695026776264709">"បានបើកថត <xliff:g id="WIDTH">%1$d</xliff:g> ដោយ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ប៉ះ ដើម្បីបិទថត"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"ប៉ះដើម្បីរក្សាទុកឈ្មោះដែលបានប្តូរ"</string> @@ -190,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"បិទ"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"ផ្ទាល់ខ្លួន"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"ការងារ"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"ផ្ទាំងកម្មវិធីផ្ទាល់ខ្លួន"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"ផ្ទាំងកម្មវិធីការងារ"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"កម្រងព័ត៌មានការងារ"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"កម្មវិធីការងារត្រូវបានដាក់គ្រឿងសម្គាល់ ហើយអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកអាចមើលឃើញ"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"យល់ហើយ"</string> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index e588634199..24053c8bb5 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"페이지 %1$d/%2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"홈 화면 %1$d/%2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"새로운 홈 화면 페이지"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"활성"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"최소화"</string> <string name="folder_opened" msgid="94695026776264709">"폴더 열림(<xliff:g id="WIDTH">%1$d</xliff:g>X<xliff:g id="HEIGHT">%2$d</xliff:g>)"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"탭하여 폴더 닫기"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"탭하여 변경된 이름 저장"</string> diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index fb1675edc6..2ad0668e72 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ичинен %1$d барак"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Үй экраны %2$d ичинен %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Жаңы башкы экран барагы"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Жигердүү"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Кичирейтилди"</string> <string name="folder_opened" msgid="94695026776264709">"Фолдер ачылды, туурасы <xliff:g id="WIDTH">%1$d</xliff:g>, бийиктиги <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Куржунду жабуу үчүн таптаңыз"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Өзгөртүлгөн аталышын сактоо үчүн таптаңыз"</string> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 0ba127dd3e..e1b9b34177 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. lapa no %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Sākuma ekrāns: %1$d no %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Jauna sākuma ekrāna lapa"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktīva"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizēta"</string> <string name="folder_opened" msgid="94695026776264709">"Atvērta mape: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Pieskarieties, lai aizvērtu mapi."</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Pieskarieties, lai saglabātu jauno nosaukumu."</string> diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index ba119f78ca..8ab50b852e 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d од %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Екран на почетна страница %1$d од %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Нова страница на почетен екран"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Активно"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Минимизирано"</string> <string name="folder_opened" msgid="94695026776264709">"Отворена е папка, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Допрете за да ја затворите папката"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Допрете за да го зачувате преименувањето"</string> diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 2a2e050970..d6df3ac592 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"പേജ് %1$d / %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"ഹോം സ്ക്രീൻ %1$d / %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"പുതിയ ഹോം സ്ക്രീൻ പേജ്"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"സജീവം"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ചെറുതാക്കി"</string> <string name="folder_opened" msgid="94695026776264709">"ഫോൾഡർ തുറന്നു, <xliff:g id="WIDTH">%1$d</xliff:g> / <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ഫോൾഡർ അടയ്ക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"പേരുമാറ്റം സംരക്ഷിക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string> diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index ffe1b2cd6b..78032967d4 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d-н %1$d хуудас"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d-н Нүүр дэлгэц %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Шинэ үндсэн нүүр хуудас"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Идэвхтэй"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Жижгэрүүлсэн"</string> <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> <xliff:g id="HEIGHT">%2$d</xliff:g> фолдер нээгдэв"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Фолдерийг хаахын тулд дарна уу"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Шинэ нэрийг хадгалахын тулд дарна уу."</string> diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index b249150b30..b0cda7741d 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पेज"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string> <string name="workspace_new_page" msgid="257366611030256142">"नवीन होम स्क्रीन पेज"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"अॅक्टिव्ह"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"लहान केलेले"</string> <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डर बंद करण्यासाठी टॅप करा"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे सेव्ह करण्यासाठी टॅप करा"</string> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index 3585ec7044..c4d97d5056 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"Tutup"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"Peribadi"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"Tab apl peribadi"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"Tab apl kerja"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Apl kerja mempunyai lencana dan kelihatan kepada pentadbir IT anda"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string> diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 01168347ac..75e87f48e3 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"စာမျက်နှာ %1$d မှ %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"ပင်မစာမျက်နှာ %1$d မှ %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"သုံးနေသည်"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ချုံ့ထားသည်"</string> <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ဖိုင်တွဲကို ပိတ်ရန် တို့ပါ"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းရန် တို့ပါ"</string> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 47c6abbafd..d7497cd785 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d av %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Startside %1$d av %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Ny side på startskjermen"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimert"</string> <string name="folder_opened" msgid="94695026776264709">"Mappen er åpnet – <xliff:g id="WIDTH">%1$d</xliff:g> ganger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Trykk for å lukke mappen"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Trykk for å lagre det nye navnet"</string> diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index e451926c93..bbe8233a5e 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d को %1$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"होम स्क्रिन %1$d को %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"नयाँ होम स्क्रिन पृष्ठ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"सक्रिय"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"सानो पारिएको"</string> <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डरलाई बन्द गर्न ट्याप गर्नुहोस्"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनःनामाकरणलाई सुरक्षित गर्न ट्याप गर्नुहोस्"</string> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 75793b0836..971eee9d11 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -135,7 +135,7 @@ <string name="allow_rotation_title" msgid="7222049633713050106">"Draaien van startscherm toestaan"</string> <string name="allow_rotation_desc" msgid="8662546029078692509">"Als de telefoon gedraaid is"</string> <string name="landscape_mode_title" msgid="5138814555934843926">"Liggende modus"</string> - <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefoon instellen op liggende modus"</string> + <string name="landscape_mode_desc" msgid="7372569859592816793">"Stel telefoon in op liggende modus"</string> <string name="notification_dots_title" msgid="9062440428204120317">"Meldingsstipjes"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"Aan"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"Uit"</string> diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 98ccaf14e4..d5b87dc3b6 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"ମୋଟ %2$dରୁ %1$d ନମ୍ବର ପୃଷ୍ଠା"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dରୁ %1$d ହୋମ ସ୍କ୍ରିନ"</string> <string name="workspace_new_page" msgid="257366611030256142">"ନୂଆ ହୋମ ସ୍କ୍ରିନ ପେଜ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"ସକ୍ରିୟ"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ଛୋଟ କରାଯାଇଛି"</string> <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="HEIGHT">%2$d</xliff:g> / <xliff:g id="WIDTH">%1$d</xliff:g>ର ଫୋଲ୍ଡର ଖୋଲାଗଲା"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ଫୋଲ୍ଡର୍ ବନ୍ଦ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"ନାମ ବଦଳାଇବା ସେଭ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 3904473f7e..a9b089b30b 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"ਸਫ਼ਾ %2$d ਦਾ %1$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"ਹੋਮ ਸਕ੍ਰੀਨ %2$d ਦੀ %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"ਨਵਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਸਫ਼ਾ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"ਕਿਰਿਆਸ਼ੀਲ"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"ਛੋਟਾ ਕੀਤਾ ਗਿਆ"</string> <string name="folder_opened" msgid="94695026776264709">"ਫੋਲਡਰ ਖੋਲ੍ਹਿਆ, <xliff:g id="WIDTH">%1$d</xliff:g> ਬਾਇ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ਫੋਲਡਰ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"ਬਦਲੇ ਗਏ ਨਾਮ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index f7f71f4dc8..78604647a6 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Strona %1$d z %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekran główny %1$d z %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nowa strona ekranu głównego"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktywna"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Zminimalizowana"</string> <string name="folder_opened" msgid="94695026776264709">"Folder otwarty, <xliff:g id="WIDTH">%1$d</xliff:g> na <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Kliknij, by zamknąć folder"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Kliknij, by zapisać nową nazwę"</string> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index d0e11785d6..76e6bcfc34 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Tela inicial %1$d de %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Nova página na tela inicial"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Ativo"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizado"</string> <string name="folder_opened" msgid="94695026776264709">"Pasta aberta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Toque para fechar a pasta"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toque para salvar o novo nome"</string> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 9022d6fe66..035e8cda7b 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d din %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecranul de pornire %1$d din %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Pagină nouă pe ecranul de pornire"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Activă"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizată"</string> <string name="folder_opened" msgid="94695026776264709">"Dosar deschis, <xliff:g id="WIDTH">%1$d</xliff:g> pe <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Atinge pentru a închide dosarul"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Atinge pentru a salva noul nume"</string> diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index 7e64c0d933..db885f4533 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$d හි %1$d පිටුව"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"මුල් පිටු තිරය %2$d හි %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"නව මුල් පිටුව"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"සක්රිය"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"කුඩා කරන ලදි"</string> <string name="folder_opened" msgid="94695026776264709">"ෆෝල්ඩරය විවෘත විය, <xliff:g id="WIDTH">%1$d</xliff:g> හි <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ෆෝල්ඩරය වැසීමට තට්ටු කරන්න"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"යළි නම් කිරීම සුරැකීමට තට්ටු කරන්න"</string> diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index ac47b0a2d1..21095385b9 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Faqja: %1$d nga gjithsej %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekrani bazë: %1$d nga gjithsej %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Faqja e ekranit të ri kryesor"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktiv"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimizuar"</string> <string name="folder_opened" msgid="94695026776264709">"Dosja u hap, <xliff:g id="WIDTH">%1$d</xliff:g> me <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Trokit për të mbyllur dosjen"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Trokit për të ruajtur riemërtimin"</string> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 7c676e92b9..f2d0ed91e1 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Sidan %1$d av %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskärmen %1$d av %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Ny sida på startskärmen"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktivt"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Minimerat"</string> <string name="folder_opened" msgid="94695026776264709">"Mappen är öppen, <xliff:g id="WIDTH">%1$d</xliff:g> gånger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Tryck för att stänga mappen"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tryck för att spara namnändringen"</string> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 06ba9816b4..6a5aa133be 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Ukurasa%1$d wa %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrini ya mwanzo %1$d ya %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Ukurasa mpya wa skrini ya kwanza"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Inatumika"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Imepunguzwa"</string> <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Gusa ili ufunge folda"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Gusa ili ubadilishe jina"</string> diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 4bb86da55c..890e2804ef 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"பக்கம் %1$d / %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"புதிய முகப்புத் திரை பக்கம்"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"செயலில் உள்ளது"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"சிறிதாக்கப்பட்டது"</string> <string name="folder_opened" msgid="94695026776264709">"திறக்கப்பட்ட ஃபோல்டர், <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"ஃபோல்டரை மூட, தட்டவும்"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"மாற்றிய பெயரைச் சேமிக்க, தட்டவும்"</string> diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index cd4f456af6..63d25f7472 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -188,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"మూసివేస్తుంది"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"వ్యక్తిగతం"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"వర్క్"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"వ్యక్తిగత యాప్ల ట్యాబ్"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"వర్క్ యాప్ల ట్యాబ్"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"వర్క్ యాప్లకు బ్యాడ్జ్ ఉంటుంది, అవి మీ IT అడ్మిన్కు కనిపిస్తాయి"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"అర్థమైంది"</string> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index b8a0df4cb6..27b171bd44 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Pahina %1$d ng %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d ng %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Bagong page ng home screen"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Aktibo"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Na-minimize"</string> <string name="folder_opened" msgid="94695026776264709">"Binuksan ang folder, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"I-tap upang isara ang folder"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"I-tap upang i-save ang bagong pangalan"</string> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 5bd7c52280..a1bc2b7571 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Sayfa %1$d / %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Ana ekran %1$d / %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Yeni ana ekran sayfası"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Etkin"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Simge durumuna küçültülmüş"</string> <string name="folder_opened" msgid="94695026776264709">"Klasör açıldı, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Klasörü kapatmak için dokunun"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Yeni adın kaydedilmesi için dokunun"</string> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 798c5672a1..389dd75dea 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Сторінка %1$d з %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Головний екран %1$d з %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Нова сторінка головного екрана"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Додаток активний"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Додаток згорнуто"</string> <string name="folder_opened" msgid="94695026776264709">"Папку відкрито (<xliff:g id="WIDTH">%1$d</xliff:g> х <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Торкніться, щоб закрити папку"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Торкніться, щоб зберегти зміни"</string> diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index ec5129d6ee..724cbcd8b3 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"صفحہ %1$d از %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"ہوم اسکرین %1$d از %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"نیا ہوم اسکرین صفحہ"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"فعال"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"کم کر دیا گیا"</string> <string name="folder_opened" msgid="94695026776264709">"فولڈر کھولا گیا، <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"فولڈر کو بند کرنے کیلئے تھپتھپائیں"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"نام کی تبدیلی محفوظ کرنے کیلئے تھپتھپائیں"</string> @@ -190,10 +188,8 @@ <string name="accessibility_close" msgid="2277148124685870734">"بند کریں"</string> <string name="all_apps_personal_tab" msgid="4190252696685155002">"ذاتی"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string> - <!-- no translation found for all_apps_personal_tab_content_description (6286808898381807242) --> - <skip /> - <!-- no translation found for all_apps_work_tab_content_description (3835637212347968316) --> - <skip /> + <string name="all_apps_personal_tab_content_description" msgid="6286808898381807242">"ذاتی ایپس کا ٹیب"</string> + <string name="all_apps_work_tab_content_description" msgid="3835637212347968316">"ورک ایپس کا ٹیب"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"ورک ایپس پر بَیج لگا ہوتا ہے اور آپ کا IT منتظم انہیں دیکھ سکتا ہے"</string> <string name="work_profile_edu_accept" msgid="6069788082535149071">"سمجھ آ گئی"</string> diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 48068d64dc..67c96ef443 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Yangi bosh ekran sahifasi"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Faol"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Yigʻilgan"</string> <string name="folder_opened" msgid="94695026776264709">"Jild ochildi, <xliff:g id="WIDTH">%1$d</xliff:g> ga <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Jildni yopish uchun ustiga bosing"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"O‘zgarishni saqlash uchun ustiga bosing"</string> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 5b8809948d..3074222cf9 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Trang %1$d / %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Màn hình chính %1$d / %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Trang màn hình chính mới"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Đang hoạt động"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Đã thu nhỏ"</string> <string name="folder_opened" msgid="94695026776264709">"Đã mở thư mục, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Nhấn để đóng thư mục"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Nhấn để lưu đổi tên"</string> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 7b51d1d45d..bed166c1a5 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"第%1$d页,共%2$d页"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"主屏幕:第%1$d屏,共%2$d屏"</string> <string name="workspace_new_page" msgid="257366611030256142">"主屏幕新页面"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"活跃"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"已最小化"</string> <string name="folder_opened" msgid="94695026776264709">"文件夹已打开,大小为<xliff:g id="WIDTH">%1$d</xliff:g>×<xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"点按可关闭文件夹"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"点按可保存新名称"</string> diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 0dd1801922..07c6386426 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"主畫面 %1$d,共 %2$d 個"</string> <string name="workspace_new_page" msgid="257366611030256142">"新主畫面頁面"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"運作中"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"已縮到最小"</string> <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"輕按即可關閉資料夾"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"輕按即可儲存新名稱"</string> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 424939b528..c3ffbc16e6 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"主畫面:第 %1$d 頁,共 %2$d 頁"</string> <string name="workspace_new_page" msgid="257366611030256142">"新的主畫面頁面"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"運作中"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"最小化"</string> <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"輕觸即可關閉資料夾"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"輕觸即可儲存新名稱"</string> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 918b7ca165..d08a21efee 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -117,10 +117,8 @@ <string name="default_scroll_format" msgid="7475544710230993317">"Ikhasi elingu-%1$d kwangu-%2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Isikrini sasekhaya esingu-%1$d se-%2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"Ikhasi elisha lesikrini sasekhaya"</string> - <!-- no translation found for app_running_state_description (5645053189564740904) --> - <skip /> - <!-- no translation found for app_minimized_state_description (710740620044902509) --> - <skip /> + <string name="app_running_state_description" msgid="5645053189564740904">"Kuyasebenza"</string> + <string name="app_minimized_state_description" msgid="710740620044902509">"Kuncishisiwe"</string> <string name="folder_opened" msgid="94695026776264709">"Ifolda ivuliwe, <xliff:g id="WIDTH">%1$d</xliff:g> nge-<xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="4625795376335528256">"Thepa ukuze uvale ifolda"</string> <string name="folder_tap_to_rename" msgid="4017685068016979677">"Thepha ukuze ulondoloze ukuqamba kabusha"</string> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index a22f943fd4..1ecac338a4 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -19,6 +19,7 @@ <!-- Attributes used for launcher theme --> <attr name="allAppsScrimColor" format="color" /> + <attr name="allAppsScrimColorOverBlur" format="color" /> <attr name="allappsHeaderProtectionColor" format="color" /> <attr name="allAppsNavBarScrimColor" format="color" /> <attr name="allAppsTheme" format="reference" /> diff --git a/res/values/config.xml b/res/values/config.xml index d65580caf0..3b48c9eddd 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -224,4 +224,7 @@ of the same name in SystemUI. --> <string-array name="config_appsSupportMultiInstancesSplit"> </string-array> + + <!-- Used to differentiate between desktop and non-desktop devices. --> + <bool name="desktop_form_factor">false</bool> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index cc740a5668..a626097ea3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -323,6 +323,8 @@ <string name="edit_home_screen">Edit Home Screen</string> <!-- Text for settings button [CHAR LIMIT=20]--> <string name="settings_button_text">Home settings</string> + <!-- Text for app menu button [CHAR LIMIT=30]--> + <string name="all_apps_home_screen">Apps</string> <!-- Message shown when a feature is disabled by the administrator --> <string name="msg_disabled_by_admin">Disabled by your admin</string> @@ -469,6 +471,12 @@ <!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] --> <string name="action_deep_shortcut">Shortcut Menu</string> + <!-- Accessibility name for the app widget resize frame. --> + <string name="widget_frame_name">Widget Resize Frame for <xliff:g id="string" example="Clock">%1$s</xliff:g></string> + + <!-- Accessibility action to close the widget resize frame. [CHAR_LIMIT=30] --> + <string name="action_close">Close</string> + <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] --> <string name="action_dismiss_notification">Dismiss</string> @@ -541,4 +549,5 @@ <string name="ps_add_button_label">Install</string> <!-- Content description for install app icon --> <string name="ps_add_button_content_description">Install apps to Private Space</string> + <string name="ps_app_content_description">Add files and more to Private Space</string> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index 04421c0ed2..39206d3428 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -40,6 +40,7 @@ <style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme"> <item name="android:textColorSecondary">#DE000000</item> <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item> + <item name="allAppsScrimColorOverBlur">#33000000</item> <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerHighest</item> <item name="allAppsNavBarScrimColor">#66FFFFFF</item> <item name="popupColorPrimary">@color/popup_color_primary_light</item> @@ -114,6 +115,7 @@ <item name="android:colorControlHighlight">#19FFFFFF</item> <item name="android:colorPrimary">#FF212121</item> <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item> + <item name="allAppsScrimColorOverBlur">#52000000</item> <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerLow</item> <item name="allAppsNavBarScrimColor">#80000000</item> <item name="popupColorPrimary">@color/popup_color_primary_dark</item> diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index b51e850c04..213d88f852 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -216,6 +216,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater() .inflate(R.layout.app_widget_resize_frame, dl, false); frame.setupForWidget(widget, cellLayout, dl); + // Save widget item info as tag on resize frame; so that, the accessibility delegate can + // attach actions that typically happen on widget (e.g. resize, move) also on the resize + // frame. + frame.setTag(widget.getTag()); + frame.setAccessibilityDelegate(launcher.getAccessibilityDelegate()); + frame.setContentDescription(launcher.asContext().getString(R.string.widget_frame_name, + widget.getContentDescription())); ((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true; dl.addView(frame); @@ -235,6 +242,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O } } + /** + * Retrieves the view where accessibility actions happen. + */ + public View getViewForAccessibility() { + return mWidgetView; + } + private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) { mCellLayout = cellLayout; diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 783e82cae9..30e3a2b577 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -26,6 +26,7 @@ import static com.android.launcher3.BubbleTextView.RunningAppState.NOT_RUNNING; import static com.android.launcher3.BubbleTextView.RunningAppState.MINIMIZED; import static com.android.launcher3.Flags.enableContrastTiles; import static com.android.launcher3.Flags.enableCursorHoverStates; +import static com.android.launcher3.allapps.AlphabeticalAppsList.PRIVATE_SPACE_PACKAGE; import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon; import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE; import static com.android.launcher3.icons.BitmapInfo.FLAG_SKIP_USER_BADGE; @@ -104,6 +105,7 @@ import com.android.launcher3.views.FloatingIconViewCompanion; import java.text.NumberFormat; import java.util.HashMap; import java.util.Locale; +import java.util.Objects; /** * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan @@ -589,7 +591,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } private void setNonPendingIcon(ItemInfoWithIcon info) { - int flags = shouldUseTheme() ? FLAG_THEMED : info.bitmap.creationFlags; + // Set nonPendingIcon acts as a restart which should refresh the flag state when applicable. + int flags = Objects.equals(info.getTargetPackage(), PRIVATE_SPACE_PACKAGE) + ? info.bitmap.creationFlags : shouldUseTheme() ? FLAG_THEMED : 0; // Remove badge on icons smaller than 48dp. if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) { flags |= FLAG_NO_BADGE; diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index c85ca49c43..090208a33c 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -30,8 +30,8 @@ import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURC import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp; import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat; import static com.android.wm.shell.Flags.enableBubbleBar; -import static com.android.wm.shell.Flags.enableTinyTaskbar; import static com.android.wm.shell.Flags.enableBubbleBarOnPhones; +import static com.android.wm.shell.Flags.enableTinyTaskbar; import android.annotation.SuppressLint; import android.content.Context; @@ -508,9 +508,11 @@ public class DeviceProfile { bottomSheetOpenDuration = res.getInteger(R.integer.config_bottomSheetOpenDuration); bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration); - if (isTablet) { + if (shouldShowAllAppsOnSheet()) { bottomSheetWorkspaceScale = workspaceContentScale; - if (isMultiDisplay) { + if (Flags.allAppsBlur()) { + bottomSheetDepth = 2f; + } else if (isMultiDisplay) { // TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth // when screen recorder bug is fixed. if (enableScalingRevealHomeAnimation()) { @@ -1830,10 +1832,17 @@ public class DeviceProfile { workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace; } int paddingTop = workspaceTopPadding + (mIsScalableGrid ? 0 : edgeMarginPx); - // On isFixedLandscapeMode on phones we already have padding because of the camera hole - int paddingSide = inv.isFixedLandscape ? 0 : desiredWorkspaceHorizontalMarginPx; + int paddingLeft = desiredWorkspaceHorizontalMarginPx; + int paddingRight = desiredWorkspaceHorizontalMarginPx; - padding.set(paddingSide, paddingTop, paddingSide, paddingBottom); + // In fixed Landscape we don't need padding on the side next to the cutout because + // the cutout is already adding padding to all of Launcher, we only need on the other + // side + if (inv.isFixedLandscape) { + paddingLeft = isSeascape() ? desiredWorkspaceHorizontalMarginPx : 0; + paddingRight = isSeascape() ? 0 : desiredWorkspaceHorizontalMarginPx; + } + padding.set(paddingLeft, paddingTop, paddingRight, paddingBottom); } insetPadding(workspacePadding, cellLayoutPaddingPx); } @@ -1931,7 +1940,24 @@ public class DeviceProfile { hotseatBarPadding.set(mHotseatBarWorkspaceSpacePx, paddingTop, mInsets.right + mHotseatBarEdgePaddingPx, paddingBottom); } - } else if (isTaskbarPresent || inv.isFixedLandscape) { + } else if (inv.isFixedLandscape) { + // Center the QSB vertically with hotseat + int hotseatBarBottomPadding = getHotseatBarBottomPadding(); + int hotseatPlusQSBWidth = getHotseatRequiredWidth(); + int qsbWidth = getAdditionalQsbSpace(); + int availableWidthPxForHotseat = availableWidthPx - Math.abs(workspacePadding.width()) + - Math.abs(cellLayoutPaddingPx.width()); + int remainingSpaceOnSide = (availableWidthPxForHotseat - hotseatPlusQSBWidth) / 2; + + hotseatBarPadding.set( + (remainingSpaceOnSide + qsbWidth) + mInsets.left + workspacePadding.left + + cellLayoutPaddingPx.left, + hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx, + remainingSpaceOnSide + mInsets.right + workspacePadding.right + + cellLayoutPaddingPx.right, + hotseatBarBottomPadding + ); + } else if (isTaskbarPresent) { // Center the QSB vertically with hotseat int hotseatBarBottomPadding = getHotseatBarBottomPadding(); int hotseatBarTopPadding = @@ -1950,11 +1976,6 @@ public class DeviceProfile { } startSpacing += getAdditionalQsbSpace(); - if (inv.isFixedLandscape) { - endSpacing += mInsets.right; - startSpacing += mInsets.left; - } - hotseatBarPadding.top = hotseatBarTopPadding; hotseatBarPadding.bottom = hotseatBarBottomPadding; boolean isRtl = Utilities.isRtl(context.getResources()); @@ -2164,7 +2185,8 @@ public class DeviceProfile { } public boolean isSeascape() { - return rotationHint == Surface.ROTATION_270 && isVerticalBarLayout(); + return rotationHint == Surface.ROTATION_270 + && (isVerticalBarLayout() || inv.isFixedLandscape); } public boolean shouldFadeAdjacentWorkspaceScreens() { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 289f175aa9..5c9392d69d 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1472,8 +1472,7 @@ public class Launcher extends StatefulActivity<LauncherState> // Adding a shortcut to a Folder. FolderIcon folderIcon = findFolderIcon(container); if (folderIcon != null) { - FolderInfo folderInfo = (FolderInfo) folderIcon.getTag(); - folderInfo.add(info, args.rank, false); + folderIcon.getFolder().addFolderContent(info, args.rank, false); } else { Log.e(TAG, "Could not find folder with id " + container + " to add shortcut."); } @@ -1792,7 +1791,6 @@ public class Launcher extends StatefulActivity<LauncherState> SettingsCache.INSTANCE.get(this).unregister(TOUCHPAD_NATURAL_SCROLLING, mNaturalScrollingChangedListener); ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener); - mWorkspace.removeFolderListeners(); PluginManagerWrapper.INSTANCE.get(this).removePluginListener(this); mModel.removeCallbacks(this); @@ -2053,9 +2051,10 @@ public class Launcher extends StatefulActivity<LauncherState> @Nullable final String reason) { if (itemInfo instanceof WorkspaceItemInfo) { View collectionIcon = mWorkspace.getViewByItemId(itemInfo.container); - if (collectionIcon instanceof FolderIcon) { + if (collectionIcon instanceof FolderIcon folderIcon) { // Remove the shortcut from the folder before removing it from launcher - ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true); + Folder folder = folderIcon.getFolder(); + folder.removeFolderContent(true, itemInfo); } else if (collectionIcon instanceof AppPairIcon appPairIcon) { removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb, "removing app pair because one of its member apps was removed"); @@ -2066,9 +2065,6 @@ public class Launcher extends StatefulActivity<LauncherState> getModelWriter().deleteItemFromDatabase(itemInfo, reason); } } else if (itemInfo instanceof CollectionInfo ci) { - if (v instanceof FolderIcon) { - ((FolderIcon) v).removeListeners(); - } mWorkspace.removeWorkspaceItem(v); if (deleteFromDb) { getModelWriter().deleteCollectionAndContentsFromDatabase(ci); diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt index add0ad843c..557ad67386 100644 --- a/src/com/android/launcher3/LauncherModel.kt +++ b/src/com/android/launcher3/LauncherModel.kt @@ -28,11 +28,12 @@ import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.icons.IconCache import com.android.launcher3.model.AddWorkspaceItemsTask import com.android.launcher3.model.AllAppsList -import com.android.launcher3.model.BaseLauncherBinder +import com.android.launcher3.model.BaseLauncherBinder.BaseLauncherBinderFactory import com.android.launcher3.model.BgDataModel import com.android.launcher3.model.CacheDataUpdatedTask import com.android.launcher3.model.ItemInstallQueue import com.android.launcher3.model.LoaderTask +import com.android.launcher3.model.LoaderTask.LoaderTaskFactory import com.android.launcher3.model.ModelDbController import com.android.launcher3.model.ModelDelegate import com.android.launcher3.model.ModelInitializer @@ -43,6 +44,8 @@ import com.android.launcher3.model.PackageUpdatedTask import com.android.launcher3.model.ReloadStringCacheTask import com.android.launcher3.model.ShortcutsChangedTask import com.android.launcher3.model.UserLockStateChangedTask +import com.android.launcher3.model.UserManagerState +import com.android.launcher3.model.WorkspaceItemSpaceFinder import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.pm.UserCache @@ -70,30 +73,24 @@ class LauncherModel @Inject constructor( @ApplicationContext private val context: Context, - private val appProvider: Provider<LauncherAppState>, + private val taskControllerProvider: Provider<ModelTaskController>, private val iconCache: IconCache, private val prefs: LauncherPrefs, private val installQueue: ItemInstallQueue, - appFilter: AppFilter, @Named("ICONS_DB") dbFileName: String?, initializer: ModelInitializer, lifecycle: DaggerSingletonTracker, val modelDelegate: ModelDelegate, + private val mBgAllAppsList: AllAppsList, + private val mBgDataModel: BgDataModel, + private val loaderFactory: LoaderTaskFactory, + private val binderFactory: BaseLauncherBinderFactory, + private val spaceFinderFactory: Provider<WorkspaceItemSpaceFinder>, + val modelDbController: ModelDbController, ) { private val mCallbacksList = ArrayList<BgDataModel.Callbacks>(1) - // < only access in worker thread > - private val mBgAllAppsList = AllAppsList(iconCache, appFilter) - - /** - * All the static data should be accessed on the background thread, A lock should be acquired on - * this object when accessing any data from this model. - */ - private val mBgDataModel = BgDataModel() - - val modelDbController = ModelDbController(context) - private val mLock = Any() private var mLoaderTask: LoaderTask? = null @@ -139,7 +136,7 @@ constructor( /** Adds the provided items to the workspace. */ fun addAndBindAddedWorkspaceItems(itemList: List<Pair<ItemInfo?, Any?>?>) { callbacks.forEach { it.preAddApps() } - enqueueModelUpdateTask(AddWorkspaceItemsTask(itemList)) + enqueueModelUpdateTask(AddWorkspaceItemsTask(itemList, spaceFinderFactory.get())) } fun getWriter( @@ -299,13 +296,7 @@ constructor( // Clear any pending bind-runnables from the synchronized load process. callbacksList.forEach { MAIN_EXECUTOR.execute(it::clearPendingBinds) } - val launcherBinder = - BaseLauncherBinder( - appProvider.get(), - mBgDataModel, - mBgAllAppsList, - callbacksList, - ) + val launcherBinder = binderFactory.createBinder(callbacksList) if (bindDirectly) { // Divide the set of loaded items into those that we are binding synchronously, // and everything else that is to be bound normally (asynchronously). @@ -317,14 +308,7 @@ constructor( launcherBinder.bindWidgets() return true } else { - val task = - LoaderTask( - appProvider.get(), - mBgAllAppsList, - mBgDataModel, - this.modelDelegate, - launcherBinder, - ) + val task = loaderFactory.newLoaderTask(launcherBinder, UserManagerState()) mLoaderTask = task // Always post the loader task, instead of running directly @@ -425,7 +409,7 @@ constructor( /** Called when the labels for the widgets has updated in the icon cache. */ fun onWidgetLabelsUpdated(updatedPackages: HashSet<String?>, user: UserHandle) { enqueueModelUpdateTask { taskController, dataModel, _ -> - dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, appProvider.get()) + dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user) taskController.bindUpdatedWidgets(dataModel) } } @@ -439,17 +423,7 @@ constructor( // Loader has not yet run. return@execute } - task.execute( - ModelTaskController( - appProvider.get(), - mBgDataModel, - mBgAllAppsList, - this, - MAIN_EXECUTOR, - ), - mBgDataModel, - mBgAllAppsList, - ) + task.execute(taskControllerProvider.get(), mBgDataModel, mBgAllAppsList) } } @@ -476,7 +450,7 @@ constructor( fun refreshAndBindWidgetsAndShortcuts(packageUser: PackageUserKey?) { enqueueModelUpdateTask { taskController, dataModel, _ -> - dataModel.widgetsModel.update(taskController.app, packageUser) + dataModel.widgetsModel.update(packageUser) taskController.bindUpdatedWidgets(dataModel) } } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 03ecf14ef6..acb2b48aeb 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -26,13 +26,13 @@ import android.content.ContentUris; import android.content.ContentValues; import android.content.pm.PackageManager; import android.database.Cursor; -import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Process; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.ModelDbController; @@ -74,24 +74,20 @@ public class LauncherProvider extends ContentProvider { @Override public String getType(Uri uri) { - SqlArguments args = new SqlArguments(uri, null, null); - if (TextUtils.isEmpty(args.where)) { - return "vnd.android.cursor.dir/" + args.table; + if (TextUtils.isEmpty(parseUri(uri, null, null).first)) { + return "vnd.android.cursor.dir/" + Favorites.TABLE_NAME; } else { - return "vnd.android.cursor.item/" + args.table; + return "vnd.android.cursor.item/" + Favorites.TABLE_NAME; } } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - SqlArguments args = new SqlArguments(uri, selection, selectionArgs); - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - qb.setTables(args.table); - + Pair<String, String[]> args = parseUri(uri, selection, selectionArgs); Cursor[] result = new Cursor[1]; executeControllerTask(controller -> { - result[0] = controller.query(args.table, projection, args.where, args.args, sortOrder); + result[0] = controller.query(projection, args.first, args.second, sortOrder); return 0; }); return result[0]; @@ -108,7 +104,7 @@ public class LauncherProvider extends ContentProvider { // attempt allocate and bind the widget. Integer itemType = values.getAsInteger(Favorites.ITEM_TYPE); if (itemType != null - && itemType.intValue() == Favorites.ITEM_TYPE_APPWIDGET + && itemType == Favorites.ITEM_TYPE_APPWIDGET && !values.containsKey(Favorites.APPWIDGET_ID)) { ComponentName cn = ComponentName.unflattenFromString( @@ -135,8 +131,7 @@ public class LauncherProvider extends ContentProvider { } } - SqlArguments args = new SqlArguments(uri); - return controller.insert(args.table, values); + return controller.insert(values); }); return rowId < 0 ? null : ContentUris.withAppendedId(uri, rowId); @@ -144,14 +139,14 @@ public class LauncherProvider extends ContentProvider { @Override public int delete(Uri uri, String selection, String[] selectionArgs) { - SqlArguments args = new SqlArguments(uri, selection, selectionArgs); - return executeControllerTask(c -> c.delete(args.table, args.where, args.args)); + Pair<String, String[]> args = parseUri(uri, selection, selectionArgs); + return executeControllerTask(c -> c.delete(args.first, args.second)); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - SqlArguments args = new SqlArguments(uri, selection, selectionArgs); - return executeControllerTask(c -> c.update(args.table, values, args.where, args.args)); + Pair<String, String[]> args = parseUri(uri, selection, selectionArgs); + return executeControllerTask(c -> c.update(values, args.first, args.second)); } @Override @@ -209,35 +204,24 @@ public class LauncherProvider extends ContentProvider { } } - static class SqlArguments { - public final String table; - public final String where; - public final String[] args; - - SqlArguments(Uri url, String where, String[] args) { - if (url.getPathSegments().size() == 1) { - this.table = url.getPathSegments().get(0); - this.where = where; - this.args = args; - } else if (url.getPathSegments().size() != 2) { - throw new IllegalArgumentException("Invalid URI: " + url); - } else if (!TextUtils.isEmpty(where)) { - throw new UnsupportedOperationException("WHERE clause not supported: " + url); - } else { - this.table = url.getPathSegments().get(0); - this.where = "_id=" + ContentUris.parseId(url); - this.args = null; + /** + * Parses the uri and returns the where and arg clause. + * + * Note: This should be called on the binder thread (before posting on any executor) so that + * any parsing error gets propagated to the caller. + */ + private static Pair<String, String[]> parseUri(Uri url, String where, String[] args) { + switch (url.getPathSegments().size()) { + case 1 -> { + return Pair.create(where, args); } - } - - SqlArguments(Uri url) { - if (url.getPathSegments().size() == 1) { - table = url.getPathSegments().get(0); - where = null; - args = null; - } else { - throw new IllegalArgumentException("Invalid URI: " + url); + case 2 -> { + if (!TextUtils.isEmpty(where)) { + throw new UnsupportedOperationException("WHERE clause not supported: " + url); + } + return Pair.create("_id=" + ContentUris.parseId(url), null); } + default -> throw new IllegalArgumentException("Invalid URI: " + url); } } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 9a9bc1d97e..d6ae3a6335 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -100,6 +100,7 @@ import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.function.Predicate; /** @@ -276,8 +277,12 @@ public final class Utilities { */ public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) { sMatrix.reset(); + //TODO(b/307488755) when implemented this check should be removed + if (!Objects.equals(descendant.getWindowId(), root.getWindowId())) { + return; + } View v = descendant; - while(v != root) { + while (v != root) { sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY()); sMatrix.postConcat(v.getMatrix()); sMatrix.postTranslate(v.getLeft(), v.getTop()); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6ed183ab23..59f84ab891 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -137,7 +137,6 @@ import java.util.Iterator; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * The workspace is a wide area with a wallpaper and a finite number of pages. @@ -659,7 +658,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } // Remove the pages and clear the screen models - removeFolderListeners(); removeAllViews(); mScreenOrder.clear(); mWorkspaceScreens.clear(); @@ -1914,7 +1912,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> boolean aboveShortcut = Folder.willAccept(dropOverView.getTag()) && ((ItemInfo) dropOverView.getTag()).container != CONTAINER_HOTSEAT_PREDICTION; - boolean willBecomeShortcut = Folder.willAcceptItemType(info.itemType); + boolean willBecomeShortcut = FolderInfo.willAcceptItemType(info.itemType); return (aboveShortcut && willBecomeShortcut); } @@ -1994,8 +1992,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale); } else { fi.prepareCreateAnimation(v); - fi.addItem(destInfo); - fi.addItem(sourceInfo); + fi.getFolder().addFolderContent(destInfo); + fi.getFolder().addFolderContent(sourceInfo); } return true; } @@ -3209,21 +3207,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> }); } - /** - * Removes all folder listeners - */ - public void removeFolderListeners() { - mapOverItems(new ItemOperator() { - @Override - public boolean evaluate(ItemInfo info, View view) { - if (view instanceof FolderIcon) { - ((FolderIcon) view).removeListeners(); - } - return false; - } - }); - } - public boolean isDropEnabled() { return true; } @@ -3349,15 +3332,15 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> if (child instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) child); } - } else if (child instanceof FolderIcon) { + } else if (child instanceof FolderIcon folderIcon) { FolderInfo folderInfo = (FolderInfo) info; - List<ItemInfo> matches = folderInfo.getContents().stream() + ItemInfo[] matches = folderInfo.getContents().stream() .filter(matcher) - .collect(Collectors.toList()); - if (!matches.isEmpty()) { - folderInfo.removeAll(matches, false); - if (((FolderIcon) child).getFolder().isOpen()) { - ((FolderIcon) child).getFolder().close(false /* animate */); + .toArray(ItemInfo[]::new); + if (matches.length > 0) { + folderIcon.getFolder().removeFolderContent(false, matches); + if (folderIcon.getFolder().isOpen()) { + folderIcon.getFolder().close(false /* animate */); } } } else if (info instanceof AppPairInfo api) { diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index 78b53a96bd..df34ccf090 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -25,6 +25,7 @@ import android.view.accessibility.AccessibilityEvent; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.BubbleTextView; import com.android.launcher3.ButtonDropTarget; import com.android.launcher3.CellLayout; @@ -82,6 +83,7 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace; protected static final int RESIZE = R.id.action_resize; public static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts; + public static final int CLOSE = R.id.action_close; public LauncherAccessibilityDelegate(Launcher launcher) { super(launcher); @@ -104,6 +106,8 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau RESIZE, R.string.action_resize, KeyEvent.KEYCODE_R)); mActions.put(DEEP_SHORTCUTS, new LauncherAction(DEEP_SHORTCUTS, R.string.action_deep_shortcut, KeyEvent.KEYCODE_S)); + mActions.put(CLOSE, new LauncherAction(CLOSE, + R.string.action_close, KeyEvent.KEYCODE_X)); } private static boolean isNotInShortcutMenu(@Nullable View view) { @@ -137,6 +141,10 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau } } + if (host instanceof AppWidgetResizeFrame) { + out.add(mActions.get(CLOSE)); + } + if (supportAddToWorkSpace(item)) { out.add(mActions.get(ADD_TO_WORKSPACE)); } @@ -183,22 +191,28 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau } return dragCondition != null; } else if (action == MOVE) { - return beginAccessibleDrag(host, item, fromKeyboard); + final View itemView = (host instanceof AppWidgetResizeFrame) + ? ((AppWidgetResizeFrame) host).getViewForAccessibility() + : host; + return beginAccessibleDrag(itemView, item, fromKeyboard); } else if (action == ADD_TO_WORKSPACE) { return addToWorkspace(item, true /*accessibility*/, null /*finishCallback*/); } else if (action == MOVE_TO_WORKSPACE) { return moveToWorkspace(item); } else if (action == RESIZE) { + final View itemView = (host instanceof AppWidgetResizeFrame) + ? ((AppWidgetResizeFrame) host).getViewForAccessibility() + : host; final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item; - List<OptionItem> actions = getSupportedResizeActions(host, info); + List<OptionItem> actions = getSupportedResizeActions(itemView, info); Rect pos = new Rect(); - mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos); + mContext.getDragLayer().getDescendantRectRelativeToSelf(itemView, pos); ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false); popup.requestFocus(); popup.addOnCloseCallback(() -> { - host.requestFocus(); - host.sendAccessibilityEvent(TYPE_VIEW_FOCUSED); - host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null); + itemView.requestFocus(); + itemView.sendAccessibilityEvent(TYPE_VIEW_FOCUSED); + itemView.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null); AbstractFloatingView.closeOpenViews(mContext, /* animate= */ false, AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME); }); @@ -208,6 +222,11 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau : (host instanceof BubbleTextHolder ? ((BubbleTextHolder) host).getBubbleText() : null); return btv != null && PopupContainerWithArrow.showForIcon(btv) != null; + } else if (action == CLOSE) { + if (host instanceof AppWidgetResizeFrame) { + AbstractFloatingView.closeOpenViews(mContext, /* animate= */ false, + AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME); + } } else { for (ButtonDropTarget dropTarget : mContext.getDropTargetBar().getDropTargets()) { if (dropTarget.supportsAccessibilityDrop(item, host) @@ -222,6 +241,10 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau private List<OptionItem> getSupportedResizeActions(View host, LauncherAppWidgetInfo info) { List<OptionItem> actions = new ArrayList<>(); + if (host instanceof AppWidgetResizeFrame) { + return getSupportedResizeActions( + ((AppWidgetResizeFrame) host).getViewForAccessibility(), info); + } AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo(); if (providerInfo == null) { return actions; @@ -496,7 +519,7 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau Folder folder = Folder.getOpen(mContext); folder.close(true); WorkspaceItemInfo info = (WorkspaceItemInfo) item; - folder.getInfo().remove(info, false); + folder.removeFolderContent(false, info); final int[] coordinates = new int[2]; final int screenId = findSpaceOnWorkspace(item, coordinates); diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index fafa60bf6d..f60896eb6d 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -181,6 +181,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> private ScrimView mScrimView; private int mHeaderColor; private int mBottomSheetBackgroundColor; + private float mBottomSheetBackgroundAlpha = 1f; private int mTabsProtectionAlpha; @Nullable private AllAppsTransitionController mAllAppsTransitionController; @@ -311,7 +312,17 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 0, 0 // Bottom left }; - mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim); + if (Flags.allAppsBlur()) { + int resId = Utilities.isDarkTheme(getContext()) + ? android.R.color.system_accent1_800 : android.R.color.system_accent1_100; + int layerAbove = ColorUtils.setAlphaComponent(getResources().getColor(resId, null), + (int) (0.4f * 255)); + int layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.1f * 255)); + mBottomSheetBackgroundColor = ColorUtils.compositeColors(layerAbove, layerBelow); + } else { + mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim); + } + mBottomSheetBackgroundAlpha = Color.alpha(mBottomSheetBackgroundColor) / 255.0f; updateBackgroundVisibility(mActivityContext.getDeviceProfile()); mSearchUiManager.initializeSearch(this); } @@ -1152,7 +1163,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> if (!grid.isVerticalBarLayout() || FeatureFlags.enableResponsiveWorkspace()) { int topPadding = grid.allAppsPadding.top; - if (isSearchBarFloating() && !grid.isTablet) { + if (isSearchBarFloating() && !grid.shouldShowAllAppsOnSheet()) { topPadding += getResources().getDimensionPixelSize( R.dimen.all_apps_additional_top_padding_floating_search); } @@ -1401,7 +1412,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> // Draw full background panel for tablets. if (hasBottomSheet) { mHeaderPaint.setColor(mBottomSheetBackgroundColor); - mHeaderPaint.setAlpha(255); + mHeaderPaint.setAlpha((int) (mBottomSheetBackgroundAlpha * 255)); mTmpRectF.set( leftWithScale, @@ -1424,6 +1435,10 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> return; } + if (hasBottomSheet) { + mHeaderPaint.setAlpha((int) (mHeaderPaint.getAlpha() * mBottomSheetBackgroundAlpha)); + } + // Draw header on background panel final float headerBottomNoScale = getHeaderBottom() + getVisibleContainerView().getPaddingTop(); @@ -1455,7 +1470,11 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> mHeaderPaint.setColor(Color.BLUE); mHeaderPaint.setAlpha(255); } else { - mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha)); + float tabAlpha = getAlpha() * mTabsProtectionAlpha; + if (hasBottomSheet) { + tabAlpha *= mBottomSheetBackgroundAlpha; + } + mHeaderPaint.setAlpha((int) tabAlpha); } float left = 0f; float right = canvas.getWidth(); @@ -1507,7 +1526,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> public int getHeaderBottom() { int bottom = (int) getTranslationY() + mHeader.getClipTop(); if (isSearchBarFloating()) { - if (mActivityContext.getDeviceProfile().isTablet) { + if (mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) { return bottom + mBottomSheetBackground.getTop(); } return bottom; diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 4cc31d296e..350f763939 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -290,7 +290,8 @@ public class AllAppsTransitionController private void onScaleProgressChanged() { final float scaleProgress = mAllAppScale.value; SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress); - if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) { + if (!mLauncher.getAppsView().isSearching() + || !mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet()) { mLauncher.getScrimView().setScrimHeaderScale(scaleProgress); } diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 5f632fe25d..f223eaa600 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -64,7 +64,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement AllAppsStore.OnUpdateListener { public static final String TAG = "AlphabeticalAppsList"; - private static final String PRIVATE_SPACE_PACKAGE = "com.android.privatespace"; + public static final String PRIVATE_SPACE_PACKAGE = "com.android.privatespace"; private final WorkProfileManager mWorkProviderManager; @@ -436,6 +436,8 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement if (currentItem.itemInfo != null && Objects.equals( currentItem.itemInfo.getTargetPackage(), PRIVATE_SPACE_PACKAGE)) { currentItem.itemInfo.bitmap.creationFlags |= FLAG_NO_BADGE; + currentItem.itemInfo.contentDescription = + mPrivateProviderManager.getPsAppContentDesc(); privateSpaceAppIndex = i; } } diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java index 609edd2c99..1bc1b17d15 100644 --- a/src/com/android/launcher3/allapps/PrivateProfileManager.java +++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java @@ -142,6 +142,7 @@ public class PrivateProfileManager extends UserProfileManager { private PrivateSpaceSettingsButton mPrivateSpaceSettingsButton; @Nullable private ConstraintLayout mFloatingMaskView; + private final String mPrivateSpaceAppContentDesc; private final String mLockedStateContentDesc; private final String mUnLockedStateContentDesc; @@ -157,6 +158,8 @@ public class PrivateProfileManager extends UserProfileManager { UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext)); mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize( R.dimen.ps_header_height); + mPrivateSpaceAppContentDesc = mAllApps.getContext() + .getString(R.string.ps_app_content_description); mLockedStateContentDesc = mAllApps.getContext() .getString(R.string.ps_container_lock_button_content_description); mUnLockedStateContentDesc = mAllApps.getContext() @@ -929,6 +932,10 @@ public class PrivateProfileManager extends UserProfileManager { return mPsHeaderHeight; } + String getPsAppContentDesc() { + return mPrivateSpaceAppContentDesc; + } + boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) { return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo); diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java index 06643d3cbf..c49909772e 100644 --- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java +++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java @@ -28,6 +28,7 @@ import com.android.launcher3.graphics.GridCustomizationsProxy; import com.android.launcher3.graphics.ThemeManager; import com.android.launcher3.icons.LauncherIcons.IconPool; import com.android.launcher3.model.ItemInstallQueue; +import com.android.launcher3.model.LoaderCursor.LoaderCursorFactory; import com.android.launcher3.model.WidgetsFilterDataProvider; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.UserCache; @@ -87,6 +88,8 @@ public interface LauncherBaseAppComponent { GridCustomizationsProxy getGridCustomizationsProxy(); WidgetsFilterDataProvider getWidgetsFilterDataProvider(); + LoaderCursorFactory getLoaderCursorFactory(); + /** Builder for LauncherBaseAppComponent. */ interface Builder { @BindsInstance Builder appContext(@ApplicationContext Context context); diff --git a/src/com/android/launcher3/debug/TestEventEmitter.java b/src/com/android/launcher3/debug/TestEventEmitter.java index ed3b4bbac9..db69bc2130 100644 --- a/src/com/android/launcher3/debug/TestEventEmitter.java +++ b/src/com/android/launcher3/debug/TestEventEmitter.java @@ -34,7 +34,9 @@ public class TestEventEmitter { RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"), WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"), SPRING_LOADED_STATE_STARTED("SPRING_LOADED_STATE_STARTED"), - SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"); + SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"), + + LAUNCHER_STATE_COMPLETED("LAUNCHER_STATE_COMPLETED"); TestEvent(String event) { } diff --git a/src/com/android/launcher3/dot/FolderDotInfo.java b/src/com/android/launcher3/dot/FolderDotInfo.java index 54800a07a8..cb91db7654 100644 --- a/src/com/android/launcher3/dot/FolderDotInfo.java +++ b/src/com/android/launcher3/dot/FolderDotInfo.java @@ -30,6 +30,10 @@ public class FolderDotInfo extends DotInfo { private int mNumNotifications; + public void reset() { + mNumNotifications = 0; + } + public void addDotInfo(DotInfo dotToAdd) { if (dotToAdd == null) { return; @@ -39,15 +43,6 @@ public class FolderDotInfo extends DotInfo { mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT); } - public void subtractDotInfo(DotInfo dotToSubtract) { - if (dotToSubtract == null) { - return; - } - mNumNotifications -= dotToSubtract.getNotificationKeys().size(); - mNumNotifications = Utilities.boundToRange( - mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT); - } - @Override public int getNotificationCount() { return mNumNotifications; diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index 613b4308eb..415a2c6230 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -16,6 +16,7 @@ package com.android.launcher3.dragndrop; +import static com.android.launcher3.Flags.removeAppsRefreshOnRightClick; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE; import android.graphics.Point; @@ -521,17 +522,21 @@ public abstract class DragController<T extends ActivityContext> mDragObject.dragComplete = true; if (mIsInPreDrag) { - if (dropTarget != null) { - dropTarget.onDragExit(mDragObject); + if (removeAppsRefreshOnRightClick()) { + mDragObject.cancelled = true; + } else { + if (dropTarget != null) { + dropTarget.onDragExit(mDragObject); + } + return; } - return; } // Drop onto the target. boolean accepted = false; if (dropTarget != null) { dropTarget.onDragExit(mDragObject); - if (dropTarget.acceptDrop(mDragObject)) { + if (!mIsInPreDrag && dropTarget.acceptDrop(mDragObject)) { if (flingAnimation != null) { flingAnimation.run(); } else { @@ -539,9 +544,10 @@ public abstract class DragController<T extends ActivityContext> } accepted = true; } + + final View dropTargetAsView = dropTarget.getDropView(); + dispatchDropComplete(dropTargetAsView, accepted); } - final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null; - dispatchDropComplete(dropTargetAsView, accepted); } private DropTarget findDropTarget(final int x, final int y) { diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java index 4aa3673586..dd433c02d3 100644 --- a/src/com/android/launcher3/dragndrop/LauncherDragController.java +++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java @@ -15,7 +15,10 @@ */ package com.android.launcher3.dragndrop; +import static android.view.View.VISIBLE; + import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE; +import static com.android.launcher3.Flags.removeAppsRefreshOnRightClick; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.LauncherState.NORMAL; @@ -25,6 +28,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import androidx.annotation.Nullable; @@ -33,10 +37,13 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; +import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.accessibility.DragViewStateAnnouncer; +import com.android.launcher3.dragndrop.DragOptions.PreDragCondition; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.util.TouchUtil; import com.android.launcher3.widget.util.WidgetDragScaleUtils; /** @@ -47,6 +54,9 @@ public class LauncherDragController extends DragController<Launcher> { private static final boolean PROFILE_DRAWING_DURING_DRAG = false; private final FlingToDeleteHelper mFlingToDeleteHelper; + /** Whether or not the drag operation is triggered by mouse right click. */ + private boolean mIsInMouseRightClick = false; + public LauncherDragController(Launcher launcher) { super(launcher); mFlingToDeleteHelper = new FlingToDeleteHelper(launcher); @@ -69,6 +79,28 @@ public class LauncherDragController extends DragController<Launcher> { android.os.Debug.startMethodTracing("Launcher"); } + if (removeAppsRefreshOnRightClick() && mIsInMouseRightClick + && options.preDragCondition == null + && originalView instanceof View v) { + options.preDragCondition = new PreDragCondition() { + + @Override + public boolean shouldStartDrag(double distanceDragged) { + return false; + } + + @Override + public void onPreDragStart(DragObject dragObject) { + // Set it to visible so the text of FolderIcon would not flash (avoid it from + // being invisible and then visible) + v.setVisibility(VISIBLE); + } + + @Override + public void onPreDragEnd(DragObject dragObject, boolean dragStarted) { } + }; + } + mActivity.hideKeyboard(); AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_DISCOVERY_BOUNCE); @@ -191,7 +223,7 @@ public class LauncherDragController extends DragController<Launcher> { @Override protected void exitDrag() { - if (!mActivity.isInState(EDIT_MODE)) { + if (!mIsInPreDrag && !mActivity.isInState(EDIT_MODE)) { mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY); } } @@ -218,4 +250,13 @@ public class LauncherDragController extends DragController<Launcher> { dropCoordinates); return mActivity.getWorkspace(); } + + /** + * Intercepts touch events from a drag source view. + */ + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + mIsInMouseRightClick = TouchUtil.isMouseRightClickDownOrMove(ev); + return super.onControllerInterceptTouchEvent(ev); + } } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 28032569b2..967af053fb 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -19,9 +19,6 @@ package com.android.launcher3.folder; import static android.text.TextUtils.isEmpty; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; -import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; -import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR; -import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; @@ -29,6 +26,7 @@ import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTI import static com.android.launcher3.folder.FolderGridOrganizer.createFolderGridOrganizer; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED; +import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType; import static com.android.launcher3.testing.shared.TestProtocol.FOLDER_OPENED_MESSAGE; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; @@ -95,14 +93,12 @@ import com.android.launcher3.logger.LauncherAtom.ToState; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.data.FolderInfo; -import com.android.launcher3.model.data.FolderInfo.FolderListener; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemFactory; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pageindicators.PageIndicatorDots; import com.android.launcher3.util.Executors; import com.android.launcher3.util.LauncherBindableItemsContainer; -import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator; import com.android.launcher3.util.Thunk; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; @@ -112,6 +108,7 @@ import com.android.launcher3.widget.PendingAddShortcutInfo; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -123,7 +120,7 @@ import java.util.stream.Stream; * Represents a set of icons chosen by the user or generated by the system. */ public class Folder extends AbstractFloatingView implements ClipPathView, DragSource, - View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener, + View.OnLongClickListener, DropTarget, TextView.OnEditorActionListener, View.OnFocusChangeListener, DragListener, ExtendedEditText.OnBackKeyListener, LauncherBindableItemsContainer { private static final String TAG = "Launcher.Folder"; @@ -180,15 +177,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return o instanceof ItemInfo info && willAcceptItemType(info.itemType); } - /** - * Checks if {@code itemType} is a type that can be placed in folders. - */ - public static boolean willAcceptItemType(int itemType) { - return itemType == ITEM_TYPE_APPLICATION - || itemType == ITEM_TYPE_DEEP_SHORTCUT - || itemType == ITEM_TYPE_APP_PAIR; - } - private Alarm mReorderAlarm = new Alarm(Looper.getMainLooper()); private Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper()); private Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper()); @@ -244,7 +232,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo private boolean mIsExternalDrag; private boolean mIsDragInProgress = false; private boolean mDeleteFolderOnDropCompleted = false; + private boolean mSuppressFolderDeletion = false; + private boolean mSuppressContentUpdate = false; + private boolean mItemAddedBackToSelfViaIcon = false; private boolean mIsEditingName = false; @@ -386,9 +377,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo // We do not want to get events for the item being removed, as they will get handled // when the drop completes - try (SuppressInfoChanges s = new SuppressInfoChanges()) { - mInfo.remove(dragObject.dragInfo, true); - } + executeWithContentUpdateSuppressed(() -> removeFolderContent(true, dragObject.dragInfo)); + mIsDragInProgress = true; mItemAddedBackToSelfViaIcon = false; } @@ -533,8 +523,17 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo lp.customPosition = true; setLayoutParams(lp); } + reapplyItemInfo(); + // In case any children didn't come across during loading, clean up the folder accordingly + mFolderIcon.post(() -> { + if (getItemCount() <= 1) { + replaceFolderWithFinalItem(); + } + }); + } + + public void reapplyItemInfo() { mItemsInvalidated = true; - mInfo.addListener(this); if (!isEmpty(mInfo.title)) { mFolderName.setText(mInfo.title); @@ -543,15 +542,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderName.setText(""); mFolderName.setHint(R.string.folder_hint_text); } - // In case any children didn't come across during loading, clean up the folder accordingly - mFolderIcon.post(() -> { - if (getItemCount() <= 1) { - replaceFolderWithFinalItem(); - } - }); } - /** * Show suggested folder title in FolderEditText if the first suggestion is non-empty, push * rest of the suggestions to InputMethodManager. @@ -681,7 +673,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo if (!shouldAnimateOpen(items)) { return; } - Folder openFolder = getOpen(mActivityContext); closeOpenFolder(openFolder); @@ -955,9 +946,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo @Override public boolean acceptDrop(DragObject d) { - final ItemInfo item = d.dragInfo; - final int itemType = item.itemType; - return Folder.willAcceptItemType(itemType); + return willAcceptItemType(d.dragInfo.itemType); } public void onDragEnter(DragObject d) { @@ -1116,13 +1105,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info) ? mCurrentDragView : mContent.createNewView(info); ArrayList<View> views = getIconsInReadingOrder(); - info.rank = Utilities.boundToRange(info.rank, 0, views.size()); - views.add(info.rank, icon); - mContent.arrangeChildren(views); - mItemsInvalidated = true; - - try (SuppressInfoChanges s = new SuppressInfoChanges()) { - mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */); + if (!views.contains(icon)) { + info.rank = Utilities.boundToRange(info.rank, 0, views.size()); + views.add(info.rank, icon); + mContent.arrangeChildren(views); + mItemsInvalidated = true; + + executeWithContentUpdateSuppressed( + () -> mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */)); } } @@ -1416,9 +1406,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo rearrangeChildren(); // Temporarily suppress the listener, as we did all the work already here. - try (SuppressInfoChanges s = new SuppressInfoChanges()) { - mInfo.add(si, mEmptyCellRank, false); - } + executeWithContentUpdateSuppressed(() -> addFolderContent(si, mEmptyCellRank, false)); // We only need to update the locations if it doesn't get handled in // #onDropCompleted. @@ -1464,37 +1452,66 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } } - @Override - public void onAdd(ItemInfo item, int rank) { - FolderGridOrganizer verifier = createFolderGridOrganizer( - mActivityContext.getDeviceProfile()).setFolderInfo(mInfo); - verifier.updateRankAndPos(item, rank); - mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX, - item.cellY); - updateItemLocationsInDatabaseBatch(false); + /** Add an app or shortcut */ + public void addFolderContent(ItemInfo item) { + addFolderContent(item, mInfo.getContents().size(), true); + } - if (mContent.areViewsBound()) { - mContent.createAndAddViewForRank(item, rank); + /** Add an app or shortcut for a specified rank */ + public void addFolderContent(ItemInfo item, int rank, boolean animate) { + if (!willAcceptItemType(item.itemType)) { + throw new RuntimeException("tried to add an illegal type into a folder"); } - mItemsInvalidated = true; + + rank = Utilities.boundToRange(rank, 0, mInfo.getContents().size()); + mInfo.getContents().add(rank, item); + + if (!mSuppressContentUpdate) { + FolderGridOrganizer verifier = createFolderGridOrganizer( + mActivityContext.getDeviceProfile()).setFolderInfo(mInfo); + verifier.updateRankAndPos(item, rank); + mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, + item.cellX, + item.cellY); + updateItemLocationsInDatabaseBatch(false); + + if (mContent.areViewsBound()) { + mContent.createAndAddViewForRank(item, rank); + } + mItemsInvalidated = true; + updateTextViewFocus(); + } + + mLauncherDelegate.getModelWriter().notifyItemModified(mInfo); + mFolderIcon.onItemsChanged(animate); } - @Override - public void onRemove(List<ItemInfo> items) { - mItemsInvalidated = true; - items.stream().map(this::getViewForInfo).forEach(mContent::removeItem); - if (mState == STATE_ANIMATING) { - mRearrangeOnClose = true; - } else { - rearrangeChildren(); + /** Remove all matching app or shortcut. Does not change the DB. */ + public void removeFolderContent(boolean animate, ItemInfo... items) { + List<ItemInfo> itemArray = Arrays.asList(items); + if (mInfo.getContents().removeAll(itemArray)) { + mLauncherDelegate.getModelWriter().notifyItemModified(mInfo); } - if (getItemCount() <= 1) { - if (mIsOpen) { - close(true); + + if (!mSuppressContentUpdate) { + mItemsInvalidated = true; + itemArray.forEach(item -> mContent.removeItem(getViewForInfo(item))); + if (mState == STATE_ANIMATING) { + mRearrangeOnClose = true; } else { - replaceFolderWithFinalItem(); + rearrangeChildren(); } + if (getItemCount() <= 1) { + if (mIsOpen) { + close(true); + } else { + replaceFolderWithFinalItem(); + } + } + updateTextViewFocus(); } + + mFolderIcon.onItemsChanged(animate); } @VisibleForTesting @@ -1502,16 +1519,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return mContent.iterateOverItems((info, view) -> info == item); } - @Override - public void onItemsChanged(boolean animate) { - updateTextViewFocus(); - } - - @Override - public void onTitleChanged(CharSequence title) { - mFolderName.setText(title); - } - /** * Utility methods to iterate over items of the view */ @@ -1665,18 +1672,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } }; - /** - * Temporary resource held while we don't want to handle info changes - */ - private class SuppressInfoChanges implements AutoCloseable { - - SuppressInfoChanges() { - mInfo.removeListener(Folder.this); - } - - @Override - public void close() { - mInfo.addListener(Folder.this); + /** Executes the task while suppressing the content update for the folder */ + private void executeWithContentUpdateSuppressed(Runnable task) { + if (mSuppressContentUpdate) { + task.run(); + } else { + mSuppressContentUpdate = true; + task.run(); + mSuppressContentUpdate = false; updateTextViewFocus(); } } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 0ed87871cc..1cd9bcc965 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -23,6 +23,7 @@ import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMA import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS; +import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -73,7 +74,6 @@ import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.FolderInfo; -import com.android.launcher3.model.data.FolderInfo.FolderListener; import com.android.launcher3.model.data.FolderInfo.LabelState; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemFactory; @@ -92,7 +92,7 @@ import java.util.function.Predicate; /** * An icon that can appear on in the workspace representing an {@link Folder}. */ -public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion, +public class FolderIcon extends FrameLayout implements FloatingIconViewCompanion, DraggableView, Reorderable { private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this); @@ -127,7 +127,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI private boolean mForceHideDot; @ViewDebug.ExportedProperty(category = "launcher", deepExport = true) - private FolderDotInfo mDotInfo = new FolderDotInfo(); + private final FolderDotInfo mDotInfo = new FolderDotInfo(); private DotRenderer mDotRenderer; @ViewDebug.ExportedProperty(category = "launcher", deepExport = true) private DotRenderer.DrawParams mDotParams; @@ -178,7 +178,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI folder.bind(folderInfo); icon.setFolder(folder); - folderInfo.addListener(icon); return icon; } @@ -217,13 +216,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI icon.mDotRenderer = grid.mDotRendererWorkSpace; icon.setContentDescription(icon.getAccessiblityTitle(folderInfo.title)); - - // Keep the notification dot up to date with the sum of all the content's dots. - FolderDotInfo folderDotInfo = new FolderDotInfo(); - for (ItemInfo si : folderInfo.getContents()) { - folderDotInfo.addDotInfo(activity.getDotInfoForItem(si)); - } - icon.setDotInfo(folderDotInfo); + icon.updateDotInfo(); icon.setAccessibilityDelegate(activity.getAccessibilityDelegate()); @@ -264,22 +257,13 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI } private boolean willAcceptItem(ItemInfo item) { - final int itemType = item.itemType; - return (Folder.willAcceptItemType(itemType) && item != mInfo && !mFolder.isOpen()); + return (willAcceptItemType(item.itemType) && item != mInfo && !mFolder.isOpen()); } public boolean acceptDrop(ItemInfo dragInfo) { return !mFolder.isDestroyed() && willAcceptItem(dragInfo); } - public void addItem(ItemInfo item) { - mInfo.add(item, true); - } - - public void removeItem(ItemInfo item, boolean animate) { - mInfo.remove(item, animate); - } - public void onDragEnter(ItemInfo dragInfo) { if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return; CellLayoutLayoutParams lp = (CellLayoutLayoutParams) getLayoutParams(); @@ -308,9 +292,8 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI public void performCreateAnimation(final ItemInfo destInfo, final View destView, final ItemInfo srcInfo, final DragObject d, Rect dstRect, float scaleRelativeToDragLayer) { - final DragView srcView = d.dragView; prepareCreateAnimation(destView); - addItem(destInfo); + getFolder().addFolderContent(destInfo); // This will animate the first item from it's position as an icon into its // position as the first item in the preview mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null) @@ -364,7 +347,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI boolean itemAdded = false; if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) { List<ItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems); - mInfo.add(item, index, false); + getFolder().addFolderContent(item, index, false); mCurrentPreviewItems.clear(); mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0)); @@ -380,12 +363,12 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item); itemAdded = true; } else { - removeItem(item, false); + getFolder().removeFolderContent(false, item); } } if (!itemAdded) { - mInfo.add(item, index, true); + getFolder().addFolderContent(item, index, true); } int[] center = new int[2]; @@ -431,7 +414,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI }, DROP_IN_ANIMATION_DURATION); }); } else { - addItem(item); + getFolder().addFolderContent(item); } } @@ -500,9 +483,23 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI ); } - public void setDotInfo(FolderDotInfo dotInfo) { - updateDotScale(mDotInfo.hasDot(), dotInfo.hasDot()); - mDotInfo = dotInfo; + /** Keep the notification dot up to date with the sum of all the content's dots. */ + public void updateDotInfo() { + boolean hadDot = mDotInfo.hasDot(); + mDotInfo.reset(); + for (ItemInfo si : mInfo.getContents()) { + mDotInfo.addDotInfo(mActivity.getDotInfoForItem(si)); + } + boolean isDotted = mDotInfo.hasDot(); + float newDotScale = isDotted ? 1f : 0f; + // Animate when a dot is first added or when it is removed. + if ((hadDot ^ isDotted) && isShown()) { + animateDotScale(newDotScale); + } else { + cancelDotScaleAnim(); + mDotScale = newDotScale; + invalidate(); + } } public ClippedFolderIconLayoutRule getLayoutRule() { @@ -523,22 +520,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI } } - /** - * Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false - * (the dot is being added or removed). - */ - private void updateDotScale(boolean wasDotted, boolean isDotted) { - float newDotScale = isDotted ? 1f : 0f; - // Animate when a dot is first added or when it is removed. - if ((wasDotted ^ isDotted) && isShown()) { - animateDotScale(newDotScale); - } else { - cancelDotScaleAnim(); - mDotScale = newDotScale; - invalidate(); - } - } - private void cancelDotScaleAnim() { if (mDotScaleAnim != null) { mDotScaleAnim.cancel(); @@ -682,13 +663,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who); } - @Override - public void onItemsChanged(boolean animate) { - updatePreviewItems(animate); - invalidate(); - requestLayout(); - } - private void updatePreviewItems(boolean animate) { mPreviewItemManager.updatePreviewItems(animate); mCurrentPreviewItems.clear(); @@ -702,31 +676,15 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI mPreviewItemManager.updatePreviewItems(itemCheck); } - @Override - public void onAdd(ItemInfo item, int rank) { - updatePreviewItems(false); - boolean wasDotted = mDotInfo.hasDot(); - mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item)); - boolean isDotted = mDotInfo.hasDot(); - updateDotScale(wasDotted, isDotted); - setContentDescription(getAccessiblityTitle(mInfo.title)); - invalidate(); - requestLayout(); - } - - @Override - public void onRemove(List<ItemInfo> items) { + public void onItemsChanged(boolean animate) { updatePreviewItems(false); - boolean wasDotted = mDotInfo.hasDot(); - items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo); - boolean isDotted = mDotInfo.hasDot(); - updateDotScale(wasDotted, isDotted); + updateDotInfo(); setContentDescription(getAccessiblityTitle(mInfo.title)); + updatePreviewItems(animate); invalidate(); requestLayout(); } - @Override public void onTitleChanged(CharSequence title) { mFolderName.setText(title); setContentDescription(getAccessiblityTitle(title)); @@ -762,11 +720,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI mLongPressHelper.cancelLongPress(); } - public void removeListeners() { - mInfo.removeListener(this); - mInfo.removeListener(mFolder); - } - private boolean isInHotseat() { return mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT; } diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index bebe1a49ef..0963421f8a 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -47,6 +47,7 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.pageindicators.Direction; import com.android.launcher3.pageindicators.PageIndicatorDots; import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator; import com.android.launcher3.util.Thunk; @@ -129,6 +130,8 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli public void setFolder(Folder folder) { mFolder = folder; mPageIndicator = folder.findViewById(R.id.folder_page_indicator); + mPageIndicator.setArrowClickListener(direction -> snapToPageImmediately( + (Direction.END == direction) ? mCurrentPage + 1 : mCurrentPage - 1)); initParentViews(folder); } diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java index 70b9f46c1f..48519ce8bc 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java @@ -113,6 +113,7 @@ public class GridCustomizationsProxy implements ProxyProvider { private static final String KEY_SHAPE_OPTIONS = "/shape_options"; // default_grid is for setting grid and shape to system settings private static final String KEY_DEFAULT_GRID = "/default_grid"; + private static final String SET_SHAPE = "/shape"; private static final String METHOD_GET_PREVIEW = "get_preview"; @@ -130,6 +131,7 @@ public class GridCustomizationsProxy implements ProxyProvider { private static final int MESSAGE_ID_UPDATE_SHAPE = 2586; private static final int MESSAGE_ID_UPDATE_GRID = 7414; private static final int MESSAGE_ID_UPDATE_COLOR = 856; + private static final int MESSAGE_ID_UPDATE_ICON_THEMED = 311; // Set of all active previews used to track duplicate memory allocations private final Set<PreviewLifecycleObserver> mActivePreviews = @@ -264,6 +266,12 @@ public class GridCustomizationsProxy implements ProxyProvider { mContext.getContentResolver().notifyChange(uri, null); return 1; } + case SET_SHAPE: + if (Flags.newCustomizationPickerUi()) { + mPrefs.put(PREF_ICON_SHAPE, + requireNonNullElse(values.getAsString(KEY_SHAPE_KEY), "")); + } + return 1; case ICON_THEMED: case SET_ICON_THEMED: { mThemeManager.setMonoThemeEnabled(values.getAsBoolean(BOOLEAN_VALUE)); @@ -384,6 +392,12 @@ public class GridCustomizationsProxy implements ProxyProvider { renderer.previewColor(message.getData()); } break; + case MESSAGE_ID_UPDATE_ICON_THEMED: + if (Flags.newCustomizationPickerUi()) { + Boolean iconThemed = message.getData().getBoolean(BOOLEAN_VALUE); + // TODO Update icon themed in the preview + } + break; default: // Unknown command, destroy lifecycle Log.d(TAG, "Unknown preview command: " + message.what + ", destroying preview"); diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index b80238cb1e..e4e4b900fa 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -80,8 +80,10 @@ import com.android.launcher3.dagger.LauncherAppComponent; import com.android.launcher3.dagger.LauncherAppModule; import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.model.BaseLauncherBinder.BaseLauncherBinderFactory; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.FixedContainerItems; +import com.android.launcher3.model.LoaderTask.LoaderTaskFactory; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.CollectionInfo; import com.android.launcher3.model.data.FolderInfo; @@ -605,6 +607,10 @@ public class LauncherPreviewRenderer extends BaseContext @Component(modules = LauncherAppModule.class) public interface PreviewAppComponent extends LauncherAppComponent { + LoaderTaskFactory getLoaderTaskFactory(); + BaseLauncherBinderFactory getBaseLauncherBinderFactory(); + BgDataModel getDataModel(); + /** Builder for NexusLauncherAppComponent. */ @Component.Builder interface Builder extends LauncherAppComponent.Builder { diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index d425f03712..457d12e8ca 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -21,7 +21,6 @@ import static android.content.res.Configuration.UI_MODE_NIGHT_YES; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.launcher3.LauncherPrefs.GRID_NAME; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.graphics.ThemeManager.PREF_ICON_SHAPE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -58,19 +57,21 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Workspace; +import com.android.launcher3.dagger.LauncherComponentProvider; +import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewAppComponent; import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; -import com.android.launcher3.model.BaseLauncherBinder; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.model.UserManagerState; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; import com.android.launcher3.widget.LocalColorExtractor; import com.android.systemui.shared.Flags; -import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -177,7 +178,7 @@ public class PreviewSurfaceRenderer { ModelDbController mainController = LauncherAppState.getInstance(mContext).getModel().getModelDbController(); - try (Cursor c = mainController.query(TABLE_NAME, + try (Cursor c = mainController.query( new String[] { LauncherSettings.Favorites.APPWIDGET_ID, LauncherSettings.Favorites.SPANX, @@ -338,38 +339,32 @@ public class PreviewSurfaceRenderer { // Start the migration PreviewContext previewContext = new PreviewContext(inflationContext, mGridName, mShapeKey); + PreviewAppComponent appComponent = + (PreviewAppComponent) LauncherComponentProvider.get(previewContext); + + LoaderTask task = appComponent.getLoaderTaskFactory().newLoaderTask( + appComponent.getBaseLauncherBinderFactory().createBinder(new Callbacks[0]), + new UserManagerState()); + + InvariantDeviceProfile idp = appComponent.getIDP(); + DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext); + String query = + LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID + + " or " + LauncherSettings.Favorites.CONTAINER + " = " + + LauncherSettings.Favorites.CONTAINER_HOTSEAT; + if (deviceProfile.isTwoPanels) { + query += " or " + LauncherSettings.Favorites.SCREEN + " = " + + Workspace.SECOND_SCREEN_ID; + } - BgDataModel bgModel = new BgDataModel(); - new LoaderTask( - LauncherAppState.getInstance(previewContext), - /* bgAllAppsList= */ null, - bgModel, - LauncherAppState.getInstance(previewContext).getModel().getModelDelegate(), - new BaseLauncherBinder(LauncherAppState.getInstance(previewContext), bgModel, - /* bgAllAppsList= */ null, new Callbacks[0])) { - - @Override - public void run() { - InvariantDeviceProfile idp = LauncherAppState.getIDP(previewContext); - DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext); - String query = - LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID - + " or " + LauncherSettings.Favorites.CONTAINER + " = " - + LauncherSettings.Favorites.CONTAINER_HOTSEAT; - if (deviceProfile.isTwoPanels) { - query += " or " + LauncherSettings.Favorites.SCREEN + " = " - + Workspace.SECOND_SCREEN_ID; - } - loadWorkspace(new ArrayList<>(), query, null, null); - - final SparseArray<Size> spanInfo = getLoadedLauncherWidgetInfo(); - MAIN_EXECUTOR.execute(() -> { - renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo, - idp); - mLifeCycleTracker.add(previewContext::onDestroy); - }); - } - }.run(); + Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap = new HashMap<>(); + task.loadWorkspaceForPreview(query, widgetProviderInfoMap); + final SparseArray<Size> spanInfo = getLoadedLauncherWidgetInfo(); + MAIN_EXECUTOR.execute(() -> { + renderView(previewContext, appComponent.getDataModel(), widgetProviderInfoMap, + spanInfo, idp); + mLifeCycleTracker.add(previewContext::onDestroy); + }); } else { LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> { if (dataModel != null) { @@ -420,7 +415,6 @@ public class PreviewSurfaceRenderer { view.setTranslationY((mHeight - scale * view.getHeight()) / 2); } - if (!Flags.newCustomizationPickerUi()) { view.setAlpha(mSkipAnimations ? 1 : 0); view.animate().alpha(1) @@ -477,5 +471,4 @@ public class PreviewSurfaceRenderer { MAIN_EXECUTOR.execute(mLifecycleTracker::executeAllAndDestroy); } } - } diff --git a/src/com/android/launcher3/graphics/ShapeDelegate.kt b/src/com/android/launcher3/graphics/ShapeDelegate.kt index 7c042929e2..01bfe3018c 100644 --- a/src/com/android/launcher3/graphics/ShapeDelegate.kt +++ b/src/com/android/launcher3/graphics/ShapeDelegate.kt @@ -18,6 +18,7 @@ package com.android.launcher3.graphics import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator +import android.animation.ValueAnimator.AnimatorUpdateListener import android.graphics.Canvas import android.graphics.Color import android.graphics.Matrix @@ -41,7 +42,6 @@ import androidx.graphics.shapes.SvgPathParser import androidx.graphics.shapes.rectangle import androidx.graphics.shapes.toPath import androidx.graphics.shapes.transformed -import com.android.launcher3.anim.RoundedRectRevealOutlineProvider import com.android.launcher3.icons.GraphicsUtils import com.android.launcher3.views.ClipPathView @@ -127,16 +127,20 @@ interface ShapeDelegate { endRadius: Float, isReversed: Boolean, ): ValueAnimator where T : View, T : ClipPathView { - return object : - RoundedRectRevealOutlineProvider( - (startRect.width() / 2f) * radiusRatio, - endRadius, - startRect, - endRect, - ) { - override fun shouldRemoveElevationDuringAnimation() = true - } - .createRevealAnimator(target, isReversed) + val startRadius = (startRect.width() / 2f) * radiusRatio + return ClipAnimBuilder(target) { progress, path -> + val radius = (1 - progress) * startRadius + progress * endRadius + path.addRoundRect( + (1 - progress) * startRect.left + progress * endRect.left, + (1 - progress) * startRect.top + progress * endRect.top, + (1 - progress) * startRect.right + progress * endRect.right, + (1 - progress) * startRect.bottom + progress * endRect.bottom, + radius, + radius, + Path.Direction.CW, + ) + } + .toAnim(isReversed) } override fun equals(other: Any?) = @@ -220,38 +224,44 @@ interface ShapeDelegate { ), ) - val va = - if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f) - va.addListener( - object : AnimatorListenerAdapter() { - private var oldOutlineProvider: ViewOutlineProvider? = null - - override fun onAnimationStart(animation: Animator) { - target.apply { - oldOutlineProvider = outlineProvider - outlineProvider = null - translationZ = -target.elevation - } - } + return ClipAnimBuilder(target, morph::toPath).toAnim(isReversed) + } + } - override fun onAnimationEnd(animation: Animator) { - target.apply { - translationZ = 0f - setClipPath(null) - outlineProvider = oldOutlineProvider - } - } - } - ) + private class ClipAnimBuilder<T>(val target: T, val pathProvider: (Float, Path) -> Unit) : + AnimatorListenerAdapter(), AnimatorUpdateListener where T : View, T : ClipPathView { - val path = Path() - va.addUpdateListener { anim: ValueAnimator -> - path.reset() - morph.toPath(anim.animatedValue as Float, path) - target.setClipPath(path) + private var oldOutlineProvider: ViewOutlineProvider? = null + val path = Path() + + override fun onAnimationStart(animation: Animator) { + target.apply { + oldOutlineProvider = outlineProvider + outlineProvider = null + translationZ = -target.elevation + } + } + + override fun onAnimationEnd(animation: Animator) { + target.apply { + translationZ = 0f + setClipPath(null) + outlineProvider = oldOutlineProvider } - return va } + + override fun onAnimationUpdate(anim: ValueAnimator) { + path.reset() + pathProvider.invoke(anim.animatedValue as Float, path) + target.setClipPath(path) + } + + fun toAnim(isReversed: Boolean) = + (if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f)) + .also { + it.addListener(this) + it.addUpdateListener(this) + } } companion object { diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 45ed489dbe..44d2e266f7 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -166,6 +166,9 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User tapped or long pressed on settings icon inside launcher settings.") LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS(463), + @UiEvent(doc = "User tapped or long pressed on apps icon inside launcher settings.") + LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS(2204), + @UiEvent(doc = "User tapped or long pressed on widget tray icon inside launcher settings.") LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS(464), diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index ddbbdc722a..dfba4bb192 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -66,13 +66,6 @@ public class AddWorkspaceItemsTask implements ModelUpdateTask { /** * @param itemList items to add on the workspace - */ - public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList) { - this(itemList, new WorkspaceItemSpaceFinder()); - } - - /** - * @param itemList items to add on the workspace * @param itemSpaceFinder inject WorkspaceItemSpaceFinder dependency for testing */ public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList, @@ -91,7 +84,7 @@ public class AddWorkspaceItemsTask implements ModelUpdateTask { final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>(); final IntArray addedWorkspaceScreensFinal = new IntArray(); - final Context context = taskController.getApp().getContext(); + final Context context = taskController.getContext(); synchronized (dataModel) { IntArray workspaceScreens = dataModel.collectWorkspaceScreens(); @@ -133,7 +126,7 @@ public class AddWorkspaceItemsTask implements ModelUpdateTask { for (ItemInfo item : filteredItems) { // Find appropriate space for the item. - int[] coords = mItemSpaceFinder.findSpaceForItem(taskController.getApp(), dataModel, + int[] coords = mItemSpaceFinder.findSpaceForItem( workspaceScreens, addedWorkspaceScreensFinal, item.spanX, item.spanY); int screenId = coords[0]; @@ -192,7 +185,7 @@ public class AddWorkspaceItemsTask implements ModelUpdateTask { continue; } - IconCache cache = taskController.getApp().getIconCache(); + IconCache cache = taskController.getIconCache(); WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo; wii.title = ""; wii.bitmap = cache.getDefaultIcon(item.user); diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 98f9afdaaa..2311239025 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -34,6 +34,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AppFilter; import com.android.launcher3.compat.AlphabeticIndexCompat; +import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; @@ -53,11 +54,13 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; +import javax.inject.Inject; + /** * Stores the list of all applications for the all apps view. */ -@SuppressWarnings("NewApi") +@LauncherAppSingleton public class AllAppsList { private static final String TAG = "AllAppsList"; @@ -70,10 +73,10 @@ public class AllAppsList { public final ArrayList<AppInfo> data = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER); @NonNull - private IconCache mIconCache; + private final IconCache mIconCache; @NonNull - private AppFilter mAppFilter; + private final AppFilter mAppFilter; private boolean mDataChanged = false; private Consumer<AppInfo> mRemoveListener = NO_OP_CONSUMER; @@ -92,6 +95,7 @@ public class AllAppsList { /** * Boring constructor. */ + @Inject public AllAppsList(IconCache iconCache, AppFilter appFilter) { mIconCache = iconCache; mAppFilter = appFilter; diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java index 262bf678c7..c4bbae416b 100644 --- a/src/com/android/launcher3/model/BaseLauncherBinder.java +++ b/src/com/android/launcher3/model/BaseLauncherBinder.java @@ -26,6 +26,7 @@ import static com.android.launcher3.model.ModelUtils.currentScreenContentFilter; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.content.Context; import android.os.Trace; import android.util.Log; import android.util.Pair; @@ -34,11 +35,12 @@ import android.view.View; import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherModel.CallbackTask; import com.android.launcher3.LauncherSettings; import com.android.launcher3.celllayout.CellPosMapper; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.ApplicationContext; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.AppInfo; @@ -55,6 +57,10 @@ import com.android.launcher3.util.RunnableList; import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder; import com.android.launcher3.widget.model.WidgetsListBaseEntry; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -76,7 +82,9 @@ public class BaseLauncherBinder { protected final LooperExecutor mUiExecutor; - protected final LauncherAppState mApp; + private final Context mContext; + private final InvariantDeviceProfile mIDP; + private final LauncherModel mModel; protected final BgDataModel mBgDataModel; private final AllAppsList mBgAllAppsList; @@ -84,10 +92,18 @@ public class BaseLauncherBinder { private int mMyBindingId; - public BaseLauncherBinder(LauncherAppState app, BgDataModel dataModel, - AllAppsList allAppsList, Callbacks[] callbacksList) { + @AssistedInject + public BaseLauncherBinder( + @ApplicationContext Context context, + InvariantDeviceProfile idp, + LauncherModel model, + BgDataModel dataModel, + AllAppsList allAppsList, + @Assisted Callbacks[] callbacksList) { mUiExecutor = MAIN_EXECUTOR; - mApp = app; + mContext = context; + mIDP = idp; + mModel = model; mBgDataModel = dataModel; mBgAllAppsList = allAppsList; mCallbacksList = callbacksList; @@ -110,15 +126,14 @@ public class BaseLauncherBinder { mBgDataModel.extraItems.forEach(extraItems::add); if (incrementBindId) { mBgDataModel.lastBindId++; - mBgDataModel.lastLoadId = mApp.getModel().getLastLoadId(); + mBgDataModel.lastLoadId = mModel.getLastLoadId(); } mMyBindingId = mBgDataModel.lastBindId; workspaceItemCount = mBgDataModel.itemsIdMap.size(); } for (Callbacks cb : mCallbacksList) { - new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, - itemsIdMap, extraItems, orderedScreenIds) + new UnifiedWorkspaceBinder(cb, itemsIdMap, extraItems, orderedScreenIds) .bind(isBindSync, workspaceItemCount); } } finally { @@ -162,9 +177,8 @@ public class BaseLauncherBinder { if (!WIDGETS_ENABLED) { return; } - List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mApp.getContext()) + List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mContext) .build(mBgDataModel.widgetsModel.getWidgetsByPackageItemForPicker()); - executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor); } @@ -181,10 +195,9 @@ public class BaseLauncherBinder { /** * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right) */ - protected void sortWorkspaceItemsSpatially(InvariantDeviceProfile profile, - ArrayList<ItemInfo> workspaceItems) { - final int screenCols = profile.numColumns; - final int screenCellCount = profile.numColumns * profile.numRows; + protected void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) { + final int screenCols = mIDP.numColumns; + final int screenCellCount = mIDP.numColumns * mIDP.numRows; Collections.sort(workspaceItems, (lhs, rhs) -> { if (lhs.container == rhs.container) { // Within containers, order by their spatial position in that container @@ -240,30 +253,18 @@ public class BaseLauncherBinder { private class UnifiedWorkspaceBinder { - private final Executor mUiExecutor; private final Callbacks mCallbacks; - private final LauncherAppState mApp; - private final BgDataModel mBgDataModel; - - private final int mMyBindingId; private final IntSparseArrayMap<ItemInfo> mItemIdMap; private final IntArray mOrderedScreenIds; private final ArrayList<FixedContainerItems> mExtraItems; - UnifiedWorkspaceBinder(Callbacks callbacks, - Executor uiExecutor, - LauncherAppState app, - BgDataModel bgDataModel, - int myBindingId, + UnifiedWorkspaceBinder( + Callbacks callbacks, IntSparseArrayMap<ItemInfo> itemIdMap, ArrayList<FixedContainerItems> extraItems, IntArray orderedScreenIds) { mCallbacks = callbacks; - mUiExecutor = uiExecutor; - mApp = app; - mBgDataModel = bgDataModel; - mMyBindingId = myBindingId; mItemIdMap = itemIdMap; mExtraItems = extraItems; mOrderedScreenIds = orderedScreenIds; @@ -289,9 +290,8 @@ public class BaseLauncherBinder { (WIDGET_FILTER.test(item) ? otherAppWidgets : otherWorkspaceItems).add(item); } }); - final InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile(); - sortWorkspaceItemsSpatially(idp, currentWorkspaceItems); - sortWorkspaceItemsSpatially(idp, otherWorkspaceItems); + sortWorkspaceItemsSpatially(currentWorkspaceItems); + sortWorkspaceItemsSpatially(otherWorkspaceItems); // Tell the workspace that we're about to start binding items executeCallbacksTask(c -> { @@ -352,7 +352,7 @@ public class BaseLauncherBinder { executeCallbacksTask(c -> c.bindStringCache(cacheClone), pendingExecutor); executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor); - pendingExecutor.execute(() -> ItemInstallQueue.INSTANCE.get(mApp.getContext()) + pendingExecutor.execute(() -> ItemInstallQueue.INSTANCE.get(mContext) .resumeModelPush(FLAG_LOADER_RUNNING)); } @@ -367,8 +367,8 @@ public class BaseLauncherBinder { return; } - ModelWriter writer = mApp.getModel() - .getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null); + ModelWriter writer = mModel.getWriter( + false /* verifyChanges */, CellPosMapper.DEFAULT, null); List<Pair<ItemInfo, View>> bindItems = items.stream() .map(i -> Pair.create(i, inflater.inflateItem(i, writer, null))) .collect(Collectors.toList()); @@ -398,4 +398,9 @@ public class BaseLauncherBinder { }); } } + + @AssistedFactory + public interface BaseLauncherBinderFactory { + BaseLauncherBinder createBinder(Callbacks[] callbacks); + } } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index d9eccaf4f3..ea9f36c419 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -46,6 +46,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BuildConfig; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.CollectionInfo; @@ -79,9 +80,15 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.inject.Inject; + /** * All the data stored in-memory and managed by the LauncherModel + * + * All the static data should be accessed on the background thread, A lock should be acquired on + * this object when accessing any data from this model. */ +@LauncherAppSingleton public class BgDataModel { private static final String TAG = "BgDataModel"; @@ -105,7 +112,7 @@ public class BgDataModel { /** * Entire list of widgets. */ - public final WidgetsModel widgetsModel = new WidgetsModel(); + public final WidgetsModel widgetsModel; /** * Cache for strings used in launcher @@ -124,6 +131,11 @@ public class BgDataModel { public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN && !enableSmartspaceRemovalToggle(); + @Inject + public BgDataModel(WidgetsModel widgetsModel) { + this.widgetsModel = widgetsModel; + } + /** * Clears all the data */ diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java index 48934e2c11..f740b49694 100644 --- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java +++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java @@ -59,7 +59,7 @@ public class CacheDataUpdatedTask implements ModelUpdateTask { @Override public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel, @NonNull AllAppsList apps) { - IconCache iconCache = taskController.getApp().getIconCache(); + IconCache iconCache = taskController.getIconCache(); ArrayList<ItemInfo> updatedItems = new ArrayList<>(); synchronized (dataModel) { diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java index f443f8142e..829e0fe08b 100644 --- a/src/com/android/launcher3/model/FirstScreenBroadcast.java +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -45,9 +45,9 @@ import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -76,9 +76,9 @@ public class FirstScreenBroadcast { private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken"; - private final HashMap<PackageUserKey, SessionInfo> mSessionInfoForPackage; + private final Map<PackageUserKey, SessionInfo> mSessionInfoForPackage; - public FirstScreenBroadcast(HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage) { + public FirstScreenBroadcast(Map<PackageUserKey, SessionInfo> sessionInfoForPackage) { mSessionInfoForPackage = sessionInfoForPackage; } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index bd8c36b576..efe61572fe 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET; import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED; @@ -45,13 +44,14 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.Flags; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.ApplicationContext; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; @@ -70,6 +70,10 @@ import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.UserIconInfo; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + import java.net.URISyntaxException; import java.security.InvalidParameterException; @@ -82,8 +86,8 @@ public class LoaderCursor extends CursorWrapper { private final LongSparseArray<UserHandle> allUsers; - private final LauncherAppState mApp; private final Context mContext; + private final LauncherModel mModel; private final PackageManagerHelper mPmHelper; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; @@ -130,17 +134,24 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState, - PackageManagerHelper pmHelper, - @Nullable LauncherRestoreEventLogger restoreEventLogger) { + @AssistedInject + public LoaderCursor( + @Assisted Cursor cursor, + @Assisted UserManagerState userManagerState, + @Assisted @Nullable LauncherRestoreEventLogger restoreEventLogger, + @ApplicationContext Context context, + IconCache iconCache, + InvariantDeviceProfile idp, + LauncherModel model, + PackageManagerHelper pmHelper) { super(cursor); + mContext = context; + mIconCache = iconCache; + mIDP = idp; + mModel = model; + mPmHelper = pmHelper; - mApp = app; allUsers = userManagerState.allUsers; - mContext = app.getContext(); - mIconCache = app.getIconCache(); - mPmHelper = pmHelper; - mIDP = app.getInvariantDeviceProfile(); mRestoreEventLogger = restoreEventLogger; // Init column indices @@ -432,7 +443,7 @@ public class LoaderCursor extends CursorWrapper { */ public ContentWriter updater() { return new ContentWriter(mContext, new ContentWriter.CommitParams( - mApp.getModel().getModelDbController(), + mModel.getModelDbController(), BaseColumns._ID + "= ?", new String[]{Integer.toString(id)})); } @@ -454,7 +465,7 @@ public class LoaderCursor extends CursorWrapper { public boolean commitDeleted() { if (mItemsToRemove.size() > 0) { // Remove dead items - mApp.getModel().getModelDbController().delete(TABLE_NAME, + mModel.getModelDbController().delete( Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null); return true; } @@ -480,7 +491,7 @@ public class LoaderCursor extends CursorWrapper { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); values.put(Favorites.RESTORED, 0); - mApp.getModel().getModelDbController().update(TABLE_NAME, values, + mModel.getModelDbController().update(values, Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null); } if (mRestoreEventLogger != null) { @@ -645,4 +656,12 @@ public class LoaderCursor extends CursorWrapper { return false; } } + + @AssistedFactory + public interface LoaderCursorFactory { + + LoaderCursor createLoaderCursor(Cursor cursor, + UserManagerState userManagerState, + @Nullable LauncherRestoreEventLogger restoreEventLogger); + } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index fb1ebaf3c4..78e5d898cd 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -23,7 +23,6 @@ import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle; import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE; import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE; import static com.android.launcher3.LauncherSettings.Favorites.DESKTOP_ICON_FLAG; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.icons.CacheableShortcutInfo.convertShortcutsToCacheableShortcuts; import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; @@ -53,7 +52,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; @@ -63,13 +61,14 @@ import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; import com.android.launcher3.Flags; -import com.android.launcher3.LauncherAppState; +import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.ApplicationContext; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderNameInfos; @@ -82,6 +81,7 @@ import com.android.launcher3.icons.cache.CachedObjectCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.icons.cache.LauncherActivityCachingLogic; import com.android.launcher3.logging.FileLog; +import com.android.launcher3.model.LoaderCursor.LoaderCursorFactory; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.FolderInfo; @@ -106,6 +106,10 @@ import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.widget.WidgetInflater; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -117,6 +121,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CancellationException; +import javax.inject.Named; + /** * Runnable for the thread that loads the contents of the launcher: * - workspace icons @@ -131,10 +137,14 @@ public class LoaderTask implements Runnable { private static final boolean DEBUG = true; - @NonNull - protected final LauncherAppState mApp; + private final Context mContext; + private final LauncherModel mModel; + private final InvariantDeviceProfile mIDP; + private final boolean mIsSafeModeEnabled; private final AllAppsList mBgAllAppsList; protected final BgDataModel mBgDataModel; + private final LoaderCursorFactory mLoaderCursorFactory; + private final ModelDelegate mModelDelegate; private boolean mIsRestoreFromBackup; @@ -152,7 +162,6 @@ public class LoaderTask implements Runnable { private final IconCache mIconCache; private final UserManagerState mUserManagerState; - protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>(); private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts; private HashMap<PackageUserKey, SessionInfo> mInstallingPkgsCached; @@ -164,26 +173,36 @@ public class LoaderTask implements Runnable { private boolean mItemsDeleted = false; private String mDbName; - public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel, - ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder) { - this(app, bgAllAppsList, bgModel, modelDelegate, launcherBinder, new UserManagerState()); - } - - @VisibleForTesting - LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel, - ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder, - UserManagerState userManagerState) { - mApp = app; + @AssistedInject + LoaderTask( + @ApplicationContext Context context, + InvariantDeviceProfile idp, + LauncherModel model, + UserCache userCache, + PackageManagerHelper pmHelper, + InstallSessionHelper sessionHelper, + IconCache iconCache, + AllAppsList bgAllAppsList, + BgDataModel bgModel, + LoaderCursorFactory loaderCursorFactory, + @Named("SAFE_MODE") boolean isSafeModeEnabled, + @Assisted @NonNull BaseLauncherBinder launcherBinder, + @Assisted UserManagerState userManagerState) { + mContext = context; + mIDP = idp; + mModel = model; + mIsSafeModeEnabled = isSafeModeEnabled; mBgAllAppsList = bgAllAppsList; mBgDataModel = bgModel; - mModelDelegate = modelDelegate; + mModelDelegate = model.getModelDelegate(); mLauncherBinder = launcherBinder; - 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(); + mLoaderCursorFactory = loaderCursorFactory; + mLauncherApps = mContext.getSystemService(LauncherApps.class); + mUserManager = mContext.getSystemService(UserManager.class); + mUserCache = userCache; + mPmHelper = pmHelper; + mSessionHelper = sessionHelper; + mIconCache = iconCache; mUserManagerState = userManagerState; mInstallingPkgsCached = null; } @@ -215,7 +234,7 @@ public class LoaderTask implements Runnable { .filter(currentScreenContentFilter(firstScreens)) .toList(); final int disableArchivingLauncherBroadcast = Settings.Secure.getInt( - mApp.getContext().getContentResolver(), + mContext.getContentResolver(), "disable_launcher_broadcast_installed_apps", /* default */ 0); boolean shouldAttachArchivingExtras = mIsRestoreFromBackup @@ -230,10 +249,10 @@ public class LoaderTask implements Runnable { mBgDataModel.itemsIdMap.stream().filter(WIDGET_FILTER).toList() ); logASplit("Sending first screen broadcast with additional archiving Extras"); - FirstScreenBroadcastHelper.sendBroadcastsForModels(mApp.getContext(), broadcastModels); + FirstScreenBroadcastHelper.sendBroadcastsForModels(mContext, broadcastModels); } else { logASplit("Sending first screen broadcast"); - mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems); + mFirstScreenBroadcast.sendBroadcasts(mContext, firstScreenItems); } } @@ -249,16 +268,14 @@ public class LoaderTask implements Runnable { MODEL_EXECUTOR.elevatePriority(CALLER_LOADER_TASK); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); mIsRestoreFromBackup = - LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE); + LauncherPrefs.get(mContext).get(IS_FIRST_LOAD_AFTER_RESTORE); LauncherRestoreEventLogger restoreEventLogger = null; if (enableLauncherBrMetricsFixed()) { - restoreEventLogger = LauncherRestoreEventLogger.Companion - .newInstance(mApp.getContext()); + restoreEventLogger = LauncherRestoreEventLogger.Companion.newInstance(mContext); } - try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { - + try (LauncherModel.LoaderTransaction transaction = mModel.beginLoader(this)) { List<CacheableShortcutInfo> allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts, "", memoryLogger, restoreEventLogger); + loadWorkspace(allShortcuts, "", new HashMap<>(), memoryLogger, restoreEventLogger); // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -267,7 +284,7 @@ public class LoaderTask implements Runnable { // TODO(b/384731096): Write Unit Test to make sure sanitizeWidgetsShortcutsAndPackages // actually re-pins shortcuts that are in model but not in ShortcutManager, if possible // after a simulated restore. - if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) { + if (Objects.equals(mIDP.dbFile, mDbName)) { verifyNotStopped(); sanitizeFolders(mItemsDeleted); sanitizeAppPairs(); @@ -307,13 +324,13 @@ public class LoaderTask implements Runnable { setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.INSTANCE, - mApp.getModel()::onPackageIconsUpdated); + mModel::onPackageIconsUpdated); logASplit("update AllApps icon cache finished"); verifyNotStopped(); logASplit("saving all shortcuts in icon cache"); updateHandler.updateIcons(allShortcuts, CacheableShortcutCachingLogic.INSTANCE, - mApp.getModel()::onPackageIconsUpdated); + mModel::onPackageIconsUpdated); // Take a break waitForIdle(); @@ -342,14 +359,14 @@ public class LoaderTask implements Runnable { // fourth step WidgetsModel widgetsModel = mBgDataModel.widgetsModel; - List<CachedObject> allWidgetsList = widgetsModel.update(mApp, /*packageUser=*/null); + List<CachedObject> allWidgetsList = widgetsModel.update(/*packageUser=*/null); logASplit("load widgets finished"); verifyNotStopped(); mLauncherBinder.bindWidgets(); logASplit("bindWidgets finished"); verifyNotStopped(); - LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext()); + LauncherPrefs prefs = LauncherPrefs.get(mContext); if (enableSmartspaceAsAWidget() && prefs.get(SHOULD_SHOW_SMARTSPACE)) { mLauncherBinder.bindSmartspaceWidget(); @@ -366,7 +383,7 @@ public class LoaderTask implements Runnable { logASplit("saving all widgets in icon cache"); updateHandler.updateIcons(allWidgetsList, CachedObjectCachingLogic.INSTANCE, - mApp.getModel()::onWidgetLabelsUpdated); + mModel::onWidgetLabelsUpdated); // fifth step loadFolderNames(); @@ -380,7 +397,7 @@ public class LoaderTask implements Runnable { memoryLogger.clearLogs(); if (mIsRestoreFromBackup) { mIsRestoreFromBackup = false; - LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false)); + LauncherPrefs.get(mContext).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false)); if (restoreEventLogger != null) { restoreEventLogger.reportLauncherRestoreResults(); } @@ -402,35 +419,42 @@ public class LoaderTask implements Runnable { this.notify(); } - protected void loadWorkspace( + public void loadWorkspaceForPreview(String selection, + Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) { + loadWorkspace(new ArrayList<>(), selection, widgetProviderInfoMap, null, null); + } + + private void loadWorkspace( List<CacheableShortcutInfo> allDeepShortcuts, String selection, + Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap, @Nullable LoaderMemoryLogger memoryLogger, @Nullable LauncherRestoreEventLogger restoreEventLogger ) { Trace.beginSection("LoadWorkspace"); try { - loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger, restoreEventLogger); + loadWorkspaceImpl(allDeepShortcuts, selection, widgetProviderInfoMap, + memoryLogger, restoreEventLogger); } finally { Trace.endSection(); } logASplit("loadWorkspace finished"); mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN - && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs( - mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)); + && (!enableSmartspaceRemovalToggle() + || LauncherPrefs.getPrefs(mContext).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)); } private void loadWorkspaceImpl( List<CacheableShortcutInfo> allDeepShortcuts, String selection, + Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap, @Nullable LoaderMemoryLogger memoryLogger, @Nullable LauncherRestoreEventLogger restoreEventLogger) { - final Context context = mApp.getContext(); final boolean isSdCardReady = Utilities.isBootCompleted(); - final WidgetInflater widgetInflater = new WidgetInflater(context); + final WidgetInflater widgetInflater = new WidgetInflater(mContext, mIsSafeModeEnabled); - ModelDbController dbController = mApp.getModel().getModelDbController(); + ModelDbController dbController = mModel.getModelDbController(); if (Flags.gridMigrationRefactor()) { try { dbController.attemptMigrateDb(restoreEventLogger, mModelDelegate); @@ -452,28 +476,29 @@ public class LoaderTask implements Runnable { if (Flags.enableSupportForArchiving()) { mInstallingPkgsCached = installingPkgs; } - installingPkgs.forEach(mApp.getIconCache()::updateSessionCache); + installingPkgs.forEach(mIconCache::updateSessionCache); FileLog.d(TAG, "loadWorkspace: Packages with active install/update sessions: " + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList()); mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mShortcutKeyToPinnedShortcuts = new HashMap<>(); - final LoaderCursor c = new LoaderCursor( - dbController.query(TABLE_NAME, null, selection, null, null), - mApp, mUserManagerState, mPmHelper, + final LoaderCursor c = mLoaderCursorFactory.createLoaderCursor( + dbController.query(null, selection, null, null), + mUserManagerState, mIsRestoreFromBackup ? restoreEventLogger : null); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME); try { final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>(); - queryPinnedShortcutsForUnlockedUsers(context, unlockedUsers); + queryPinnedShortcutsForUnlockedUsers(mContext, unlockedUsers); mWorkspaceIconRequestInfos = new ArrayList<>(); WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger, mUserCache, mUserManagerState, mLauncherApps, mPendingPackages, - mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel, - mWidgetProvidersMap, installingPkgs, isSdCardReady, + mShortcutKeyToPinnedShortcuts, mContext, mIDP, mIconCache, + mIsSafeModeEnabled, mBgDataModel, + widgetProviderInfoMap, installingPkgs, isSdCardReady, widgetInflater, mPmHelper, mWorkspaceIconRequestInfos, unlockedUsers, allDeepShortcuts); @@ -577,7 +602,7 @@ public class LoaderTask implements Runnable { @WorkerThread private void processFolderItems() { // Sort the folder items, update ranks, and make sure all preview items are high res. - List<FolderGridOrganizer> verifiers = mApp.getInvariantDeviceProfile().supportedProfiles + List<FolderGridOrganizer> verifiers = mIDP.supportedProfiles .stream().map(FolderGridOrganizer::createFolderGridOrganizer).toList(); for (ItemInfo itemInfo : mBgDataModel.itemsIdMap) { if (!(itemInfo instanceof FolderInfo folder)) { @@ -617,7 +642,7 @@ public class LoaderTask implements Runnable { if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) { logASplit("tryLoadWorkspaceIconsInBulk: default icon found for " + wai.getTargetComponent() + ", will attempt to load from iconBlob"); - iconRequestInfo.loadIconFromDbBlob(mApp.getContext()); + iconRequestInfo.loadIconFromDbBlob(mContext); } } } finally { @@ -649,7 +674,7 @@ public class LoaderTask implements Runnable { private void sanitizeFolders(boolean itemsDeleted) { if (itemsDeleted) { // Remove any empty folder - IntArray deletedFolderIds = mApp.getModel().getModelDbController().deleteEmptyFolders(); + IntArray deletedFolderIds = mModel.getModelDbController().deleteEmptyFolders(); synchronized (mBgDataModel) { for (int folderId : deletedFolderIds) { mBgDataModel.itemsIdMap.remove(folderId); @@ -660,8 +685,8 @@ public class LoaderTask implements Runnable { /** Cleans up app pairs if they don't have the right number of member apps (2). */ private void sanitizeAppPairs() { - IntArray deletedAppPairIds = mApp.getModel().getModelDbController().deleteBadAppPairs(); - IntArray deletedAppIds = mApp.getModel().getModelDbController().deleteUnparentedApps(); + IntArray deletedAppPairIds = mModel.getModelDbController().deleteBadAppPairs(); + IntArray deletedAppIds = mModel.getModelDbController().deleteUnparentedApps(); IntArray deleted = new IntArray(); deleted.addAll(deletedAppPairIds); @@ -675,17 +700,15 @@ public class LoaderTask implements Runnable { } private void sanitizeWidgetsShortcutsAndPackages() { - Context context = mApp.getContext(); - // Remove any ghost widgets - mApp.getModel().getModelDbController().removeGhostWidgets(); + mModel.getModelDbController().removeGhostWidgets(); // Update pinned state of model shortcuts - mBgDataModel.updateShortcutPinnedState(context); + mBgDataModel.updateShortcutPinnedState(mContext); if (!Utilities.isBootCompleted() && !mPendingPackages.isEmpty()) { - context.registerReceiver( - new SdCardAvailableReceiver(mApp, mPendingPackages), + mContext.registerReceiver( + new SdCardAvailableReceiver(mContext, mModel, mPendingPackages), new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, MODEL_EXECUTOR.getHandler()); @@ -722,7 +745,7 @@ public class LoaderTask implements Runnable { for (int i = 0; i < apps.size(); i++) { LauncherActivityInfo app = apps.get(i); AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user), - ApiWrapper.INSTANCE.get(mApp.getContext()), mPmHelper, quietMode); + ApiWrapper.INSTANCE.get(mContext), mPmHelper, quietMode); if (Flags.enableSupportForArchiving() && app.getApplicationInfo().isArchived) { // For archived apps, include progress info in case there is a pending // install session post restart of device. @@ -751,7 +774,7 @@ public class LoaderTask implements Runnable { for (PackageInstaller.SessionInfo info : mSessionHelper.getAllVerifiedSessions()) { AppInfo promiseAppInfo = mBgAllAppsList.addPromiseApp( - mApp.getContext(), + mContext, PackageInstallInfo.fromInstallingState(info), false); @@ -776,7 +799,7 @@ public class LoaderTask implements Runnable { + appInfo.getTargetComponent() + ", will attempt to load from iconBlob: " + Arrays.toString(iconRequestInfo.iconBlob)); - iconRequestInfo.loadIconFromDbBlob(mApp.getContext()); + iconRequestInfo.loadIconFromDbBlob(mContext); } } } @@ -794,9 +817,9 @@ public class LoaderTask implements Runnable { mUserManagerState.isAnyProfileQuietModeEnabled()); } mBgAllAppsList.setFlags(FLAG_HAS_SHORTCUT_PERMISSION, - hasShortcutsPermission(mApp.getContext())); + hasShortcutsPermission(mContext)); mBgAllAppsList.setFlags(FLAG_QUIET_MODE_CHANGE_PERMISSION, - mApp.getContext().checkSelfPermission("android.permission.MODIFY_QUIET_MODE") + mContext.checkSelfPermission("android.permission.MODIFY_QUIET_MODE") == PackageManager.PERMISSION_GRANTED); mBgAllAppsList.getAndResetChangeFlag(); @@ -827,7 +850,7 @@ public class LoaderTask implements Runnable { workspaceIconRequest.get().iconBlob, false /* useLowResIcon= */ ); - if (!iconRequestInfo.loadIconFromDbBlob(mApp.getContext())) { + if (!iconRequestInfo.loadIconFromDbBlob(mContext)) { Log.d(TAG, "AppInfo Icon failed to load from blob, using cache."); mIconCache.getTitleAndIcon( appInfo, @@ -853,7 +876,7 @@ public class LoaderTask implements Runnable { if (mBgAllAppsList.hasShortcutHostPermission()) { for (UserHandle user : mUserCache.getUserProfiles()) { if (mUserManager.isUserUnlocked(user)) { - List<ShortcutInfo> shortcuts = new ShortcutRequest(mApp.getContext(), user) + List<ShortcutInfo> shortcuts = new ShortcutRequest(mContext, user) .query(ShortcutRequest.ALL); allShortcuts.addAll(shortcuts); mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts); @@ -864,7 +887,7 @@ public class LoaderTask implements Runnable { } private void loadFolderNames() { - FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(), + FolderNameProvider provider = FolderNameProvider.newInstance(mContext, mBgAllAppsList.data, FolderNameProvider.getCollectionForSuggestions(mBgDataModel)); synchronized (mBgDataModel) { @@ -874,7 +897,7 @@ public class LoaderTask implements Runnable { .forEach(info -> { FolderInfo fi = (FolderInfo) info; FolderNameInfos suggestionInfos = new FolderNameInfos(); - provider.getSuggestedFolderName(mApp.getContext(), fi.getAppContents(), + provider.getSuggestedFolderName(mContext, fi.getAppContents(), suggestionInfos); fi.suggestedFolderNames = suggestionInfos; }); @@ -891,4 +914,10 @@ public class LoaderTask implements Runnable { Log.d(TAG, label); } } + + @AssistedFactory + public interface LoaderTaskFactory { + + LoaderTask newLoaderTask(BaseLauncherBinder binder, UserManagerState userState); + } } diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index feae632bc5..64b9c1c9cd 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -73,6 +73,8 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError; +import com.android.launcher3.dagger.ApplicationContext; +import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; @@ -91,10 +93,13 @@ import java.io.StringReader; import java.util.List; import java.util.stream.Collectors; +import javax.inject.Inject; + /** * Utility class which maintains an instance of Launcher database and provides utility methods * around it. */ +@LauncherAppSingleton public class ModelDbController { private static final String TAG = "ModelDbController"; @@ -105,17 +110,25 @@ public class ModelDbController { protected DatabaseHelper mOpenHelper; private final Context mContext; - - public ModelDbController(Context context) { + private final InvariantDeviceProfile mIdp; + private final LauncherPrefs mPrefs; + private final UserCache mUserCache; + + @Inject + ModelDbController( + @ApplicationContext Context context, + InvariantDeviceProfile idp, + LauncherPrefs prefs, + UserCache userCache) { mContext = context; + mIdp = idp; + mPrefs = prefs; + mUserCache = userCache; } private void printDBs(String prefix) { try { - File directory = new File( - mContext.getDatabasePath(InvariantDeviceProfile.INSTANCE.get(mContext).dbFile) - .getParent() - ); + File directory = new File(mContext.getDatabasePath(mIdp.dbFile).getParent()); if (directory.exists()) { for (File file : directory.listFiles()) { Log.d("b/353505773", prefix + "Database file: " + file.getName()); @@ -130,9 +143,9 @@ public class ModelDbController { private synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - String dbFile = LauncherPrefs.get(mContext).get(DB_FILE); + String dbFile = mPrefs.get(DB_FILE); if (dbFile.isEmpty()) { - dbFile = InvariantDeviceProfile.INSTANCE.get(mContext).dbFile; + dbFile = mIdp.dbFile; } mOpenHelper = createDatabaseHelper(false /* forMigration */, dbFile); printDBs("before: "); @@ -144,7 +157,7 @@ public class ModelDbController { protected DatabaseHelper createDatabaseHelper(boolean forMigration, String dbFile) { // Set the flag for empty DB Runnable onEmptyDbCreateCallback = forMigration ? () -> { } - : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbFile).to(true)); + : () -> mPrefs.putSync(getEmptyDbCreatedKey(dbFile).to(true)); DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbFile, this::getSerialNumberForUser, onEmptyDbCreateCallback); @@ -169,12 +182,12 @@ public class ModelDbController { * Refer {@link SQLiteDatabase#query} */ @WorkerThread - public Cursor query(String table, String[] projection, String selection, + public Cursor query(String[] projection, String selection, String[] selectionArgs, String sortOrder) { createDbIfNotExists(); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); Cursor result = db.query( - table, projection, selection, selectionArgs, null, null, sortOrder); + TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); final Bundle extra = new Bundle(); extra.putString(EXTRA_DB_NAME, mOpenHelper.getDatabaseName()); @@ -186,12 +199,12 @@ public class ModelDbController { * Refer {@link SQLiteDatabase#insert(String, String, ContentValues)} */ @WorkerThread - public int insert(String table, ContentValues initialValues) { + public int insert(ContentValues initialValues) { createDbIfNotExists(); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); addModifiedTime(initialValues); - int rowId = mOpenHelper.dbInsertAndCheck(db, table, initialValues); + int rowId = mOpenHelper.dbInsertAndCheck(db, TABLE_NAME, initialValues); if (rowId >= 0) { onAddOrDeleteOp(db); } @@ -202,11 +215,11 @@ public class ModelDbController { * Refer {@link SQLiteDatabase#delete(String, String, String[])} */ @WorkerThread - public int delete(String table, String selection, String[] selectionArgs) { + public int delete(String selection, String[] selectionArgs) { createDbIfNotExists(); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count = db.delete(table, selection, selectionArgs); + int count = db.delete(TABLE_NAME, selection, selectionArgs); if (count > 0) { onAddOrDeleteOp(db); } @@ -217,14 +230,12 @@ public class ModelDbController { * Refer {@link SQLiteDatabase#update(String, ContentValues, String, String[])} */ @WorkerThread - public int update(String table, ContentValues values, - String selection, String[] selectionArgs) { + public int update(ContentValues values, String selection, String[] selectionArgs) { createDbIfNotExists(); addModifiedTime(values); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count = db.update(table, values, selection, selectionArgs); - return count; + return db.update(TABLE_NAME, values, selection, selectionArgs); } /** @@ -261,7 +272,7 @@ public class ModelDbController { public void createEmptyDB() { createDbIfNotExists(); mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); - LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey().to(true)); + mPrefs.putSync(getEmptyDbCreatedKey().to(true)); } /** @@ -292,7 +303,6 @@ public class ModelDbController { mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); } - /** * Resets the launcher DB if we should reset it. */ @@ -302,11 +312,10 @@ public class ModelDbController { } FileLog.d(TAG, "resetLauncherDb: Migration failed: resetting launcher database"); createEmptyDB(); - LauncherPrefs.get(mContext).putSync( - getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true)); + mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true)); // Write the grid state to avoid another migration - new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext); + new DeviceGridState(mIdp).writeToPrefs(mContext); } /** @@ -326,7 +335,7 @@ public class ModelDbController { } private boolean isThereExistingDb() { - if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) { + if (mPrefs.get(getEmptyDbCreatedKey())) { // If we already have a new DB, ignore migration FileLog.d(TAG, "isThereExistingDb: new DB already created, skipping migration"); return true; @@ -335,8 +344,7 @@ public class ModelDbController { } private boolean isGridMigrationNecessary() { - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - if (GridSizeMigrationDBController.needsToMigrate(mContext, idp)) { + if (GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) { return true; } FileLog.d(TAG, "isGridMigrationNecessary: no grid migration needed"); @@ -344,8 +352,7 @@ public class ModelDbController { } private boolean isCurrentDbSameAsTarget() { - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - String targetDbName = new DeviceGridState(idp).getDbFile(); + String targetDbName = new DeviceGridState(mIdp).getDbFile(); if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) { FileLog.e(TAG, "isCurrentDbSameAsTarget: target db is same as current" + " current db: " + mOpenHelper.getDatabaseName() @@ -367,7 +374,6 @@ public class ModelDbController { return; } - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); DatabaseHelper oldHelper = mOpenHelper; // We save the existing db's before creating the destination db helper so we know what logic @@ -376,12 +382,12 @@ public class ModelDbController { .filter(dbName -> mContext.getDatabasePath(dbName).exists()) .collect(Collectors.toList()); - mOpenHelper = createDatabaseHelper(true, new DeviceGridState(idp).getDbFile()); + mOpenHelper = createDatabaseHelper(true, new DeviceGridState(mIdp).getDbFile()); try { // This is the current grid we have, given by the mContext DeviceGridState srcDeviceState = new DeviceGridState(mContext); // This is the state we want to migrate to that is given by the idp - DeviceGridState destDeviceState = new DeviceGridState(idp); + DeviceGridState destDeviceState = new DeviceGridState(mIdp); boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile()); GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic(); @@ -404,10 +410,10 @@ public class ModelDbController { ModelDelegate modelDelegate) { if (!migrateGridIfNeeded(modelDelegate)) { if (restoreEventLogger != null) { - if (LauncherPrefs.get(mContext).get(NO_DB_FILES_RESTORED)) { + if (mPrefs.get(NO_DB_FILES_RESTORED)) { restoreEventLogger.logLauncherItemsRestoreFailed(DATA_TYPE_DB_FILE, 1, RestoreError.DATABASE_FILE_NOT_RESTORED); - LauncherPrefs.get(mContext).put(NO_DB_FILES_RESTORED, false); + mPrefs.put(NO_DB_FILES_RESTORED, false); FileLog.d(TAG, "There is no data to migrate: resetting launcher database"); } else { restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1); @@ -416,11 +422,10 @@ public class ModelDbController { } FileLog.d(TAG, "tryMigrateDB: Migration failed: resetting launcher database"); createEmptyDB(); - LauncherPrefs.get(mContext).putSync( - getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true)); + mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true)); // Write the grid state to avoid another migration - new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext); + new DeviceGridState(mIdp).writeToPrefs(mContext); } else if (restoreEventLogger != null) { restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1); } @@ -434,17 +439,16 @@ public class ModelDbController { */ private boolean migrateGridIfNeeded(ModelDelegate modelDelegate) { createDbIfNotExists(); - if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) { + if (mPrefs.get(getEmptyDbCreatedKey())) { // If we have already create a new DB, ignore migration FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration"); return false; } - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - if (!GridSizeMigrationDBController.needsToMigrate(mContext, idp)) { + if (!GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) { FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed"); return true; } - String targetDbName = new DeviceGridState(idp).getDbFile(); + String targetDbName = new DeviceGridState(mIdp).getDbFile(); if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) { FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current" + " current db: " + mOpenHelper.getDatabaseName() @@ -462,7 +466,7 @@ public class ModelDbController { // This is the current grid we have, given by the mContext DeviceGridState srcDeviceState = new DeviceGridState(mContext); // This is the state we want to migrate to that is given by the idp - DeviceGridState destDeviceState = new DeviceGridState(idp); + DeviceGridState destDeviceState = new DeviceGridState(mIdp); boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile()); return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState, destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb, @@ -611,7 +615,7 @@ public class ModelDbController { } private void clearFlagEmptyDbCreated() { - LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey()); + mPrefs.removeSync(getEmptyDbCreatedKey()); } /** @@ -625,7 +629,7 @@ public class ModelDbController { public synchronized void loadDefaultFavoritesIfNecessary() { createDbIfNotExists(); - if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) { + if (mPrefs.get(getEmptyDbCreatedKey())) { Log.d(TAG, "loading default workspace"); LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); @@ -737,10 +741,9 @@ public class ModelDbController { } private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) { - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - int defaultLayout = idp.demoModeLayoutId != 0 + int defaultLayout = mIdp.demoModeLayoutId != 0 && mContext.getSystemService(UserManager.class).isDemoUser() - ? idp.demoModeLayoutId : idp.defaultLayoutId; + ? mIdp.demoModeLayoutId : mIdp.defaultLayoutId; return new DefaultLayoutParser(mContext, widgetHolder, mOpenHelper, mContext.getResources(), defaultLayout); @@ -766,6 +769,6 @@ public class ModelDbController { * Returns the serial number for the provided user */ public long getSerialNumberForUser(UserHandle user) { - return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); + return mUserCache.getSerialNumberForUser(user); } } diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt index 7ba2dad553..8b6c369e66 100644 --- a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt +++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt @@ -114,7 +114,7 @@ class ModelLauncherCallbacks(private var taskExecutor: Consumer<ModelUpdateTask> override fun onUpdateSessionDisplay(key: PackageUserKey, info: SessionInfo) { /** Updates the icons and label of all pending icons for the provided package name. */ taskExecutor.accept { controller, _, _ -> - controller.app.iconCache.updateSessionCache(key, info) + controller.iconCache.updateSessionCache(key, info) } taskExecutor.accept( CacheDataUpdatedTask( @@ -128,7 +128,7 @@ class ModelLauncherCallbacks(private var taskExecutor: Consumer<ModelUpdateTask> override fun onInstallSessionCreated(sessionInfo: PackageInstallInfo) { if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) { taskExecutor.accept { taskController, _, apps -> - apps.addPromiseApp(taskController.app.context, sessionInfo) + apps.addPromiseApp(taskController.context, sessionInfo) taskController.bindApplicationsIfNeeded() } } diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt index 5566482738..f17ca32cce 100644 --- a/src/com/android/launcher3/model/ModelTaskController.kt +++ b/src/com/android/launcher3/model/ModelTaskController.kt @@ -16,27 +16,34 @@ package com.android.launcher3.model -import com.android.launcher3.LauncherAppState +import android.content.Context import com.android.launcher3.LauncherModel import com.android.launcher3.LauncherModel.CallbackTask import com.android.launcher3.celllayout.CellPosMapper +import com.android.launcher3.dagger.ApplicationContext +import com.android.launcher3.icons.IconCache import com.android.launcher3.model.BgDataModel.FixedContainerItems import com.android.launcher3.model.data.ItemInfo +import com.android.launcher3.util.Executors.MAIN_EXECUTOR import com.android.launcher3.util.PackageUserKey import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder import java.util.Objects -import java.util.concurrent.Executor import java.util.function.Predicate +import javax.inject.Inject /** Class with utility methods and properties for running a LauncherModel Task */ -class ModelTaskController( - val app: LauncherAppState, +class ModelTaskController +@Inject +constructor( + @ApplicationContext val context: Context, + val iconCache: IconCache, val dataModel: BgDataModel, val allAppsList: AllAppsList, - private val model: LauncherModel, - private val uiExecutor: Executor, + val model: LauncherModel, ) { + private val uiExecutor = MAIN_EXECUTOR + /** Schedules a {@param task} to be executed on the current callbacks. */ fun scheduleCallbackTask(task: CallbackTask) { for (cb in model.callbacks) { @@ -78,7 +85,7 @@ class ModelTaskController( fun bindUpdatedWidgets(dataModel: BgDataModel) { val allWidgets = - WidgetsListBaseEntriesBuilder(app.context) + WidgetsListBaseEntriesBuilder(context) .build(dataModel.widgetsModel.widgetsByPackageItemForPicker) scheduleCallbackTask { it.bindAllWidgets(allWidgets) } } diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 0332775224..2650e03c63 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -16,7 +16,6 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -229,7 +228,7 @@ public class ModelWriter { }).executeOnModelThread(); } - private void notifyItemModified(ItemInfo item) { + public void notifyItemModified(ItemInfo item) { notifyOtherCallbacks(c -> c.bindItemsModified(Collections.singletonList(item))); } @@ -253,7 +252,7 @@ public class ModelWriter { item.onAddToDatabase(writer); writer.put(Favorites._ID, item.id); - mModel.getModelDbController().insert(Favorites.TABLE_NAME, writer.getValues(mContext)); + mModel.getModelDbController().insert(writer.getValues(mContext)); synchronized (mBgDataModel) { checkItemInfoLocked(item.id, item, stackTrace); mBgDataModel.addItem(mContext, item, true); @@ -292,7 +291,7 @@ public class ModelWriter { notifyDelete(items); enqueueDeleteRunnable(newModelTask(() -> { for (ItemInfo item : items) { - mModel.getModelDbController().delete(TABLE_NAME, itemIdMatch(item.id), null); + mModel.getModelDbController().delete(itemIdMatch(item.id), null); mBgDataModel.removeItem(mContext, item); verifier.verifyModel(); } @@ -307,12 +306,12 @@ public class ModelWriter { notifyDelete(Collections.singleton(info)); enqueueDeleteRunnable(newModelTask(() -> { - mModel.getModelDbController().delete(Favorites.TABLE_NAME, + mModel.getModelDbController().delete( Favorites.CONTAINER + "=" + info.id, null); mBgDataModel.removeItem(mContext, info.getContents()); info.getContents().clear(); - mModel.getModelDbController().delete(Favorites.TABLE_NAME, + mModel.getModelDbController().delete( Favorites._ID + "=" + info.id, null); mBgDataModel.removeItem(mContext, info); verifier.verifyModel(); @@ -411,7 +410,7 @@ public class ModelWriter { @Override public void runImpl() { mModel.getModelDbController().update( - TABLE_NAME, mWriter.get().getValues(mContext), itemIdMatch(mItemId), null); + mWriter.get().getValues(mContext), itemIdMatch(mItemId), null); updateItemArrays(mItem, mItemId); } } @@ -433,7 +432,7 @@ public class ModelWriter { ItemInfo item = mItems.get(i); final int itemId = item.id; mModel.getModelDbController().update( - TABLE_NAME, mValues.get(i), itemIdMatch(itemId), null); + mValues.get(i), itemIdMatch(itemId), null); updateItemArrays(item, itemId); } t.commit(); diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index a2160422b2..a3561eda4d 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -52,11 +52,11 @@ public class PackageInstallStateChangedTask implements ModelUpdateTask { try { // For instant apps we do not get package-add. Use setting events to update // any pinned icons. - Context context = taskController.getApp().getContext(); + Context context = taskController.getContext(); ApplicationInfo ai = context .getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0); if (InstantAppResolver.newInstance(context).isInstantApp(ai)) { - taskController.getApp().getModel().newModelCallbacks() + taskController.getModel().newModelCallbacks() .onPackageAdded(ai.packageName, mInstallInfo.user); } } catch (PackageManager.NameNotFoundException e) { diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 3cdb2500e1..04f3faa194 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -38,7 +38,6 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.launcher3.Flags; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel.ModelUpdateTask; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.config.FeatureFlags; @@ -106,9 +105,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { @Override public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel, @NonNull AllAppsList appsList) { - final LauncherAppState app = taskController.getApp(); - final Context context = app.getContext(); - final IconCache iconCache = app.getIconCache(); + final Context context = taskController.getContext(); + final IconCache iconCache = taskController.getIconCache(); final String[] packages = mPackages; final int packageCount = packages.length; @@ -433,7 +431,7 @@ public class PackageUpdatedTask implements ModelUpdateTask { // Load widgets for the new package. Changes due to app updates are handled through // AppWidgetHost events, this is just to initialize the long-press options. for (int i = 0; i < packageCount; i++) { - dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser)); + dataModel.widgetsModel.update(new PackageUserKey(packages[i], mUser)); } taskController.bindUpdatedWidgets(dataModel); } diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java index 9e3f0e1aa2..9ae8092345 100644 --- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java +++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.pm.LauncherApps; import android.os.UserHandle; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; import com.android.launcher3.util.ApplicationInfoWrapper; import com.android.launcher3.util.PackageUserKey; @@ -43,9 +42,10 @@ public class SdCardAvailableReceiver extends BroadcastReceiver { private final Context mContext; private final Set<PackageUserKey> mPackages; - public SdCardAvailableReceiver(LauncherAppState app, Set<PackageUserKey> packages) { - mModel = app.getModel(); - mContext = app.getContext(); + public SdCardAvailableReceiver( + Context context, LauncherModel model, Set<PackageUserKey> packages) { + mContext = context; + mModel = model; mPackages = packages; } diff --git a/src/com/android/launcher3/model/SessionFailureTask.kt b/src/com/android/launcher3/model/SessionFailureTask.kt index 8baf568ace..6ed5178ed7 100644 --- a/src/com/android/launcher3/model/SessionFailureTask.kt +++ b/src/com/android/launcher3/model/SessionFailureTask.kt @@ -33,9 +33,9 @@ class SessionFailureTask(val packageName: String, val user: UserHandle) : ModelU dataModel: BgDataModel, apps: AllAppsList, ) { - val iconCache = taskController.app.iconCache + val iconCache = taskController.iconCache val isAppArchived = - ApplicationInfoWrapper(taskController.app.context, packageName, user).isArchived() + ApplicationInfoWrapper(taskController.context, packageName, user).isArchived() synchronized(dataModel) { if (isAppArchived) { val updatedItems = mutableListOf<WorkspaceItemInfo>() diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.kt b/src/com/android/launcher3/model/ShortcutsChangedTask.kt index 56e9e43d3a..d6759e2d21 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.kt +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.kt @@ -40,8 +40,7 @@ class ShortcutsChangedTask( dataModel: BgDataModel, apps: AllAppsList, ) { - val app = taskController.app - val context = app.context + val context = taskController.context // Find WorkspaceItemInfo's that have changed on the workspace. val matchingWorkspaceItems = ArrayList<WorkspaceItemInfo>() @@ -88,7 +87,7 @@ class ShortcutsChangedTask( .filter { itemInfo: WorkspaceItemInfo -> shortcutId == itemInfo.deepShortcutId } .forEach { workspaceItemInfo: WorkspaceItemInfo -> workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context) - app.iconCache.getShortcutIcon( + taskController.iconCache.getShortcutIcon( workspaceItemInfo, CacheableShortcutInfo(fullDetails, infoWrapper), ) diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index 3dc5ff3b57..4d28ccb42d 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -23,7 +23,6 @@ import android.os.UserHandle; import androidx.annotation.NonNull; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel.ModelUpdateTask; import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -55,8 +54,7 @@ public class UserLockStateChangedTask implements ModelUpdateTask { @Override public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel, @NonNull AllAppsList apps) { - LauncherAppState app = taskController.getApp(); - Context context = app.getContext(); + Context context = taskController.getContext(); HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>(); if (mIsUserUnlocked) { @@ -92,7 +90,7 @@ public class UserLockStateChangedTask implements ModelUpdateTask { } si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER; si.updateFromDeepShortcutInfo(shortcut, context); - app.getIconCache().getShortcutIcon(si, shortcut); + taskController.getIconCache().getShortcutIcon(si, shortcut); } else { si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER; } diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index 52b142db67..f2144c0e3a 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -27,6 +27,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.ApplicationContext; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.cache.CachedObject; import com.android.launcher3.model.data.PackageItemInfo; @@ -54,6 +55,8 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import javax.inject.Inject; + /** * Widgets data model that is used by the adapters of the widget views and controllers. * @@ -68,6 +71,29 @@ public class WidgetsModel { private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsByPackageItem = new HashMap<>(); @Nullable private WidgetValidityCheckForPicker mWidgetValidityCheckForPicker = null; + private final Context mContext; + private final InvariantDeviceProfile mIdp; + private final IconCache mIconCache; + private final AppFilter mAppFilter; + + @Inject + public WidgetsModel( + @ApplicationContext Context context, + InvariantDeviceProfile idp, + IconCache iconCache, + AppFilter appFilter) { + mContext = context; + mIdp = idp; + mIconCache = iconCache; + mAppFilter = appFilter; + } + + public WidgetsModel(Context context) { + this(context, + LauncherAppState.getIDP(context), + LauncherAppState.getInstance(context).getIconCache(), new AppFilter(context)); + } + /** * Returns all widgets keyed by their component key. */ @@ -128,36 +154,33 @@ public class WidgetsModel { * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise * only widgets and shortcuts associated with the package/user are. */ - public List<CachedObject> update( - LauncherAppState app, @Nullable PackageUserKey packageUser) { + public List<CachedObject> update(@Nullable PackageUserKey packageUser) { if (!WIDGETS_ENABLED) { return new ArrayList<>(); } Preconditions.assertWorkerThread(); - Context context = app.getContext(); final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>(); List<CachedObject> updatedItems = new ArrayList<>(); try { - InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); // Widgets - WidgetManagerHelper widgetManager = new WidgetManagerHelper(context); + WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext); for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) { LauncherAppWidgetProviderInfo launcherWidgetInfo = - LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo); + LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo); widgetsAndShortcuts.add(new WidgetItem( - launcherWidgetInfo, idp, app.getIconCache(), app.getContext())); + launcherWidgetInfo, mIdp, mIconCache, mContext)); updatedItems.add(launcherWidgetInfo); } // Shortcuts for (ShortcutConfigActivityInfo info : - queryList(context, packageUser)) { - widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache())); + queryList(mContext, packageUser)) { + widgetsAndShortcuts.add(new WidgetItem(info, mIconCache)); updatedItems.add(info); } - setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser); + setWidgetsAndShortcuts(widgetsAndShortcuts, packageUser); } catch (Exception e) { if (!FeatureFlags.IS_STUDIO_BUILD && Utilities.isBinderSizeError(e)) { // the returned value may be incomplete and will not be refreshed until the next @@ -172,14 +195,14 @@ public class WidgetsModel { return updatedItems; } - private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts, - LauncherAppState app, @Nullable PackageUserKey packageUser) { + private synchronized void setWidgetsAndShortcuts( + ArrayList<WidgetItem> rawWidgetsShortcuts, @Nullable PackageUserKey packageUser) { if (DEBUG) { Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); } // Refresh the validity checker with latest app state. - mWidgetValidityCheckForPicker = new WidgetValidityCheckForPicker(app); + mWidgetValidityCheckForPicker = new WidgetValidityCheckForPicker(mIdp, mAppFilter); // Temporary cache for {@link PackageItemInfos} to avoid having to go through // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList} @@ -196,19 +219,17 @@ public class WidgetsModel { // add and update. mWidgetsByPackageItem.putAll(rawWidgetsShortcuts.stream() .filter(new WidgetFlagCheck()) - .flatMap(widgetItem -> getPackageUserKeys(app.getContext(), widgetItem).stream() + .flatMap(widgetItem -> getPackageUserKeys(mContext, widgetItem).stream() .map(key -> new Pair<>(packageItemInfoCache.getOrCreate(key), widgetItem))) .collect(groupingBy(pair -> pair.first, mapping(pair -> pair.second, toList())))); // Update each package entry - IconCache iconCache = app.getIconCache(); for (PackageItemInfo p : packageItemInfoCache.values()) { - iconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes()); + mIconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes()); } } - public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user, - LauncherAppState app) { + public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user) { if (!WIDGETS_ENABLED) { return; } @@ -220,11 +241,10 @@ public class WidgetsModel { WidgetItem item = items.get(i); if (item.user.equals(user)) { if (item.activityInfo != null) { - items.set(i, new WidgetItem(item.activityInfo, app.getIconCache())); + items.set(i, new WidgetItem(item.activityInfo, mIconCache)); } else { - items.set(i, new WidgetItem(item.widgetInfo, - app.getInvariantDeviceProfile(), app.getIconCache(), - app.getContext())); + items.set(i, new WidgetItem( + item.widgetInfo, mIdp, mIconCache, mContext)); } } } @@ -277,9 +297,9 @@ public class WidgetsModel { private final InvariantDeviceProfile mIdp; private final AppFilter mAppFilter; - WidgetValidityCheckForPicker(LauncherAppState app) { - mIdp = app.getInvariantDeviceProfile(); - mAppFilter = new AppFilter(app.getContext()); + WidgetValidityCheckForPicker(InvariantDeviceProfile idp, AppFilter appFilter) { + mIdp = idp; + mAppFilter = appFilter; } @Override diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt index 99f2837dd0..7b8f21866a 100644 --- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt +++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt @@ -18,6 +18,7 @@ package com.android.launcher3.model import android.annotation.SuppressLint import android.appwidget.AppWidgetProviderInfo import android.content.ComponentName +import android.content.Context import android.content.Intent import android.content.pm.LauncherApps import android.content.pm.LauncherApps.ShortcutQuery @@ -29,10 +30,10 @@ import android.util.Log import android.util.LongSparseArray import com.android.launcher3.Flags import com.android.launcher3.InvariantDeviceProfile -import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError import com.android.launcher3.icons.CacheableShortcutInfo +import com.android.launcher3.icons.IconCache import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG import com.android.launcher3.logging.FileLog import com.android.launcher3.model.data.AppInfo @@ -70,7 +71,10 @@ class WorkspaceItemProcessor( private val launcherApps: LauncherApps, private val pendingPackages: MutableSet<PackageUserKey>, private val shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo>, - private val app: LauncherAppState, + private val context: Context, + private val idp: InvariantDeviceProfile, + private val iconCache: IconCache, + private val isSafeMode: Boolean, private val bgDataModel: BgDataModel, private val widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?>, private val installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>, @@ -82,9 +86,7 @@ class WorkspaceItemProcessor( private val allDeepShortcuts: MutableList<CacheableShortcutInfo>, ) { - private val isSafeMode = app.isSafeModeEnabled private val tempPackageKey = PackageUserKey(null, null) - private val iconCache = app.iconCache /** * This is the entry point for processing 1 workspace item. This method is like the midfielder @@ -159,7 +161,7 @@ class WorkspaceItemProcessor( ) return } - val appInfoWrapper = ApplicationInfoWrapper(app.context, targetPkg, c.user) + val appInfoWrapper = ApplicationInfoWrapper(context, targetPkg, c.user) var validTarget = launcherApps.isPackageEnabled(targetPkg, c.user) // If it's a deep shortcut, we'll use pinned shortcuts to restore it @@ -306,7 +308,7 @@ class WorkspaceItemProcessor( ) return } - info = WorkspaceItemInfo(pinnedShortcut, app.context) + info = WorkspaceItemInfo(pinnedShortcut, context) // If the pinned deep shortcut is no longer published, // use the last saved icon instead of the default. val csi = CacheableShortcutInfo(pinnedShortcut, appInfoWrapper) @@ -369,7 +371,7 @@ class WorkspaceItemProcessor( info, activityInfo, userCache.getUserInfo(c.user), - ApiWrapper.INSTANCE[app.context], + ApiWrapper.INSTANCE[context], pmHelper, ) } @@ -529,7 +531,7 @@ class WorkspaceItemProcessor( (si == null) && (lapi == null) && !(Flags.enableSupportForArchiving() && - ApplicationInfoWrapper(app.context, component.packageName, c.user) + ApplicationInfoWrapper(context, component.packageName, c.user) .isArchived()) ) { // Restore never started @@ -553,7 +555,7 @@ class WorkspaceItemProcessor( if (si == null) 0 else (si.getProgress() * 100).toInt() appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo( - app.context, + context, appWidgetInfo.providerName, appWidgetInfo.user, ) @@ -563,7 +565,7 @@ class WorkspaceItemProcessor( WidgetSizes.updateWidgetSizeRangesAsync( appWidgetInfo.appWidgetId, lapi, - app.context, + context, appWidgetInfo.spanX, appWidgetInfo.spanY, ) @@ -586,7 +588,7 @@ class WorkspaceItemProcessor( " appWidgetId: ${c.appWidgetId}," + " component=${component}", ) - logWidgetInfo(app.invariantDeviceProfile, lapi) + logWidgetInfo(idp, lapi) } } c.checkAndAddItem(appWidgetInfo, bgDataModel, memoryLogger) diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java index 1a6d1786e6..17f1615d8d 100644 --- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java +++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java @@ -21,7 +21,7 @@ import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; import android.util.LongSparseArray; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.ItemInfo; @@ -31,23 +31,37 @@ import com.android.launcher3.util.IntSet; import java.util.ArrayList; +import javax.inject.Inject; + /** * Utility class to help find space for new workspace items */ public class WorkspaceItemSpaceFinder { + private BgDataModel mDataModel; + private InvariantDeviceProfile mIDP; + private LauncherModel mModel; + + @Inject + WorkspaceItemSpaceFinder( + BgDataModel dataModel, InvariantDeviceProfile idp, LauncherModel model) { + mDataModel = dataModel; + mIDP = idp; + mModel = model; + } + /** * Find a position on the screen for the given size or adds a new screen. * * @return screenId and the coordinates for the item in an int array of size 3. */ - public int[] findSpaceForItem(LauncherAppState app, BgDataModel dataModel, + public int[] findSpaceForItem( IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) { LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>(); // Use sBgItemsIdMap as all the items are already loaded. - synchronized (dataModel) { - for (ItemInfo info : dataModel.itemsIdMap) { + synchronized (mDataModel) { + for (ItemInfo info : mDataModel.itemsIdMap) { if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { ArrayList<ItemInfo> items = screenItems.get(info.screenId); if (items == null) { @@ -75,7 +89,7 @@ public class WorkspaceItemSpaceFinder { for (int screen = 0; screen < screenCount; screen++) { screenId = workspaceScreens.get(screen); if (!screensToExclude.contains(screenId) && findNextAvailableIconSpaceInScreen( - app, screenItems.get(screenId), coordinates, spanX, spanY)) { + screenItems.get(screenId), coordinates, spanX, spanY)) { // We found a space for it found = true; break; @@ -84,7 +98,7 @@ public class WorkspaceItemSpaceFinder { if (!found) { // Still no position found. Add a new screen to the end. - screenId = app.getModel().getModelDbController().getNewScreenId(); + screenId = mModel.getModelDbController().getNewScreenId(); // Save the screen id for binding in the workspace workspaceScreens.add(screenId); @@ -92,7 +106,7 @@ public class WorkspaceItemSpaceFinder { // If we still can't find an empty space, then God help us all!!! if (!findNextAvailableIconSpaceInScreen( - app, screenItems.get(screenId), coordinates, spanX, spanY)) { + screenItems.get(screenId), coordinates, spanX, spanY)) { throw new RuntimeException("Can't find space to add the item"); } } @@ -100,11 +114,8 @@ public class WorkspaceItemSpaceFinder { } private boolean findNextAvailableIconSpaceInScreen( - LauncherAppState app, ArrayList<ItemInfo> occupiedPos, - int[] xy, int spanX, int spanY) { - InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); - - GridOccupancy occupied = new GridOccupancy(profile.numColumns, profile.numRows); + ArrayList<ItemInfo> occupiedPos, int[] xy, int spanX, int spanY) { + GridOccupancy occupied = new GridOccupancy(mIDP.numColumns, mIDP.numRows); if (occupiedPos != null) { for (ItemInfo r : occupiedPos) { occupied.markCells(r, true); diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java index 9656ac10b2..4c792a7672 100644 --- a/src/com/android/launcher3/model/data/FolderInfo.java +++ b/src/com/android/launcher3/model/data/FolderInfo.java @@ -20,6 +20,9 @@ import static android.text.TextUtils.isEmpty; import static androidx.core.util.Preconditions.checkNotNull; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL; import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL; import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL; @@ -30,8 +33,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.Utilities; -import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderNameInfos; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom.Attribute; @@ -42,8 +43,6 @@ import com.android.launcher3.model.ModelWriter; import com.android.launcher3.util.ContentWriter; import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.OptionalInt; import java.util.stream.IntStream; @@ -52,18 +51,6 @@ import java.util.stream.IntStream; */ public class FolderInfo extends CollectionInfo { - public static final int NO_FLAGS = 0x00000000; - - /** - * The folder is locked in sorted mode - */ - public static final int FLAG_ITEMS_SORTED = 0x00000001; - - /** - * It is a work folder - */ - public static final int FLAG_WORK_FOLDER = 0x00000002; - /** * The multi-page animation has run for this folder */ @@ -95,8 +82,6 @@ public class FolderInfo extends CollectionInfo { } } - public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest"; - public int options; public FolderNameInfos suggestedFolderNames; @@ -106,61 +91,16 @@ public class FolderInfo extends CollectionInfo { */ private final ArrayList<ItemInfo> contents = new ArrayList<>(); - private ArrayList<FolderListener> mListeners = new ArrayList<>(); - public FolderInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER; } - /** Adds a app or shortcut to the contents ArrayList without animation. */ @Override public void add(@NonNull ItemInfo item) { - add(item, false /* animate */); - } - - /** - * Add an app or shortcut - * - * @param item - */ - public void add(ItemInfo item, boolean animate) { - add(item, getContents().size(), animate); - } - - /** - * Add an app or shortcut for a specified rank. - */ - public void add(ItemInfo item, int rank, boolean animate) { - if (!Folder.willAccept(item)) { + if (!willAcceptItemType(item.itemType)) { throw new RuntimeException("tried to add an illegal type into a folder"); } - - rank = Utilities.boundToRange(rank, 0, getContents().size()); - getContents().add(rank, item); - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onAdd(item, rank); - } - itemsChanged(animate); - } - - /** - * Remove an app or shortcut. Does not change the DB. - * - * @param item - */ - public void remove(ItemInfo item, boolean animate) { - removeAll(Collections.singletonList(item), animate); - } - - /** - * Remove all matching app or shortcut. Does not change the DB. - */ - public void removeAll(List<ItemInfo> items, boolean animate) { - contents.removeAll(items); - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onRemove(items); - } - itemsChanged(animate); + getContents().add(item); } /** @@ -197,28 +137,6 @@ public class FolderInfo extends CollectionInfo { writer.put(LauncherSettings.Favorites.OPTIONS, options); } - public void addListener(FolderListener listener) { - mListeners.add(listener); - } - - public void removeListener(FolderListener listener) { - mListeners.remove(listener); - } - - public void itemsChanged(boolean animate) { - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onItemsChanged(animate); - } - } - - public interface FolderListener { - void onAdd(ItemInfo item, int rank); - void onRemove(List<ItemInfo> item); - void onItemsChanged(boolean animate); - void onTitleChanged(CharSequence title); - - } - public boolean hasOption(int optionFlag) { return (options & optionFlag) != 0; } @@ -261,7 +179,6 @@ public class FolderInfo extends CollectionInfo { .build(); } - @Override public void setTitle(@Nullable CharSequence title, ModelWriter modelWriter) { // Updating label from null to empty is considered as false touch. // Retaining null title(ie., UNLABELED state) allows auto-labeling when new items added. @@ -289,10 +206,6 @@ public class FolderInfo extends CollectionInfo { if (modelWriter != null) { modelWriter.updateItemInDatabase(this); } - - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onTitleChanged(title); - } } /** @@ -401,4 +314,13 @@ public class FolderInfo extends CollectionInfo { } return LauncherAtom.ToState.TO_STATE_UNSPECIFIED; } + + /** + * Checks if {@code itemType} is a type that can be placed in folders. + */ + public static boolean willAcceptItemType(int itemType) { + return itemType == ITEM_TYPE_APPLICATION + || itemType == ITEM_TYPE_DEEP_SHORTCUT + || itemType == ITEM_TYPE_APP_PAIR; + } } diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 588e75959e..ad7696cd15 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -61,7 +61,6 @@ import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer; import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer; import com.android.launcher3.logger.LauncherAtom.WallpapersContainer; import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers; -import com.android.launcher3.model.ModelWriter; import com.android.launcher3.pm.UserCache; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ContentWriter; @@ -536,14 +535,6 @@ public class ItemInfo { } /** - * Sets the title of the item and writes to DB model if needed. - */ - public void setTitle(@Nullable final CharSequence title, - @Nullable final ModelWriter modelWriter) { - this.title = title; - } - - /** * Returns a string ID that is stable for a user session, but may not be persisted */ @Nullable diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java index 0640bf3672..a6f76c4d44 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicator.java +++ b/src/com/android/launcher3/pageindicators/PageIndicator.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.pageindicators; +import java.util.function.Consumer; + /** * Base class for a page indicator. */ @@ -27,6 +29,14 @@ public interface PageIndicator { void setMarkersCount(int numMarkers); /** + * This is only going to be used by the FolderPagedView's PageIndicator. A refactor is planned + * to separate the two purposes of this class, but in the meantime, this indicator will serve to + * let the folder snap to the page of its click, and also tell the PageIndicator not to draw + * arrows if the click listener is null (at least until after this is refactored). + */ + void setArrowClickListener(Consumer<Direction> listener); + + /** * Sets a flag indicating whether to pause scroll. * <p>Should be set to {@code true} while the screen is binding or new data is being applied, * and to {@code false} once done. This prevents animation conflicts due to scrolling during diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt new file mode 100644 index 0000000000..970d210ad9 --- /dev/null +++ b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 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.pageindicators + +interface PageIndicatorArrowClickListener { + fun onArrowClick(direction: Direction) +} + +enum class Direction { + END, + START, +} diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java index 37f51899aa..384f87623a 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java +++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java @@ -32,11 +32,13 @@ import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.IntProperty; +import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewOutlineProvider; @@ -51,9 +53,14 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.Themes; +import java.util.function.Consumer; + /** * {@link PageIndicator} which shows dots per page. The active page is shown with the current * accent color. + * <p> + * TODO(b/402258632): Split PageIndicatorDots into 2 different classes: FolderPageIndicator & + * WorkspacePageIndicator. A lot of the functionality in this class is only used by one UI purpose. */ public class PageIndicatorDots extends View implements Insettable, PageIndicator { @@ -68,6 +75,12 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150; private static final int ENTER_ANIMATION_DURATION = 400; + private static final int LARGE_HEIGHT_MULTIPLIER = 12; + private static final int SMALL_HEIGHT_MULTIPLIER = 4; + private static final int LARGE_WIDTH_MULTIPLIER = 5; + private static final int SMALL_WIDTH_MULTIPLIER = 3; + private static final float ARROW_TOUCH_BOX_FACTOR = 5f; + private static final int PAGE_INDICATOR_ALPHA = 255; private static final int DOT_ALPHA = 128; private static final float DOT_ALPHA_FRACTION = 0.5f; @@ -75,12 +88,14 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator private static final int VISIBLE_ALPHA = 255; private static final int INVISIBLE_ALPHA = 0; private Paint mPaginationPaint; + private Consumer<Direction> mOnArrowClickListener; // This value approximately overshoots to 1.5 times the original size. private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f; // This is used to optimize the onDraw method by not constructing a new RectF each draw. private static final RectF sTempRect = new RectF(); + private static final RectF sLastActiveRect = new RectF(); private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION = new FloatProperty<PageIndicatorDots>("current_position") { @@ -99,23 +114,27 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator private static final IntProperty<PageIndicatorDots> PAGINATION_ALPHA = new IntProperty<PageIndicatorDots>("pagination_alpha") { - @Override - public Integer get(PageIndicatorDots obj) { - return obj.mPaginationPaint.getAlpha(); - } + @Override + public Integer get(PageIndicatorDots obj) { + return obj.mPaginationPaint.getAlpha(); + } - @Override - public void setValue(PageIndicatorDots obj, int alpha) { - obj.mPaginationPaint.setAlpha(alpha); - obj.invalidate(); - } - }; + @Override + public void setValue(PageIndicatorDots obj, int alpha) { + obj.mPaginationPaint.setAlpha(alpha); + obj.invalidate(); + } + }; private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper()); private final float mDotRadius; private final float mGapWidth; private final float mCircleGap; private final boolean mIsRtl; + private final VectorDrawable mArrowRight; + private final VectorDrawable mArrowLeft; + private final Rect mArrowRightBounds = new Rect(); + private final Rect mArrowLeftBounds = new Rect(); private int mNumPages; private int mActivePage; @@ -167,6 +186,8 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator : DOT_GAP_FACTOR * mDotRadius; setOutlineProvider(new MyOutlineProver()); mIsRtl = Utilities.isRtl(getResources()); + mArrowRight = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_end); + mArrowLeft = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_start); } @Override @@ -405,6 +426,11 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator } @Override + public void setArrowClickListener(Consumer<Direction> listener) { + mOnArrowClickListener = listener; + } + + @Override public void setPauseScroll(boolean pause, boolean isTwoPanels) { mIsTwoPanels = isTwoPanels; @@ -419,11 +445,16 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO(b/394355070): Verify Folder Entry Animation works correctly with visual updates - // Add extra spacing of mDotRadius on all sides so than entry animation could be run. + // Add extra spacing of mDotRadius on all sides so than entry animation could be run + // and so the hitboxes of arrows can be clicked easier. int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ? - MeasureSpec.getSize(widthMeasureSpec) : (int) ((mNumPages * 3 + 2) * mDotRadius); + MeasureSpec.getSize(widthMeasureSpec) + : (int) ((mNumPages * ((enableLauncherVisualRefresh()) + ? LARGE_WIDTH_MULTIPLIER : SMALL_WIDTH_MULTIPLIER) + 2) * mDotRadius); int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY - ? MeasureSpec.getSize(heightMeasureSpec) : (int) (4 * mDotRadius); + ? MeasureSpec.getSize(heightMeasureSpec) + : (int) (((enableLauncherVisualRefresh()) + ? LARGE_HEIGHT_MULTIPLIER : SMALL_HEIGHT_MULTIPLIER) * mDotRadius); setMeasuredDimension(width, height); } @@ -443,18 +474,51 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator float y = getHeight() / 2; if (mEntryAnimationRadiusFactors != null) { - // During entry animation, only draw the circles - // TODO(b/394355070): Verify Folder Entry Animation works correctly - visual updates + if (enableLauncherVisualRefresh()) { + x -= mDotRadius; + if (mIsRtl) { + x = getWidth() - x; + circleGap = -circleGap; + } + sTempRect.top = y - mDotRadius; + sTempRect.bottom = y + mDotRadius; - if (mIsRtl) { - x = getWidth() - x; - circleGap = -circleGap; - } - for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) { - mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA); - canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], - mPaginationPaint); - x += circleGap; + for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) { + if (i == mActivePage) { + if (mIsRtl) { + sTempRect.left = x - (mDotRadius * 3); + sTempRect.right = x + mDotRadius; + x += circleGap - (mDotRadius * 2); + } else { + sTempRect.left = x - mDotRadius; + sTempRect.right = x + (mDotRadius * 3); + x += circleGap + (mDotRadius * 2); + } + scale(sTempRect, mEntryAnimationRadiusFactors[i]); + float scaledRadius = mDotRadius * mEntryAnimationRadiusFactors[i]; + mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA); + canvas.drawRoundRect(sTempRect, scaledRadius, scaledRadius, + mPaginationPaint); + } else { + mPaginationPaint.setAlpha(DOT_ALPHA); + canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], + mPaginationPaint); + x += circleGap; + } + } + } else { + // During entry animation, only draw the circles + + if (mIsRtl) { + x = getWidth() - x; + circleGap = -circleGap; + } + for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) { + mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA); + canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], + mPaginationPaint); + x += circleGap; + } } } else { // Save the current alpha value, so we can reset to it again after drawing the dots @@ -468,12 +532,31 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator sTempRect.bottom = y + mDotRadius; sTempRect.left = x - diameter; - float posDif = Math.abs(mLastPosition - mCurrentPosition); + float currentPosition = mCurrentPosition; + float lastPosition = mLastPosition; + + if (mIsRtl) { + currentPosition = mNumPages - currentPosition - 1; + lastPosition = mNumPages - lastPosition - 1; + } + float posDif = Math.abs(lastPosition - currentPosition); float boundedPosition = (posDif > 1) - ? Math.round(mCurrentPosition) - : mCurrentPosition; + ? Math.round(currentPosition) + : currentPosition; float bounceProgress = (posDif > 1) ? posDif - 1 : 0; - float bounceAdjustment = Math.abs(mCurrentPosition - boundedPosition) * diameter; + float bounceAdjustment = Math.abs(currentPosition - boundedPosition) * diameter; + + if (mOnArrowClickListener != null && boundedPosition >= 1) { + // Here we draw the Left Arrow + mArrowLeft.setAlpha(alpha); + int size = (int) (mGapWidth * 4); + mArrowLeftBounds.left = (int) (sTempRect.left - mGapWidth - size); + mArrowLeftBounds.top = (int) (y - size / 2); + mArrowLeftBounds.right = (int) (sTempRect.left - mGapWidth); + mArrowLeftBounds.bottom = (int) (y + size / 2); + mArrowLeft.setBounds(mArrowLeftBounds); + mArrowLeft.draw(canvas); + } // Here we draw the dots, one at a time from the left-most dot to the right-most dot // 1.0 => 000000 000000111111 000000 @@ -495,10 +578,10 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator // While the animation is shifting the active pagination dots size from // the previously active one, to the newly active dot, there is no bounce // adjustment. The bounce happens in the "Overshoot" phase of the animation. - // mLastPosition is used to determine when the currentPosition is just + // lastPosition is used to determine when the currentPosition is just // leaving the page, or if it is in the overshoot phase. if (boundedPosition == i && bounceProgress != 0) { - if (mLastPosition < mCurrentPosition) { + if (lastPosition < currentPosition) { sTempRect.left -= bounceAdjustment; } else { sTempRect.right += bounceAdjustment; @@ -507,19 +590,34 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator } else { sTempRect.right = sTempRect.left + diameter; - if (mLastPosition == i && bounceProgress != 0) { - if (mLastPosition > mCurrentPosition) { + if (lastPosition == i && bounceProgress != 0) { + if (lastPosition > currentPosition) { sTempRect.left += bounceAdjustment; } else { sTempRect.right -= bounceAdjustment; } } } + if (Math.round(mCurrentPosition) == i) { + sLastActiveRect.set(sTempRect); + } canvas.drawRoundRect(sTempRect, mDotRadius, mDotRadius, mPaginationPaint); // TODO(b/394355070) Verify RTL experience works correctly with visual updates sTempRect.left = sTempRect.right + mGapWidth; } + + if (mOnArrowClickListener != null && boundedPosition <= mNumPages - 2) { + // Here we draw the Right Arrow + mArrowRight.setAlpha(alpha); + int size = (int) (mGapWidth * 4); + mArrowRightBounds.left = (int) sTempRect.left; + mArrowRightBounds.top = (int) (y - size / 2); + mArrowRightBounds.right = (int) (int) (sTempRect.left + size); + mArrowRightBounds.bottom = (int) (y + size / 2); + mArrowRight.setBounds(mArrowRightBounds); + mArrowRight.draw(canvas); + } } else { // Here we draw the dots mPaginationPaint.setAlpha((int) (alpha * DOT_ALPHA_FRACTION)); @@ -538,6 +636,38 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator } } + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (mOnArrowClickListener == null) { + // No - Op. Don't care about touch events + } else if ((mIsRtl && withinExpandedBounds(mArrowRightBounds, ev)) + || (!mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev))) { + mOnArrowClickListener.accept(Direction.START); + } else if ((mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev)) + || (!mIsRtl && withinExpandedBounds(mArrowRightBounds, ev))) { + mOnArrowClickListener.accept(Direction.END); + } + return super.onTouchEvent(ev); + } + + // For larger Touch box + private boolean withinExpandedBounds(Rect rect, MotionEvent ev) { + RectF scaledRect = new RectF(rect); + scale(scaledRect, ARROW_TOUCH_BOX_FACTOR); + return scaledRect.contains(ev.getX(), ev.getY()); + } + + private static void scale(RectF rect, float factor) { + float horizontalAdjustment = rect.width() * (factor - 1) / 2; + float verticalAdjustment = rect.height() * (factor - 1) / 2; + + rect.top -= verticalAdjustment; + rect.bottom += verticalAdjustment; + + rect.left -= horizontalAdjustment; + rect.right += horizontalAdjustment; + } + private RectF getActiveRect() { float startCircle = (int) mCurrentPosition; float delta = mCurrentPosition - startCircle; @@ -590,8 +720,8 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator @Override public void getOutline(View view, Outline outline) { if (mEntryAnimationRadiusFactors == null) { - // TODO(b/394355070): Verify Outline works correctly with visual updates - RectF activeRect = getActiveRect(); + RectF activeRect = enableLauncherVisualRefresh() + ? sLastActiveRect : getActiveRect(); outline.setRoundRect( (int) activeRect.left, (int) activeRect.top, diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index aad1400865..39f68bfe70 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -16,9 +16,12 @@ package com.android.launcher3.popup; +import static android.multiuser.Flags.enableMovingContentIntoPrivateSpace; + import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; +import static com.android.launcher3.allapps.AlphabeticalAppsList.PRIVATE_SPACE_PACKAGE; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -65,6 +68,7 @@ import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -207,7 +211,10 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext> container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate( R.layout.popup_container, launcher.getDragLayer(), false); container.configureForLauncher(launcher, item); - container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts); + boolean shouldHideSystemShortcuts = enableMovingContentIntoPrivateSpace() + && Objects.equals(item.getTargetPackage(), PRIVATE_SPACE_PACKAGE); + container.populateAndShowRows(icon, deepShortcutCount, + shouldHideSystemShortcuts ? Collections.emptyList() : systemShortcuts); launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item)); container.requestFocus(); return container; diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index 5c1a7553a5..95110329d3 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -26,7 +26,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.dot.DotInfo; -import com.android.launcher3.dot.FolderDotInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.FolderInfo; @@ -76,11 +75,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan ((BubbleTextView) v).applyDotState(info, true /* animate */); } else if (v instanceof FolderIcon icon && info instanceof FolderInfo fi && fi.anyMatch(matcher)) { - FolderDotInfo folderDotInfo = new FolderDotInfo(); - for (ItemInfo si : fi.getContents()) { - folderDotInfo.addDotInfo(getDotInfoForItem(si)); - } - icon.setDotInfo(folderDotInfo); + icon.updateDotInfo(); } // process all the shortcuts diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.kt b/src/com/android/launcher3/provider/LauncherDbUtils.kt index c92328d8a3..36413715e0 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.kt +++ b/src/com/android/launcher3/provider/LauncherDbUtils.kt @@ -26,19 +26,17 @@ import android.os.PersistableBundle import android.os.Process import android.os.UserManager import android.text.TextUtils -import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import com.android.launcher3.Utilities +import com.android.launcher3.dagger.LauncherComponentProvider.appComponent import com.android.launcher3.icons.IconCache -import com.android.launcher3.model.LoaderCursor import com.android.launcher3.model.UserManagerState import com.android.launcher3.pm.PinRequestHelper import com.android.launcher3.pm.UserCache import com.android.launcher3.shortcuts.ShortcutKey import com.android.launcher3.util.IntArray import com.android.launcher3.util.IntSet -import com.android.launcher3.util.PackageManagerHelper /** A set of utility methods for Launcher DB used for DB updates and migration. */ object LauncherDbUtils { @@ -155,12 +153,11 @@ object LauncherDbUtils { null, null, ) - val pmHelper = PackageManagerHelper.INSTANCE[context] val ums = UserManagerState() ums.run { init(UserCache.INSTANCE[context], context.getSystemService(UserManager::class.java)) } - val lc = LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper, null) + val lc = context.appComponent.loaderCursorFactory.createLoaderCursor(c, ums, null) val deletedShortcuts = IntSet() while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 23941bb1e6..f6ee26baa6 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -80,6 +80,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -206,7 +207,8 @@ public class RestoreDbTask { LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger.Companion.newInstance(context); task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger); - task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger); + task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger, + () -> new AppWidgetHost(context, APPWIDGET_HOST_ID)); t.commit(); return true; } catch (Exception e) { @@ -438,14 +440,13 @@ public class RestoreDbTask { @WorkerThread @VisibleForTesting void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller, - LauncherRestoreEventLogger restoreEventLogger) { + LauncherRestoreEventLogger restoreEventLogger, Supplier<AppWidgetHost> hostSupplier) { LauncherPrefs lp = LauncherPrefs.get(context); if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) { - AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID); restoreAppWidgetIds(context, controller, restoreEventLogger, IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(), IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(), - host); + hostSupplier.get()); } else { FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore"); } diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index 2cc4909712..f86fd6ac33 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -22,6 +22,7 @@ import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE; import static com.android.app.animation.Interpolators.FINAL_FRAME; import static com.android.app.animation.Interpolators.INSTANT; import static com.android.app.animation.Interpolators.LINEAR; +import static com.android.app.animation.Interpolators.clampToProgress; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; @@ -39,6 +40,7 @@ import android.view.animation.Interpolator; import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.states.StateAnimationConfig; @@ -53,10 +55,10 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { private static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = 0.1f; private static final float ALL_APPS_STAGGERED_FADE_THRESHOLD = 0.5f; - public static final Interpolator ALL_APPS_SCRIM_RESPONDER = + private static final Interpolator ALL_APPS_SCRIM_RESPONDER = Interpolators.clampToProgress( LINEAR, ALL_APPS_SCRIM_VISIBLE_THRESHOLD, ALL_APPS_STAGGERED_FADE_THRESHOLD); - public static final Interpolator ALL_APPS_CLAMPING_RESPONDER = + private static final Interpolator ALL_APPS_CLAMPING_RESPONDER = Interpolators.clampToProgress( LINEAR, 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, @@ -207,7 +209,16 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { } config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE); config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE); - if (launcher.getDeviceProfile().isPhone) { + if (Flags.allAppsBlur()) { + if (!config.isUserControlled()) { + config.setInterpolator(ANIM_DEPTH, EMPHASIZED_DECELERATE); + } + config.setInterpolator(ANIM_WORKSPACE_FADE, + clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1)); + config.setInterpolator(ANIM_HOTSEAT_FADE, + clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1)); + } else if (launcher.getDeviceProfile().isPhone) { + // On phones without blur, reveal the workspace and hotseat when leaving All Apps. config.setInterpolator(ANIM_WORKSPACE_FADE, INSTANT); config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT); config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER; @@ -253,7 +264,14 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { } config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE); config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE); - if (launcher.getDeviceProfile().isPhone) { + if (Flags.allAppsBlur()) { + config.setInterpolator(ANIM_DEPTH, LINEAR); + config.setInterpolator(ANIM_WORKSPACE_FADE, + clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD)); + config.setInterpolator(ANIM_HOTSEAT_FADE, + clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD)); + } else if (launcher.getDeviceProfile().isPhone) { + // On phones without blur, hide the workspace and hotseat when entering All Apps. config.setInterpolator(ANIM_WORKSPACE_FADE, FINAL_FRAME); config.setInterpolator(ANIM_HOTSEAT_FADE, FINAL_FRAME); config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER; diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java index d72e6f9e39..576f17616b 100644 --- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java +++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java @@ -131,7 +131,7 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe } boolean isInAllAppsBottomSheet = mLauncher.isInState(ALL_APPS) - && mLauncher.getDeviceProfile().isTablet; + && mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet(); final boolean result; if (mLongPressState == STATE_COMPLETED) { diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java index 9910dc2e70..c2c1fee561 100644 --- a/src/com/android/launcher3/util/ContentWriter.java +++ b/src/com/android/launcher3/util/ContentWriter.java @@ -23,7 +23,6 @@ import android.os.UserHandle; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.model.ModelDbController; @@ -107,7 +106,7 @@ public class ContentWriter { public int commit() { if (mCommitParams != null) { return mCommitParams.mDbController.update( - Favorites.TABLE_NAME, getValues(mContext), + getValues(mContext), mCommitParams.mWhere, mCommitParams.mSelectionArgs); } return 0; diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt index ebf4656c61..acb3c4ee12 100644 --- a/src/com/android/launcher3/util/ItemInflater.kt +++ b/src/com/android/launcher3/util/ItemInflater.kt @@ -24,6 +24,7 @@ import android.view.View.OnClickListener import android.view.View.OnFocusChangeListener import android.view.ViewGroup import com.android.launcher3.BubbleTextView +import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.R import com.android.launcher3.apppairs.AppPairIcon @@ -46,10 +47,11 @@ class ItemInflater<T>( private val widgetHolder: LauncherWidgetHolder, private val clickListener: OnClickListener, private val focusListener: OnFocusChangeListener, - private val defaultParent: ViewGroup + private val defaultParent: ViewGroup, ) where T : Context, T : ActivityContext { - private val widgetInflater = WidgetInflater(context) + private val widgetInflater = + WidgetInflater(context, LauncherAppState.getInstance(context).isSafeModeEnabled) @JvmOverloads fun inflateItem(item: ItemInfo, writer: ModelWriter, nullableParent: ViewGroup? = null): View? { @@ -75,7 +77,7 @@ class ItemInflater<T>( R.layout.folder_icon, context, parent, - item as FolderInfo + item as FolderInfo, ) Favorites.ITEM_TYPE_APP_PAIR -> return AppPairIcon.inflateIcon( @@ -83,7 +85,7 @@ class ItemInflater<T>( context, parent, item as AppPairInfo, - BubbleTextView.DISPLAY_WORKSPACE + BubbleTextView.DISPLAY_WORKSPACE, ) Favorites.ITEM_TYPE_APPWIDGET, Favorites.ITEM_TYPE_CUSTOM_APPWIDGET -> diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java index 7a40abe62b..53e0bce182 100644 --- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java +++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java @@ -123,6 +123,32 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { } } + /** + * Same as {@link #register(Runnable, int, String...)} above but with additional permission + * params utilizine the original {@link Context}. + */ + @AnyThread + public void register(@Nullable Runnable completionCallback, + String broadcastPermission, int flags, String... actions) { + if (Looper.myLooper() == mHandler.getLooper()) { + registerInternal(mContext, completionCallback, broadcastPermission, flags, actions); + } else { + mHandler.post(() -> registerInternal(mContext, completionCallback, broadcastPermission, + flags, actions)); + } + } + + /** Register broadcast receiver with permission and run completion callback if passed. */ + @AnyThread + private void registerInternal( + @NonNull Context context, @Nullable Runnable completionCallback, + String broadcastPermission, int flags, String... actions) { + context.registerReceiver(this, getFilter(actions), broadcastPermission, null, flags); + if (completionCallback != null) { + completionCallback.run(); + } + } + /** Same as {@link #register(Runnable, String...)} above but with pkg name. */ @AnyThread public void registerPkgActions(@Nullable String pkg, String... actions) { diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 82cc40d93b..8c01c5999f 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -19,6 +19,7 @@ import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS; @@ -219,6 +220,11 @@ public class OptionsPopupView<T extends Context & ActivityContext> extends Arrow OptionsPopupView::enterHomeGardening)); } options.add(new OptionItem(launcher, + R.string.all_apps_home_screen, + R.drawable.ic_apps, + LAUNCHER_ALL_APPS_TAP_OR_LONGPRESS, + OptionsPopupView::enterAllApps)); + options.add(new OptionItem(launcher, R.string.settings_button_text, R.drawable.ic_setting, LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS, @@ -226,6 +232,20 @@ public class OptionsPopupView<T extends Context & ActivityContext> extends Arrow return options; } + /** + * Used by the options to open All Apps, uses an intent as to not tie the implementation of + * opening All Apps with OptionsPopup, instead it uses the public API to open All Apps. + */ + public static boolean enterAllApps(View view) { + Launcher launcher = Launcher.getLauncher(view.getContext()); + launcher.startActivity( + new Intent(Intent.ACTION_ALL_APPS) + .setComponent(launcher.getComponentName()) + .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) + ); + return true; + } + private static boolean enterHomeGardening(View view) { Launcher launcher = Launcher.getLauncher(view.getContext()); launcher.getStateManager().goToState(EDIT_MODE); diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index ce58de1ee5..ec71f3118a 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -54,8 +54,7 @@ public class ScrimView extends View implements Insettable { } @Override - public void setInsets(Rect insets) { - } + public void setInsets(Rect insets) {} @Override public boolean hasOverlappingRendering() { diff --git a/src/com/android/launcher3/widget/WidgetInflater.kt b/src/com/android/launcher3/widget/WidgetInflater.kt index d6cadc73a8..03f680abb4 100644 --- a/src/com/android/launcher3/widget/WidgetInflater.kt +++ b/src/com/android/launcher3/widget/WidgetInflater.kt @@ -19,14 +19,21 @@ package com.android.launcher3.widget import android.content.Context import com.android.launcher3.BuildConfig import com.android.launcher3.Launcher -import com.android.launcher3.LauncherAppState import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError +import com.android.launcher3.dagger.ApplicationContext import com.android.launcher3.logging.FileLog import com.android.launcher3.model.data.LauncherAppWidgetInfo import com.android.launcher3.qsb.QsbContainerView +import javax.inject.Inject +import javax.inject.Named /** Utility class for handling widget inflation taking into account all the restore state updates */ -class WidgetInflater(private val context: Context) { +class WidgetInflater +@Inject +constructor( + @ApplicationContext private val context: Context, + @Named("SAFE_MODE") private val isSafeModeEnabled: Boolean, +) { private val widgetHelper = WidgetManagerHelper(context) @@ -41,9 +48,8 @@ class WidgetInflater(private val context: Context) { ) } } - if (LauncherAppState.INSTANCE.get(context).isSafeModeEnabled) { - return InflationResult(TYPE_PENDING) - } + if (isSafeModeEnabled) return InflationResult(TYPE_PENDING) + val appWidgetInfo: LauncherAppWidgetProviderInfo? var removalReason = "" @RestoreError var logReason = RestoreError.OTHER_WIDGET_INFLATION_FAIL diff --git a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java index e94f3a065d..185c3ee9ed 100644 --- a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java +++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java @@ -26,9 +26,12 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.pageindicators.Direction; import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.views.ActivityContext; +import java.util.function.Consumer; + /** * Supports two indicator colors, dedicated for personal and work tabs. */ @@ -78,6 +81,11 @@ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageInd } @Override + public void setArrowClickListener(Consumer<Direction> listener) { + // No-Op. All Apps doesn't need accessibility arrows for single click navigation. + } + + @Override public boolean hasOverlappingRendering() { return false; } diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt index a13d63b2ba..6a0d774a45 100644 --- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt +++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt @@ -53,7 +53,7 @@ DeviceProfile: bottomSheetTopPadding: 146.0px (55.61905dp) bottomSheetOpenDuration: 267 bottomSheetCloseDuration: 267 - bottomSheetWorkspaceScale: 1.0 + bottomSheetWorkspaceScale: 0.97 bottomSheetDepth: 0.0 allAppsShiftRange: 2400.0px (914.2857dp) allAppsOpenDuration: 600 diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt index 3c24885e73..9e2397c62b 100644 --- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt +++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt @@ -53,7 +53,7 @@ DeviceProfile: bottomSheetTopPadding: 146.0px (55.61905dp) bottomSheetOpenDuration: 267 bottomSheetCloseDuration: 267 - bottomSheetWorkspaceScale: 1.0 + bottomSheetWorkspaceScale: 0.97 bottomSheetDepth: 0.0 allAppsShiftRange: 2400.0px (914.2857dp) allAppsOpenDuration: 600 diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt index 5e06513070..f25ab42f87 100644 --- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt +++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt @@ -53,7 +53,7 @@ DeviceProfile: bottomSheetTopPadding: 114.0px (43.42857dp) bottomSheetOpenDuration: 267 bottomSheetCloseDuration: 267 - bottomSheetWorkspaceScale: 1.0 + bottomSheetWorkspaceScale: 0.97 bottomSheetDepth: 0.0 allAppsShiftRange: 1080.0px (411.42856dp) allAppsOpenDuration: 600 diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt index d1079880c3..053dd62a08 100644 --- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt +++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt @@ -53,7 +53,7 @@ DeviceProfile: bottomSheetTopPadding: 114.0px (43.42857dp) bottomSheetOpenDuration: 267 bottomSheetCloseDuration: 267 - bottomSheetWorkspaceScale: 1.0 + bottomSheetWorkspaceScale: 0.97 bottomSheetDepth: 0.0 allAppsShiftRange: 1080.0px (411.42856dp) allAppsOpenDuration: 600 diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java index 47110fa0e6..f7723392d4 100644 --- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java +++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.celllayout; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.TestUtil.runOnExecutorSync; @@ -89,7 +88,7 @@ public class FavoriteItemsTransaction { item.onAddToDatabase(writer); writer.put(LauncherSettings.Favorites._ID, i); - controller.insert(TABLE_NAME, writer.getValues(mContext)); + controller.insert(writer.getValues(mContext)); } for (int i = 0; i < containerItems.size(); i++) { @@ -97,7 +96,7 @@ public class FavoriteItemsTransaction { ItemInfo item = containerItems.get(i); item.onAddToDatabase(writer); writer.put(LauncherSettings.Favorites._ID, count + i); - controller.insert(TABLE_NAME, writer.getValues(mContext)); + controller.insert(writer.getValues(mContext)); } transaction.commit(); } diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt index 2e556e8d79..3405cae355 100644 --- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt +++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt @@ -44,7 +44,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { private fun fillWithWidgets( widgetRect: WidgetRect, transaction: FavoriteItemsTransaction, - screenId: Int + screenId: Int, ): FavoriteItemsTransaction { val initX = widgetRect.cellX val initY = widgetRect.cellY @@ -76,7 +76,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { appComponentName = ComponentName( InstrumentationRegistry.getInstrumentation().context.packageName, - TEST_ACTIVITY_PACKAGE_PREFIX + testAppName + TEST_ACTIVITY_PACKAGE_PREFIX + testAppName, ) } @@ -92,7 +92,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { private fun addCorrespondingWidgetRect( widgetRect: WidgetRect, transaction: FavoriteItemsTransaction, - screenId: Int + screenId: Int, ) { if (widgetRect.type == 'x') { fillWithWidgets(widgetRect, transaction, screenId) @@ -105,7 +105,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { fun buildFromBoard( board: CellLayoutBoard, transaction: FavoriteItemsTransaction, - screenId: Int + screenId: Int, ): FavoriteItemsTransaction { board.widgets.forEach { addCorrespondingWidgetRect(it, transaction, screenId) } board.icons.forEach { transaction.addItem { createIconInCell(it, screenId) } } @@ -130,7 +130,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { WidgetUtils.createWidgetInfo( TestViewHelpers.findWidgetProvider(false), ApplicationProvider.getApplicationContext(), - true + true, ) .apply { cellX = widgetRect.cellX @@ -154,7 +154,7 @@ class TestWorkspaceBuilder(private val mContext: Context) { minSpanY = 1 setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null) for (i in 0 until folderPoint.numberIconsInside) { - add(getDefaultWorkspaceItem(paramScreenId), false) + add(getDefaultWorkspaceItem(paramScreenId)) } } diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt index bcf5f0d817..e8259956fb 100644 --- a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt @@ -298,12 +298,13 @@ class FolderTest { val dragObject = DragObject(context) dragObject.dragInfo = Mockito.mock(ItemInfo::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) dragObject.dragSource = folder folder.onDragStart(dragObject, DragOptions()) verify(folder.mContent, times(1)).removeItem(folder.currentDragView) - verify(folder.mInfo, times(1)).remove(dragObject.dragInfo, true) + verify(folder, times(1)).removeFolderContent(true, dragObject.dragInfo) assertTrue(folder.itemsInvalidated) assertTrue(folder.isDragInProgress) assertFalse(folder.itemAddedBackToSelfViaIcon) @@ -827,19 +828,19 @@ class FolderTest { @Test fun `onRemove should call removeItem with the correct views`() { + val folderInfo = + workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) + val items = folderInfo.getContents().toTypedArray() + folder.mInfo = folderInfo + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) - val items = - arrayListOf<ItemInfo>( - Mockito.mock(ItemInfo::class.java), - Mockito.mock(ItemInfo::class.java), - ) val view1 = Mockito.mock(View::class.java) val view2 = Mockito.mock(View::class.java) doReturn(view1).whenever(folder).getViewForInfo(items[0]) doReturn(view2).whenever(folder).getViewForInfo(items[1]) doReturn(2).whenever(folder).itemCount - folder.onRemove(items) + folder.removeFolderContent(false, *items) verify(folder.mContent, times(1)).removeItem(view1) verify(folder.mContent, times(1)).removeItem(view2) @@ -847,20 +848,20 @@ class FolderTest { @Test fun `onRemove should set mRearrangeOnClose to true and not call rearrangeChildren if animating`() { + val folderInfo = + workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) + val items = folderInfo.getContents().toTypedArray() + folder.mInfo = folderInfo + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) folder.state = STATE_ANIMATING - val items = - arrayListOf<ItemInfo>( - Mockito.mock(ItemInfo::class.java), - Mockito.mock(ItemInfo::class.java), - ) val view1 = Mockito.mock(View::class.java) val view2 = Mockito.mock(View::class.java) doReturn(view1).whenever(folder).getViewForInfo(items[0]) doReturn(view2).whenever(folder).getViewForInfo(items[1]) doReturn(2).whenever(folder).itemCount - folder.onRemove(items) + folder.removeFolderContent(true, *items) assertTrue(folder.rearrangeOnClose) verify(folder, times(0)).rearrangeChildren() @@ -868,21 +869,21 @@ class FolderTest { @Test fun `onRemove should set not change mRearrangeOnClose and not call rearrangeChildren if not animating`() { + val folderInfo = + workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) + val items = folderInfo.getContents().toTypedArray() + folder.mInfo = folderInfo + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) folder.state = STATE_CLOSED folder.rearrangeOnClose = false - val items = - arrayListOf<ItemInfo>( - Mockito.mock(ItemInfo::class.java), - Mockito.mock(ItemInfo::class.java), - ) val view1 = Mockito.mock(View::class.java) val view2 = Mockito.mock(View::class.java) doReturn(view1).whenever(folder).getViewForInfo(items[0]) doReturn(view2).whenever(folder).getViewForInfo(items[1]) doReturn(2).whenever(folder).itemCount - folder.onRemove(items) + folder.removeFolderContent(false, *items) assertFalse(folder.rearrangeOnClose) verify(folder, times(1)).rearrangeChildren() @@ -890,12 +891,12 @@ class FolderTest { @Test fun `onRemove should call close if mIsOpen is true and item count is less than or equal to one`() { + val folderInfo = + workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) + val items = folderInfo.getContents().toTypedArray() + folder.mInfo = folderInfo + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) - val items = - arrayListOf<ItemInfo>( - Mockito.mock(ItemInfo::class.java), - Mockito.mock(ItemInfo::class.java), - ) val view1 = Mockito.mock(View::class.java) val view2 = Mockito.mock(View::class.java) doReturn(view1).whenever(folder).getViewForInfo(items[0]) @@ -904,19 +905,19 @@ class FolderTest { folder.setIsOpen(true) doNothing().`when`(folder).close(true) - folder.onRemove(items) + folder.removeFolderContent(false, *items) verify(folder, times(1)).close(true) } @Test fun `onRemove should call replaceFolderWithFinalItem if mIsOpen is false and item count is less than or equal to one`() { + val folderInfo = + workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) + val items = folderInfo.getContents().toTypedArray() + folder.mInfo = folderInfo + folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) folder.mContent = Mockito.mock(FolderPagedView::class.java) - val items = - arrayListOf<ItemInfo>( - Mockito.mock(ItemInfo::class.java), - Mockito.mock(ItemInfo::class.java), - ) val view1 = Mockito.mock(View::class.java) val view2 = Mockito.mock(View::class.java) doReturn(view1).whenever(folder).getViewForInfo(items[0]) @@ -924,7 +925,7 @@ class FolderTest { doReturn(1).whenever(folder).itemCount folder.setIsOpen(false) - folder.onRemove(items) + folder.removeFolderContent(false, *items) verify(folder, times(1)).replaceFolderWithFinalItem() } diff --git a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt index 08b8f81c11..25f4cf15dc 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt @@ -33,7 +33,6 @@ import org.mockito.Mockito.times import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock -import org.mockito.kotlin.same import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoMoreInteractions import org.mockito.kotlin.whenever @@ -142,10 +141,9 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() { /** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */ private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) { val spaceStack = newItemSpaces.toMutableList() - whenever( - mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any(), any(), any()) - ) - .then { spaceStack.removeFirst().toIntArray() } + whenever(mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any())).then { + spaceStack.removeFirst().toIntArray() + } } /** @@ -155,8 +153,6 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() { private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) { verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall)) .findSpaceForItem( - eq(mAppState), - same(mModelHelper.bgDataModel), eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())), eq(IntArray()), eq(1), diff --git a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt index 09752b860e..89e676f52f 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt @@ -11,6 +11,7 @@ import com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE import com.android.launcher3.LauncherSettings.Favorites.addTableToDb import com.android.launcher3.pm.UserCache import com.android.launcher3.provider.LauncherDbUtils +import com.android.launcher3.util.ModelTestExtensions import java.util.function.ToLongFunction import org.junit.After import org.junit.Assert.assertEquals @@ -33,7 +34,7 @@ class DatabaseHelperTest { @Before fun setUp() { - db = FactitiousDbController(context, INSERTION_SQL).inMemoryDb + db = ModelTestExtensions.createInMemoryDb(INSERTION_SQL) } @After diff --git a/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt b/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt deleted file mode 100644 index 711e1d2d65..0000000000 --- a/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.android.launcher3.model - -import android.content.Context -import android.database.Cursor -import android.database.sqlite.SQLiteDatabase -import androidx.test.platform.app.InstrumentationRegistry -import java.io.BufferedReader -import java.io.InputStreamReader - -private val All_COLUMNS = - arrayOf( - "_id", - "title", - "intent", - "container", - "screen", - "cellX", - "cellY", - "spanX", - "spanY", - "itemType", - "appWidgetId", - "icon", - "appWidgetProvider", - "modified", - "restored", - "profileId", - "rank", - "options", - "appWidgetSource" - ) - -class FactitiousDbController(context: Context, insertFile: String) : ModelDbController(context) { - - val inMemoryDb: SQLiteDatabase by lazy { - SQLiteDatabase.createInMemory(SQLiteDatabase.OpenParams.Builder().build()).also { db -> - BufferedReader( - InputStreamReader( - InstrumentationRegistry.getInstrumentation().context.assets.open(insertFile) - ) - ) - .lines() - .forEach { sqlStatement -> db.execSQL(sqlStatement) } - } - } - - override fun query( - table: String, - projection: Array<out String>?, - selection: String?, - selectionArgs: Array<out String>?, - sortOrder: String? - ): Cursor { - return inMemoryDb.query(table, All_COLUMNS, selection, selectionArgs, null, null, sortOrder) - } - - override fun loadDefaultFavoritesIfNecessary() { - // No-Op - } -} diff --git a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java index ad408185b2..b848d27cd9 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -55,7 +55,6 @@ import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.database.MatrixCursor; import android.graphics.Bitmap; @@ -76,6 +75,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.Executors; import com.android.launcher3.util.LauncherModelHelper; +import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext; import com.android.launcher3.util.PackageManagerHelper; import org.junit.After; @@ -96,11 +96,10 @@ public class LoaderCursorTest { private LauncherModelHelper mModelHelper; private LauncherAppState mApp; - private PackageManagerHelper mPmHelper; private MatrixCursor mCursor; private InvariantDeviceProfile mIDP; - private Context mContext; + private SandboxModelContext mContext; private LoaderCursor mLoaderCursor; @@ -116,7 +115,6 @@ public class LoaderCursorTest { mContext = mModelHelper.sandboxContext; mIDP = InvariantDeviceProfile.INSTANCE.get(mContext); mApp = LauncherAppState.getInstance(mContext); - mPmHelper = PackageManagerHelper.INSTANCE.get(mContext); mCursor = new MatrixCursor(new String[] { ICON, TITLE, _ID, CONTAINER, ITEM_TYPE, @@ -126,7 +124,8 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, mPmHelper, null); + mLoaderCursor = mContext.getAppComponent().getLoaderCursorFactory() + .createLoaderCursor(mCursor, ums, null); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt index eec6eeddd0..5fd93d13ce 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt @@ -27,8 +27,9 @@ import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.launcher3.AppFilter import com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE -import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings +import com.android.launcher3.dagger.LauncherAppComponent +import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.icons.IconCache import com.android.launcher3.model.PackageUpdatedTask.OP_ADD import com.android.launcher3.model.PackageUpdatedTask.OP_REMOVE @@ -39,17 +40,20 @@ import com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE import com.android.launcher3.model.PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE import com.android.launcher3.model.data.AppInfo import com.android.launcher3.model.data.WorkspaceItemInfo +import com.android.launcher3.util.AllModulesForTest import com.android.launcher3.util.Executors import com.android.launcher3.util.LauncherModelHelper -import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext import com.android.launcher3.util.TestUtil import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.verify @@ -61,10 +65,8 @@ class PackageUpdatedTaskTest { @get:Rule val setFlagsRule = SetFlagsRule() private val mUser = myUserHandle() - private val mDataModel: BgDataModel = BgDataModel() private val mLauncherModelHelper = LauncherModelHelper() - private val mContext: SandboxModelContext = spy(mLauncherModelHelper.sandboxContext) - private val mAppState: LauncherAppState = spy(LauncherAppState.getInstance(mContext)) + private val mContext = mLauncherModelHelper.sandboxContext private val expectedPackage = "Test.Package" private val expectedComponent = ComponentName(expectedPackage, "TestClass") @@ -72,22 +74,33 @@ class PackageUpdatedTaskTest { private val expectedWorkspaceItem = spy(WorkspaceItemInfo()) private val mockIconCache: IconCache = mock() - private val mockTaskController: ModelTaskController = mock<ModelTaskController>() private val mockAppFilter: AppFilter = mock<AppFilter>() + private lateinit var mAllAppsList: AllAppsList + private val mockApplicationInfo: ApplicationInfo = mock<ApplicationInfo>() private val mockActivityInfo: ActivityInfo = mock<ActivityInfo>() - private lateinit var mAllAppsList: AllAppsList + private lateinit var mDataModel: BgDataModel + private lateinit var mockTaskController: ModelTaskController @Before fun setup() { mAllAppsList = spy(AllAppsList(mockIconCache, mockAppFilter)) - mLauncherModelHelper.sandboxContext.spyService(LauncherApps::class.java).apply { + mContext.initDaggerComponent( + DaggerPackageUpdatedTaskTest_TestComponent.builder() + .bindAllAppsList(mAllAppsList) + .bindAppFilter(mockAppFilter) + .bindIconCache(mockIconCache) + ) + + mContext.spyService(LauncherApps::class.java).apply { whenever(getActivityList(expectedPackage, mUser)) .thenReturn(listOf(expectedActivityInfo)) } - whenever(mAppState.iconCache).thenReturn(mockIconCache) - whenever(mockTaskController.app).thenReturn(mAppState) + + mockTaskController = spy((mContext.appComponent as TestComponent).getTaskController()) + mDataModel = (mContext.appComponent as TestComponent).getDataModel() + whenever(mockAppFilter.shouldShowApp(expectedComponent)).thenReturn(true) mockApplicationInfo.apply { uid = 1 @@ -122,7 +135,6 @@ class PackageUpdatedTaskTest { TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser) verify(mAllAppsList).addPackage(mContext, expectedPackage, mUser) @@ -141,7 +153,6 @@ class PackageUpdatedTaskTest { TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser) verify(mAllAppsList).updatePackage(mContext, expectedPackage, mUser) @@ -159,7 +170,6 @@ class PackageUpdatedTaskTest { TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mockIconCache).removeIconsForPkg(expectedPackage, mUser) verify(mAllAppsList).removePackage(expectedPackage, mUser) @@ -176,7 +186,6 @@ class PackageUpdatedTaskTest { TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mAllAppsList).removePackage(expectedPackage, mUser) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem)) @@ -190,10 +199,11 @@ class PackageUpdatedTaskTest { // When mDataModel.addItem(mContext, expectedWorkspaceItem, true) mAllAppsList.add(AppInfo(mContext, expectedActivityInfo, mUser), expectedActivityInfo) + mAllAppsList.getAndResetChangeFlag() + doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded() TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mAllAppsList).updateDisabledFlags(any(), any()) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem)) @@ -206,10 +216,11 @@ class PackageUpdatedTaskTest { val taskUnderTest = PackageUpdatedTask(OP_UNSUSPEND, mUser, expectedPackage) // When mDataModel.addItem(mContext, expectedWorkspaceItem, true) + mAllAppsList.getAndResetChangeFlag() + doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded() TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mAllAppsList).updateDisabledFlags(any(), any()) verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList()) @@ -226,10 +237,29 @@ class PackageUpdatedTaskTest { TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList) } - mLauncherModelHelper.loadModelSync() // Then verify(mAllAppsList).updateDisabledFlags(any(), any()) verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList()) assertThat(mAllAppsList.data).isEmpty() } + + @LauncherAppSingleton + @Component(modules = [AllModulesForTest::class]) + interface TestComponent : LauncherAppComponent { + + fun getDataModel(): BgDataModel + + fun getTaskController(): ModelTaskController + + @Component.Builder + interface Builder : LauncherAppComponent.Builder { + @BindsInstance fun bindAppFilter(appFilter: AppFilter): Builder + + @BindsInstance fun bindIconCache(iconCache: IconCache): Builder + + @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder + + override fun build(): TestComponent + } + } } diff --git a/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt index c6863f40f1..0ab736b26c 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/ShortcutsChangedTaskTest.kt @@ -30,7 +30,6 @@ import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.Flags -import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT import com.android.launcher3.icons.BitmapInfo import com.android.launcher3.icons.CacheableShortcutInfo @@ -73,7 +72,6 @@ class ShortcutsChangedTaskTest { private val user: UserHandle = myUserHandle() private val mockTaskController: ModelTaskController = mock() private val mockAllApps: AllAppsList = mock() - private val mockAppState: LauncherAppState = mock() private val mockIconCache: IconCache = mock() private val expectedWai = @@ -93,9 +91,8 @@ class ShortcutsChangedTaskTest { modelHelper.loadModelSync() context = modelHelper.sandboxContext launcherApps = context.spyService(LauncherApps::class.java) - whenever(mockTaskController.app).thenReturn(mockAppState) - whenever(mockAppState.context).thenReturn(context) - whenever(mockAppState.iconCache).thenReturn(mockIconCache) + whenever(mockTaskController.context).thenReturn(context) + whenever(mockTaskController.iconCache).thenReturn(mockIconCache) whenever(mockIconCache.getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>())) .then { _ -> { expectedWai.bitmap = BitmapInfo.LOW_RES_INFO } } shortcuts = emptyList() @@ -132,8 +129,7 @@ class ShortcutsChangedTaskTest { // When shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps) // Then - verify(mockAppState.iconCache) - .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) + verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai)) } @@ -196,8 +192,7 @@ class ShortcutsChangedTaskTest { // When shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps) // Then - verify(mockAppState.iconCache) - .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) + verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai)) } @@ -256,8 +251,7 @@ class ShortcutsChangedTaskTest { // When shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps) // Then - verify(mockAppState.iconCache) - .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) + verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai)) } @@ -287,8 +281,7 @@ class ShortcutsChangedTaskTest { // When shortcutsChangedTask.execute(mockTaskController, modelHelper.bgDataModel, mockAllApps) // Then - verify(mockAppState.iconCache) - .getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) + verify(mockIconCache).getShortcutIcon(eq(expectedWai), any<CacheableShortcutInfo>()) verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWai)) } diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt index 777d81babe..2e6ecc5d94 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt @@ -25,9 +25,9 @@ import android.platform.test.rule.DeviceProduct import android.platform.test.rule.LimitDevicesRule import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.launcher3.AppFilter import com.android.launcher3.DeviceProfile import com.android.launcher3.InvariantDeviceProfile -import com.android.launcher3.LauncherAppState import com.android.launcher3.icons.IconCache import com.android.launcher3.model.data.PackageItemInfo import com.android.launcher3.pm.UserCache @@ -62,7 +62,6 @@ class WidgetsModelTest { @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var appWidgetManager: AppWidgetManager - @Mock private lateinit var app: LauncherAppState @Mock private lateinit var iconCacheMock: IconCache private lateinit var context: Context @@ -93,9 +92,6 @@ class WidgetsModelTest { whenever(iconCacheMock.getTitleNoCache(any<LauncherAppWidgetProviderInfo>())) .thenReturn("title") - whenever(app.iconCache).thenReturn(iconCacheMock) - whenever(app.context).thenReturn(context) - whenever(app.invariantDeviceProfile).thenReturn(idp) val widgetToCategoryEntry: Map.Entry<ComponentName, IntSet> = WidgetSections.getWidgetsToCategory(context).entries.first() @@ -128,7 +124,7 @@ class WidgetsModelTest { val userCache = spy(UserCache.INSTANCE.get(context)) whenever(userCache.userProfiles).thenReturn(listOf(UserHandle.CURRENT)) - underTest = WidgetsModel() + underTest = WidgetsModel(context, idp, iconCacheMock, AppFilter(context)) } @Test @@ -237,7 +233,7 @@ class WidgetsModelTest { update = false // Similarly, model could update its code independently while a client is // iterating on the list. - underTest.update(app, /* packageUser= */ null) + underTest.update(/* packageUser= */ null) } } @@ -253,7 +249,7 @@ class WidgetsModelTest { private fun loadWidgets() { val latch = CountDownLatch(1) Executors.MODEL_EXECUTOR.execute { - underTest.update(app, /* packageUser= */ null) + underTest.update(/* packageUser= */ null) latch.countDown() } if (!latch.await(LOAD_WIDGETS_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt index a55d64ba4f..cba7b88890 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt @@ -31,7 +31,7 @@ import android.platform.test.flag.junit.SetFlagsRule import android.util.LongSparseArray import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.launcher3.Flags -import com.android.launcher3.LauncherAppState +import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION @@ -41,6 +41,7 @@ import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError import com.android.launcher3.icons.CacheableShortcutInfo +import com.android.launcher3.icons.IconCache import com.android.launcher3.model.data.FolderInfo import com.android.launcher3.model.data.IconRequestInfo import com.android.launcher3.model.data.ItemInfo @@ -66,12 +67,14 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.mock import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.doAnswer @@ -88,12 +91,12 @@ class WorkspaceItemProcessorTest { @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo> @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo @Mock private lateinit var mockBgDataModel: BgDataModel - @Mock private lateinit var mockAppState: LauncherAppState @Mock private lateinit var mockPmHelper: PackageManagerHelper - @Mock private lateinit var mockCursor: LoaderCursor + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var mockCursor: LoaderCursor @Mock private lateinit var mockUserCache: UserCache @Mock private lateinit var mockUserManagerState: UserManagerState @Mock private lateinit var mockWidgetInflater: WidgetInflater + @Mock private lateinit var mockIconCache: IconCache lateinit var mModelHelper: LauncherModelHelper lateinit var mContext: SandboxModelContext @@ -114,6 +117,7 @@ class WorkspaceItemProcessorTest { @Before fun setup() { + MockitoAnnotations.initMocks(this) mModelHelper = LauncherModelHelper() mContext = mModelHelper.sandboxContext mLauncherApps = @@ -122,9 +126,6 @@ class WorkspaceItemProcessorTest { doReturn(true).whenever(this).isActivityEnabled(mComponentName, mUserHandle) } mUserHandle = Process.myUserHandle() - mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>() - mockWorkspaceInfo = mock<WorkspaceItemInfo>() - mockBgDataModel = mock<BgDataModel>() mComponentName = ComponentName("package", "class") mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) } mIntent = @@ -133,40 +134,26 @@ class WorkspaceItemProcessorTest { `package` = "pkg" putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "") } - mockAppState = - mock<LauncherAppState>().apply { - whenever(context).thenReturn(mContext) - whenever(iconCache).thenReturn(mock()) - whenever(iconCache.getShortcutIcon(any(), any(), any())).then {} - } - mockPmHelper = - mock<PackageManagerHelper>().apply { - whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle)) - .thenReturn(mIntent) - } - mockCursor = - mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply { - user = mUserHandle - itemType = ITEM_TYPE_APPLICATION - id = 1 - restoreFlag = 1 - serialNumber = 101 - whenever(parseIntent()).thenReturn(mIntent) - whenever(markRestored()).doAnswer { restoreFlag = 0 } - whenever(updater().put(Favorites.INTENT, mIntent.toUri(0)).commit()).thenReturn(1) - whenever(getAppShortcutInfo(any(), any(), any(), any())) - .thenReturn(mockWorkspaceInfo) - whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo) - } - mockUserCache = - mock<UserCache>().apply { - val userIconInfo = - mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) } - whenever(getUserInfo(any())).thenReturn(userIconInfo) - } + whenever(mockIconCache.getShortcutIcon(any(), any(), any())).then {} + whenever(mockPmHelper.getAppLaunchIntent(mComponentName.packageName, mUserHandle)) + .thenReturn(mIntent) + mockCursor.apply { + user = mUserHandle + itemType = ITEM_TYPE_APPLICATION + id = 1 + restoreFlag = 1 + serialNumber = 101 + whenever(parseIntent()).thenReturn(mIntent) + whenever(markRestored()).doAnswer { restoreFlag = 0 } + whenever(updater().put(Favorites.INTENT, mIntent.toUri(0)).commit()).thenReturn(1) + whenever(getAppShortcutInfo(any(), any(), any(), any())).thenReturn(mockWorkspaceInfo) + whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo) + } + mockUserCache.apply { + val userIconInfo = mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) } + whenever(getUserInfo(any())).thenReturn(userIconInfo) + } - mockUserManagerState = mock<UserManagerState>() - mockWidgetInflater = mock<WidgetInflater>() mKeyToPinnedShortcutsMap = mutableMapOf() mInstallingPkgs = hashMapOf() mAllDeepShortcuts = mutableListOf() @@ -187,7 +174,6 @@ class WorkspaceItemProcessorTest { userManagerState: UserManagerState = mockUserManagerState, launcherApps: LauncherApps = mLauncherApps, shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap, - app: LauncherAppState = mockAppState, bgDataModel: BgDataModel = mockBgDataModel, widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap, widgetInflater: WidgetInflater = mockWidgetInflater, @@ -205,7 +191,7 @@ class WorkspaceItemProcessorTest { userCache = userCache, userManagerState = userManagerState, launcherApps = launcherApps, - app = app, + context = mContext, bgDataModel = bgDataModel, widgetProvidersMap = widgetProvidersMap, widgetInflater = widgetInflater, @@ -217,6 +203,9 @@ class WorkspaceItemProcessorTest { shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts, installingPkgs = installingPkgs, allDeepShortcuts = allDeepShortcuts, + iconCache = mockIconCache, + idp = InvariantDeviceProfile.INSTANCE.get(mContext), + isSafeMode = false, ) @Test diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt index dd03eee12c..a18f93b9dc 100644 --- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt @@ -29,8 +29,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() { - private val mItemSpaceFinder = WorkspaceItemSpaceFinder() - @Before override fun setup() { super.setup() @@ -42,15 +40,12 @@ class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() { } private fun findSpace(spanX: Int, spanY: Int): NewItemSpace = - mItemSpaceFinder - .findSpaceForItem( - mAppState, + WorkspaceItemSpaceFinder( mModelHelper.bgDataModel, - mExistingScreens, - mNewScreens, - spanX, - spanY, + mAppState.invariantDeviceProfile, + mModelHelper.model, ) + .findSpaceForItem(mExistingScreens, mNewScreens, spanX, spanY) .let { NewItemSpace.fromIntArray(it) } private fun assertRegionVacant(newItemSpace: NewItemSpace, spanX: Int, spanY: Int) { diff --git a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index c30b730807..0f4940e7ed 100644 --- a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -24,8 +24,6 @@ import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; -import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID; import static com.google.common.truth.Truth.assertThat; @@ -50,7 +48,6 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.UserHandle; import android.os.UserManager; -import android.util.LongSparseArray; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -60,9 +57,17 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; +import com.android.launcher3.dagger.LauncherAppComponent; +import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.pm.UserCache; +import com.android.launcher3.util.AllModulesForTest; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.LauncherModelHelper; +import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext; + +import dagger.BindsInstance; +import dagger.Component; import org.junit.After; import org.junit.Before; @@ -85,7 +90,9 @@ public class RestoreDbTaskTest { private final UserHandle mWorkUser = UserHandle.getUserHandleForUid(PER_USER_RANGE); private LauncherModelHelper mModelHelper; - private Context mContext; + private SandboxModelContext mContext; + private UserCache mUserCacheSpy; + private RestoreDbTask mTask; private ModelDbController mMockController; private SQLiteDatabase mMockDb; @@ -94,10 +101,17 @@ public class RestoreDbTaskTest { private LauncherRestoreEventLogger mMockRestoreEventLogger; private SQLiteDatabase mDb; + private AppWidgetHost mWidgetHost; + @Before public void setup() { mModelHelper = new LauncherModelHelper(); mContext = mModelHelper.sandboxContext; + mUserCacheSpy = spy(UserCache.getInstance(getInstrumentation().getTargetContext())); + + mContext.initDaggerComponent( + DaggerRestoreDbTaskTest_TestComponent.builder().bindUserCache(mUserCacheSpy)); + mTask = new RestoreDbTask(); mMockController = Mockito.mock(ModelDbController.class); mMockDb = mock(SQLiteDatabase.class); @@ -106,24 +120,34 @@ public class RestoreDbTaskTest { mMockRestoreEventLogger = mock(LauncherRestoreEventLogger.class); } + private synchronized AppWidgetHost getWidgetHostLazy() { + if (mWidgetHost == null) { + mWidgetHost = new AppWidgetHost(mContext, 1012); + } + return mWidgetHost; + } + @After public void teardown() { if (mDb != null) { mDb.close(); } + if (mWidgetHost != null) { + mWidgetHost.deleteHost(); + } mModelHelper.destroy(); LauncherPrefs.get(mContext).removeSync(RESTORE_DEVICE); } @Test public void testGetProfileId() throws Exception { - mDb = new MyModelDbController(23).getDb(); + mDb = getModelDbController(23).getDb(); assertEquals(23, new RestoreDbTask().getDefaultProfileId(mDb)); } @Test public void testMigrateProfileId() throws Exception { - mDb = new MyModelDbController(42).getDb(); + mDb = getModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -143,7 +167,7 @@ public class RestoreDbTaskTest { @Test public void testChangeDefaultColumn() throws Exception { - mDb = new MyModelDbController(42).getDb(); + mDb = getModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -173,12 +197,12 @@ public class RestoreDbTaskTest { long workProfileId = myProfileId + 2; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); + ModelDbController controller = getModelDbController(myProfileId); mDb = controller.getDb(); BackupManager bm = spy(new BackupManager(mContext)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - controller.users.put(workProfileId, mWorkUser); + doReturn(workProfileId).when(mUserCacheSpy).getSerialNumberForUser(mWorkUser); addIconsBulk(controller, 10, 1, myProfileId_old); addIconsBulk(controller, 6, 2, workProfileId_old); @@ -202,7 +226,7 @@ public class RestoreDbTaskTest { long myProfileId_old = myProfileId + 1; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); + ModelDbController controller = getModelDbController(myProfileId); mDb = controller.getDb(); BackupManager bm = spy(new BackupManager(mContext)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); @@ -226,7 +250,8 @@ public class RestoreDbTaskTest { @Test public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() { // When - mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger); + mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger, + this::getWidgetHostLazy); // Then assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse(); } @@ -234,7 +259,7 @@ public class RestoreDbTaskTest { @Test public void givenNoPendingRestore_WhenRestoreAppWidgetIds_ThenRemoveNewWidgetIds() { // Given - AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID); + AppWidgetHost expectedHost = getWidgetHostLazy(); int[] expectedOldIds = generateOldWidgetIds(expectedHost); int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds); when(mMockController.getDb()).thenReturn(mMockDb); @@ -242,7 +267,8 @@ public class RestoreDbTaskTest { // When setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds); - mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger); + mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger, + this::getWidgetHostLazy); // Then assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds); @@ -254,7 +280,7 @@ public class RestoreDbTaskTest { @Test public void givenRestoreWithNonExistingWidgets_WhenRestoreAppWidgetIds_ThenRemoveNewIds() { // Given - AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID); + AppWidgetHost expectedHost = getWidgetHostLazy(); int[] expectedOldIds = generateOldWidgetIds(expectedHost); int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds); when(mMockController.getDb()).thenReturn(mMockDb); @@ -265,18 +291,19 @@ public class RestoreDbTaskTest { // When setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds); - mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger); + mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger, + this::getWidgetHostLazy); // Then assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds); assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse(); - verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any()); + verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any()); } @Test public void givenRestore_WhenRestoreAppWidgetIds_ThenAddNewIds() { // Given - AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID); + AppWidgetHost expectedHost = getWidgetHostLazy(); int[] expectedOldIds = generateOldWidgetIds(expectedHost); int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds); int[] allExpectedIds = IntStream.concat( @@ -294,15 +321,16 @@ public class RestoreDbTaskTest { // When setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds); - mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger); + mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger, + this::getWidgetHostLazy); // Then assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds); assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse(); - verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any()); + verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any()); } - private void addIconsBulk(MyModelDbController controller, + private void addIconsBulk(ModelDbController controller, int count, int screen, long profileId) { int columns = LauncherAppState.getIDP(mContext).numColumns; String packageName = getInstrumentation().getContext().getPackageName(); @@ -320,7 +348,7 @@ public class RestoreDbTaskTest { values.put(LauncherSettings.Favorites.INTENT, new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); - controller.insert(TABLE_NAME, values); + controller.insert(values); } } @@ -346,7 +374,7 @@ public class RestoreDbTaskTest { } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { - mDb = new MyModelDbController(42).getDb(); + mDb = getModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); @@ -397,25 +425,29 @@ public class RestoreDbTaskTest { .map(id -> host.allocateAppWidgetId()).toArray(); } - private class MyModelDbController extends ModelDbController { - - public final LongSparseArray<UserHandle> users = new LongSparseArray<>(); - - MyModelDbController(long profileId) { - super(mContext); - users.put(profileId, myUserHandle()); - } - - @Override - public long getSerialNumberForUser(UserHandle user) { - int index = users.indexOfValue(user); - return index >= 0 ? users.keyAt(index) : -1; - } - } - private void setRestoredAppWidgetIds(Context context, int[] oldIds, int[] newIds) { LauncherPrefs.get(context).putSync( OLD_APP_WIDGET_IDS.to(IntArray.wrap(oldIds).toConcatString()), APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } + + private ModelDbController getModelDbController(long profileId) { + doReturn(profileId).when(mUserCacheSpy).getSerialNumberForUser(myUserHandle()); + return ((TestComponent) mContext.getAppComponent()).getDbController(); + } + + @LauncherAppSingleton + @Component(modules = AllModulesForTest.class) + public interface TestComponent extends LauncherAppComponent { + + ModelDbController getDbController(); + + @Component.Builder + interface Builder extends LauncherAppComponent.Builder { + + @BindsInstance Builder bindUserCache(UserCache userCache); + + TestComponent build(); + } + } } diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt index ceefb0dced..524acff61d 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt @@ -1,10 +1,11 @@ package com.android.launcher3.util import android.content.ContentValues +import android.database.sqlite.SQLiteDatabase import android.os.Process +import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.Flags import com.android.launcher3.LauncherModel -import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE @@ -24,6 +25,8 @@ import com.android.launcher3.LauncherSettings.Favorites.TITLE import com.android.launcher3.LauncherSettings.Favorites._ID import com.android.launcher3.model.BgDataModel import com.android.launcher3.model.ModelDbController +import java.io.BufferedReader +import java.io.InputStreamReader object ModelTestExtensions { /** Clears and reloads Launcher db to cleanup the workspace */ @@ -68,7 +71,6 @@ object ModelTestExtensions { spanY: Int = 1, id: Int = 0, profileId: Int = Process.myUserHandle().identifier, - tableName: String = Favorites.TABLE_NAME, appWidgetId: Int = -1, appWidgetSource: Int = -1, appWidgetProvider: String? = null, @@ -97,9 +99,21 @@ object ModelTestExtensions { values[APPWIDGET_PROVIDER] = appWidgetProvider } // Migrate any previous data so that the DB state is correct - controller.insert(tableName, values) + controller.insert(values) transaction.commit() } } } + + /** Creates an in-memory sqlite DB and initializes with the data in [insertFile] */ + fun createInMemoryDb(insertFile: String): SQLiteDatabase = + SQLiteDatabase.createInMemory(SQLiteDatabase.OpenParams.Builder().build()).also { db -> + BufferedReader( + InputStreamReader( + InstrumentationRegistry.getInstrumentation().context.assets.open(insertFile) + ) + ) + .lines() + .forEach { sqlStatement -> db.execSQL(sqlStatement) } + } } diff --git a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt index 17933f202b..97651d3dab 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt @@ -127,6 +127,29 @@ class SimpleBroadcastReceiverTest { } @Test + fun sync_register_withCompletionRunnable_and_permission_and_flag() { + underTest = + SimpleBroadcastReceiver(context, Handler(Looper.getMainLooper()), intentConsumer) + + underTest.register(completionRunnable, "permission", 1, "test_action_1", "test_action_2") + getInstrumentation().waitForIdleSync() + + verify(context) + .registerReceiver( + same(underTest), + intentFilterCaptor.capture(), + eq("permission"), + eq(null), + eq(1), + ) + verify(completionRunnable).run() + val intentFilter = intentFilterCaptor.value + assertThat(intentFilter.countActions()).isEqualTo(2) + assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1") + assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2") + } + + @Test fun async_unregister() { underTest.unregisterReceiverSafely() diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt index 38fad6bc6c..34d9d40d67 100644 --- a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt +++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt @@ -23,8 +23,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.android.launcher3.Flags +import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherPrefs -import com.android.launcher3.model.ModelDbController import com.android.launcher3.model.ModelDelegate import com.android.launcher3.provider.RestoreDbTask import com.android.launcher3.util.Executors.MODEL_EXECUTOR @@ -45,11 +45,8 @@ import org.mockito.kotlin.mock @MediumTest class BackupAndRestoreDBSelectionTest { - @JvmField @Rule var backAndRestoreRule = BackAndRestoreRule() - - @JvmField - @Rule - val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT) + @get:Rule var backAndRestoreRule = BackAndRestoreRule() + @get:Rule val setFlagsRule = SetFlagsRule() val modelDelegate = mock<ModelDelegate>() @@ -70,7 +67,8 @@ class BackupAndRestoreDBSelectionTest { @Test fun oldDatabasesNotPresentAfterRestore() { - val dbController = ModelDbController(getInstrumentation().targetContext) + val dbController = + LauncherAppState.getInstance(getInstrumentation().targetContext).model.modelDbController if (Flags.gridMigrationRefactor()) { dbController.attemptMigrateDb(null, modelDelegate) } else { diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt index 246219ffda..560d306244 100644 --- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt +++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt @@ -5,6 +5,7 @@ import android.content.ComponentName import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.LauncherActivityInfo +import android.database.sqlite.SQLiteDatabase import android.os.Process import android.os.UserHandle import android.platform.test.annotations.DisableFlags @@ -16,7 +17,6 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn import com.android.launcher3.Flags -import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherModel import com.android.launcher3.LauncherModel.LoaderTransaction import com.android.launcher3.LauncherPrefs @@ -26,11 +26,13 @@ import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER +import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME import com.android.launcher3.dagger.LauncherAppComponent import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.icons.IconCache import com.android.launcher3.icons.cache.CachingLogic import com.android.launcher3.icons.cache.IconCacheUpdateHandler +import com.android.launcher3.model.LoaderTask.LoaderTaskFactory import com.android.launcher3.model.data.AppInfo import com.android.launcher3.model.data.IconRequestInfo import com.android.launcher3.model.data.WorkspaceItemInfo @@ -41,9 +43,9 @@ import com.android.launcher3.util.AllModulesForTest import com.android.launcher3.util.Executors.MODEL_EXECUTOR import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext import com.android.launcher3.util.LooperIdleLock +import com.android.launcher3.util.ModelTestExtensions import com.android.launcher3.util.TestUtil import com.android.launcher3.util.UserIconInfo -import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat import dagger.BindsInstance import dagger.Component @@ -57,7 +59,6 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito -import org.mockito.Mockito.mock import org.mockito.Mockito.times import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @@ -65,6 +66,7 @@ import org.mockito.MockitoSession import org.mockito.Spy import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.verify @@ -93,26 +95,33 @@ class LoaderTaskTest { @Mock private lateinit var bgAllAppsList: AllAppsList @Mock private lateinit var modelDelegate: ModelDelegate + @Mock private lateinit var launcherModel: LauncherModel + @Mock private lateinit var iconCache: IconCache + @Mock private lateinit var userCache: UserCache + @Mock private lateinit var modelDbController: ModelDbController + @Mock private lateinit var launcherBinder: BaseLauncherBinder - private lateinit var launcherModel: LauncherModel @Mock private lateinit var transaction: LoaderTransaction - @Mock private lateinit var iconCache: IconCache @Mock private lateinit var idleLock: LooperIdleLock @Mock private lateinit var iconCacheUpdateHandler: IconCacheUpdateHandler - @Mock private lateinit var userCache: UserCache - @Spy private var userManagerState: UserManagerState? = UserManagerState() + @Spy private var userManagerState: UserManagerState = UserManagerState() @get:Rule val setFlagsRule = SetFlagsRule() - private val app: LauncherAppState - get() = context.appComponent.launcherAppState + private val testComponent: TestComponent + get() = context.appComponent as TestComponent + + private val bgDataModel: BgDataModel + get() = testComponent.getDataModel() + + private val inMemoryDb: SQLiteDatabase by lazy { + ModelTestExtensions.createInMemoryDb(INSERTION_STATEMENT_FILE) + } @Before fun setup() { MockitoAnnotations.initMocks(this) - setFlagsRule.enableFlags(Flags.FLAG_ENABLE_TIERED_WIDGETS_BY_DEFAULT_IN_PICKER) - launcherModel = mock(LauncherModel::class.java) mockitoSession = ExtendedMockito.mockitoSession() .strictness(Strictness.LENIENT) @@ -123,16 +132,34 @@ class LoaderTaskTest { .getAppWidgetInfo(any()) `when`(launcherModel.beginLoader(any())).thenReturn(transaction) - `when`(launcherModel.modelDbController) - .thenReturn(FactitiousDbController(context, INSERTION_STATEMENT_FILE)) + + `when`(launcherModel.modelDbController).thenReturn(modelDbController) + doAnswer {}.whenever(modelDbController).loadDefaultFavoritesIfNecessary() + doAnswer { i -> + inMemoryDb.query( + TABLE_NAME, + i.getArgument(0), + i.getArgument(1), + i.getArgument(2), + null, + null, + i.getArgument(3), + ) + } + .whenever(modelDbController) + .query(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) + + `when`(launcherModel.modelDelegate).thenReturn(modelDelegate) `when`(launcherBinder.newIdleLock(any())).thenReturn(idleLock) `when`(idleLock.awaitLocked(1000)).thenReturn(false) `when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler) + context.initDaggerComponent( DaggerLoaderTaskTest_TestComponent.builder() .bindUserCache(userCache) .bindIconCache(iconCache) .bindLauncherModel(launcherModel) + .bindAllAppsList(bgAllAppsList) ) context.appComponent.idp.apply { numRows = 5 @@ -146,20 +173,23 @@ class LoaderTaskTest { fun tearDown() { LauncherPrefs.get(context).removeSync(RESTORE_DEVICE) LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false)) + inMemoryDb.close() context.onDestroy() mockitoSession.finishMocking() } @Test fun loadsDataProperly() = - with(BgDataModel()) { + with(bgDataModel) { val MAIN_HANDLE = Process.myUserHandle() val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE) `when`(userCache.userProfiles).thenReturn(mockUserHandles) `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1)) - LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() - Truth.assertThat( + assertThat( itemsIdMap .filter { it.container == CONTAINER_DESKTOP || it.container == CONTAINER_HOTSEAT @@ -167,9 +197,8 @@ class LoaderTaskTest { .size ) .isAtLeast(32) - Truth.assertThat(itemsIdMap.filter { ModelUtils.WIDGET_FILTER.test(it) }.size) - .isAtLeast(7) - Truth.assertThat( + assertThat(itemsIdMap.filter { ModelUtils.WIDGET_FILTER.test(it) }.size).isAtLeast(7) + assertThat( itemsIdMap .filter { it.itemType == ITEM_TYPE_FOLDER || it.itemType == ITEM_TYPE_APP_PAIR @@ -177,12 +206,14 @@ class LoaderTaskTest { .size ) .isAtLeast(8) - Truth.assertThat(itemsIdMap.size()).isAtLeast(40) + assertThat(itemsIdMap.size()).isAtLeast(40) } @Test fun bindsLoadedDataCorrectly() { - LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() verify(launcherBinder).bindWorkspace(true, false) @@ -200,7 +231,7 @@ class LoaderTaskTest { @Test fun setsQuietModeFlagCorrectlyForWorkProfile() = - with(BgDataModel()) { + with(bgDataModel) { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE) val MAIN_HANDLE = Process.myUserHandle() val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE) @@ -208,7 +239,9 @@ class LoaderTaskTest { `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true) `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1)) - LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() verify(bgAllAppsList) @@ -221,7 +254,7 @@ class LoaderTaskTest { @Test fun setsQuietModeFlagCorrectlyForPrivateProfile() = - with(BgDataModel()) { + with(bgDataModel) { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE) val MAIN_HANDLE = Process.myUserHandle() val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE) @@ -229,7 +262,9 @@ class LoaderTaskTest { `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true) `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 3)) - LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() verify(bgAllAppsList) @@ -268,7 +303,9 @@ class LoaderTaskTest { RestoreDbTask.setPending(spyContext) // When - LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() // Then @@ -336,7 +373,9 @@ class LoaderTaskTest { Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0) // When - LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() // Then @@ -375,7 +414,9 @@ class LoaderTaskTest { RestoreDbTask.setPending(spyContext) // When - LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() // Then @@ -414,7 +455,9 @@ class LoaderTaskTest { RestoreDbTask.setPending(spyContext) // When - LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + testComponent + .getLoaderTaskFactory() + .newLoaderTask(launcherBinder, userManagerState) .runSyncOnBackgroundThread() // Then @@ -444,7 +487,8 @@ class LoaderTaskTest { ) val expectedAppInfo = AppInfo().apply { componentName = expectedComponent } // When - val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + val loader = + testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState) val actualIconRequest = loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests) // Then @@ -474,7 +518,8 @@ class LoaderTaskTest { ) val expectedAppInfo = AppInfo().apply { componentName = expectedComponent } // When - val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + val loader = + testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState) val actualIconRequest = loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests) // Then @@ -505,7 +550,8 @@ class LoaderTaskTest { val expectedAppInfo = AppInfo().apply { componentName = ComponentName("differentPkg", "differentClass") } // When - val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + val loader = + testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState) val actualIconRequest = loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests) // Then @@ -532,7 +578,8 @@ class LoaderTaskTest { ) val expectedAppInfo = AppInfo() // When - val loader = LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder) + val loader = + testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState) val actualIconRequest = loader.getAppInfoIconRequestInfo(expectedAppInfo, activityInfo, workspaceIconRequests) // Then @@ -543,6 +590,11 @@ class LoaderTaskTest { @LauncherAppSingleton @Component(modules = [AllModulesForTest::class]) interface TestComponent : LauncherAppComponent { + + fun getLoaderTaskFactory(): LoaderTaskFactory + + fun getDataModel(): BgDataModel + @Component.Builder interface Builder : LauncherAppComponent.Builder { @BindsInstance fun bindUserCache(userCache: UserCache): Builder @@ -551,6 +603,8 @@ class LoaderTaskTest { @BindsInstance fun bindIconCache(iconCache: IconCache): Builder + @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder + override fun build(): TestComponent } } diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt index 8db049c492..fd44023de4 100644 --- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt +++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt @@ -30,12 +30,13 @@ import android.util.LongSparseArray import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING -import com.android.launcher3.LauncherAppState +import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET import com.android.launcher3.icons.CacheableShortcutInfo +import com.android.launcher3.icons.IconCache import com.android.launcher3.model.data.IconRequestInfo import com.android.launcher3.model.data.LauncherAppWidgetInfo import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED @@ -52,11 +53,12 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.Mock -import org.mockito.Mockito import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.doAnswer @@ -71,10 +73,10 @@ class WorkspaceItemProcessorExtraTest { @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo @Mock private lateinit var mockBgDataModel: BgDataModel @Mock private lateinit var mockContext: Context - @Mock private lateinit var mockAppState: LauncherAppState + @Mock private lateinit var mockIconCache: IconCache @Mock private lateinit var mockPmHelper: PackageManagerHelper @Mock private lateinit var mockLauncherApps: LauncherApps - @Mock private lateinit var mockCursor: LoaderCursor + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var mockCursor: LoaderCursor @Mock private lateinit var mockUserCache: UserCache @Mock private lateinit var mockUserManagerState: UserManagerState @Mock private lateinit var mockWidgetInflater: WidgetInflater @@ -95,10 +97,9 @@ class WorkspaceItemProcessorExtraTest { @Before fun setup() { + MockitoAnnotations.initMocks(this) + mUserHandle = UserHandle(0) - mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>() - mockWorkspaceInfo = mock<WorkspaceItemInfo>() - mockBgDataModel = mock<BgDataModel>() mComponentName = ComponentName("package", "class") mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) } intent = @@ -107,52 +108,36 @@ class WorkspaceItemProcessorExtraTest { `package` = "pkg" putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "") } - mockLauncherApps = - mock<LauncherApps>().apply { - whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true) - whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true) - } - mockContext = - mock<Context>().apply { - whenever(packageManager).thenReturn(mock()) - whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("") - whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext()) - whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps) - } - mockAppState = - mock<LauncherAppState>().apply { - whenever(context).thenReturn(mockContext) - whenever(iconCache).thenReturn(mock()) - whenever(iconCache.getShortcutIcon(any(), any(), any())).then {} - } - mockPmHelper = - mock<PackageManagerHelper>().apply { - whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle)) - .thenReturn(intent) - } - mockCursor = - Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply { - user = mUserHandle - itemType = ITEM_TYPE_APPLICATION - id = 1 - restoreFlag = 1 - serialNumber = 101 - whenever(parseIntent()).thenReturn(intent) - whenever(markRestored()).doAnswer { restoreFlag = 0 } - whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1) - whenever(getAppShortcutInfo(any(), any(), any(), any())) - .thenReturn(mockWorkspaceInfo) - whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo) - } - mockUserCache = - mock<UserCache>().apply { - val userIconInfo = - mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) } - whenever(getUserInfo(any())).thenReturn(userIconInfo) - } + mockLauncherApps.apply { + whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true) + whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true) + } + mockContext.apply { + whenever(packageManager).thenReturn(mock()) + whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("") + whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext()) + whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps) + } + + whenever(mockIconCache.getShortcutIcon(any(), any(), any())).then {} + whenever(mockPmHelper.getAppLaunchIntent(mComponentName.packageName, mUserHandle)) + .thenReturn(intent) + mockCursor.apply { + user = mUserHandle + itemType = ITEM_TYPE_APPLICATION + id = 1 + restoreFlag = 1 + serialNumber = 101 + whenever(parseIntent()).thenReturn(intent) + whenever(markRestored()).doAnswer { restoreFlag = 0 } + whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1) + whenever(getAppShortcutInfo(any(), any(), any(), any())).thenReturn(mockWorkspaceInfo) + whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo) + } + + val mockUserInfo = mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) } + whenever(mockUserCache.getUserInfo(any())).thenReturn(mockUserInfo) - mockUserManagerState = mock<UserManagerState>() - mockWidgetInflater = mock<WidgetInflater>() mKeyToPinnedShortcutsMap = mutableMapOf() mInstallingPkgs = hashMapOf() mAllDeepShortcuts = mutableListOf() @@ -283,7 +268,7 @@ class WorkspaceItemProcessorExtraTest { userManagerState: UserManagerState = mockUserManagerState, launcherApps: LauncherApps = mockLauncherApps, shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap, - app: LauncherAppState = mockAppState, + context: Context = mockContext, bgDataModel: BgDataModel = mockBgDataModel, widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap, widgetInflater: WidgetInflater = mockWidgetInflater, @@ -297,11 +282,11 @@ class WorkspaceItemProcessorExtraTest { ) = WorkspaceItemProcessor( c = cursor, + context = context, memoryLogger = memoryLogger, userCache = userCache, userManagerState = userManagerState, launcherApps = launcherApps, - app = app, bgDataModel = bgDataModel, widgetProvidersMap = widgetProvidersMap, widgetInflater = widgetInflater, @@ -313,5 +298,8 @@ class WorkspaceItemProcessorExtraTest { shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts, installingPkgs = installingPkgs, allDeepShortcuts = allDeepShortcuts, + idp = InvariantDeviceProfile.INSTANCE.get(context), + iconCache = mockIconCache, + isSafeMode = false, ) } diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index 8846d6593a..67ee1ac789 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.ui.widget; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_ID_NOT_VALID; import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; @@ -318,7 +317,7 @@ public class BindWidgetTest extends BaseLauncherActivityTest<Launcher> { try { return MODEL_EXECUTOR.submit(() -> mModel.getModelDbController().query( - TABLE_NAME, null, itemIdMatch(0), null, null)).get(); + null, itemIdMatch(0), null, null)).get(); } catch (Exception e) { throw new RuntimeException(e); } |