Merge "Fix keyboard staying up in AOSP launcher." into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 878aa6e..4ff976d 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -501,10 +501,13 @@
}
flag {
- name: "enforce_system_radius_for_app_widgets"
+ name: "use_system_radius_for_app_widgets"
namespace: "launcher"
- description: "Enforce system radius for widget corners instead of a separate 16.dp value"
- bug: "370950552"
+ description: "Use system radius for enforced widget corners instead of a separate 16.dp value"
+ bug: "373351337"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -526,4 +529,11 @@
namespace: "launcher"
description: "Enable Taskbar LayoutTransition for Recent Apps"
bug: "343521765"
+}
+
+flag {
+ name: "enable_pinning_app_with_context_menu"
+ namespace: "launcher"
+ description: "Add options to pin/unpin to taskbar to app context menus."
+ bug: "375648361"
}
\ No newline at end of file
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 57bfb4a..8c39585 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -152,7 +152,7 @@
android:showOnLockScreen="true"
android:launchMode="singleTop"
android:exported="true"
- android:permission="android.permission.START_WIDGET_PICKER_ACTIVITY">
+ android:permission="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY">
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/quickstep/res/drawable/desktop_mode_ic_taskbar_menu_manage_windows.xml b/quickstep/res/drawable/desktop_mode_ic_taskbar_menu_manage_windows.xml
new file mode 100644
index 0000000..7d912a2
--- /dev/null
+++ b/quickstep/res/drawable/desktop_mode_ic_taskbar_menu_manage_windows.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/black" android:pathData="M160,880Q127,880 103.5,856.5Q80,833 80,800L80,440Q80,407 103.5,383.5Q127,360 160,360L240,360L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,520Q880,553 856.5,576.5Q833,600 800,600L720,600L720,800Q720,833 696.5,856.5Q673,880 640,880L160,880ZM160,800L640,800Q640,800 640,800Q640,800 640,800L640,520L160,520L160,800Q160,800 160,800Q160,800 160,800ZM720,520L800,520Q800,520 800,520Q800,520 800,520L800,240L320,240L320,360L640,360Q673,360 696.5,383.5Q720,407 720,440L720,520Z"/>
+</vector>
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 2420a46..4118500 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -22,6 +22,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/keyboard_quick_switch_margin_top"
android:layout_marginHorizontal="@dimen/keyboard_quick_switch_margin_ends"
+ android:layout_gravity="center_horizontal"
android:background="@drawable/keyboard_quick_switch_view_background"
android:clipToOutline="true"
android:alpha="0"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 0472007..5270284 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -24,10 +24,6 @@
android:focusable="true"
launcher:focusBorderColor="?attr/materialColorOutline"
launcher:hoverBorderColor="?attr/materialColorPrimary">
- <View
- android:id="@+id/background"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
<ViewStub
android:id="@+id/icon"
@@ -38,6 +34,13 @@
<com.android.quickstep.views.DesktopTaskContentView
android:id="@+id/desktop_content"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent">
+
+ <View
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </com.android.quickstep.views.DesktopTaskContentView>
</com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index c350bc5..441a80c 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prijeđite prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvršili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Izvršili ste pokret za povratak"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Napravili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Napravili ste pokret za povratak"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite da ne prijeđete prstom preblizu dnu zaslona"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osjetljivost pokreta povratka promijenite u postavkama"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Prijeđite prstom da biste se vratili"</string>
@@ -64,8 +64,8 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Pazite da prijeđete prstom prema gore od donjeg ruba zaslona"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Pazite da ne zastanete prije podizanja prsta"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Pazite da prijeđete prstom ravno prema gore"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Izvršili ste pokret za otvaranje početnog zaslona. Sad saznajte kako se vratiti."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Izvršili ste pokret za otvaranje početnog zaslona"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Napravili ste pokret za otvaranje početnog zaslona. Sad saznajte kako se vratiti."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Napravili ste pokret za otvaranje početnog zaslona"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prijeđite prstom da biste otvorili početni zaslon"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prijeđite prstom od dna zaslona prema gore. Tim pokretom uvijek će se otvoriti početni zaslon."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prijeđite s dva prsta od dna zaslona prema gore. Tim pokretom uvijek će se otvoriti početni zaslon."</string>
@@ -76,7 +76,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor dulje prije podizanja prsta"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prijeđite prstom ravno prema gore, a zatim zastanite"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste koristiti pokrete. Pokrete možete isključiti u postavkama."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Izvršili ste pokret za promjenu aplikacije"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Napravili ste pokret za promjenu aplikacije"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Povlačenje prstom za promjenu aplikacije"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Da biste promijenili aplikaciju, prijeđite prstom od dna zaslona prema gore, zadržite pritisak pa pustite."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Za promjenu aplikacije prijeđite s dva prsta od dna zaslona prema gore, zadržite pritisak i pustite."</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index e1400a9..4039f36 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -53,7 +53,7 @@
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pastikan Anda menggeser dari tepi kanan atau kiri ke tengah layar, lalu lepaskan"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Anda telah belajar cara geser dari kanan untuk kembali. Berikutnya, pelajari cara beralih aplikasi."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Anda telah menyelesaikan gestur kembali. Selanjutnya, pelajari cara beralih aplikasi."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah menyelesaikan gestur kembali"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah menyelesaikan gestur untuk kembali"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pastikan Anda tidak menggeser terlalu dekat ke bagian bawah layar"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Untuk mengubah sensitivitas gestur kembali, buka Setelan"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Geser untuk kembali"</string>
@@ -71,7 +71,7 @@
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Geser ke atas dengan 2 jari dari bawah layar. Gestur ini akan selalu membawa Anda ke Layar utama."</string>
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Buka layar utama"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Geser ke atas dari bagian bawah layar"</string>
- <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Bagus."</string>
+ <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Bagus!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pastikan Anda menggeser ke atas dari tepi bawah layar"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Coba tahan jendela lebih lama sebelum melepaskan"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pastikan Anda menggeser lurus ke atas, lalu berhenti sejenak"</string>
@@ -82,12 +82,12 @@
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Untuk beralih antar-aplikasi, geser ke atas dengan 2 jari dari bawah layar, tahan, lalu lepaskan."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Beralih aplikasi"</string>
<string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Geser ke atas dari bagian bawah layar, tahan, kemudian lepas"</string>
- <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Bagus."</string>
+ <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Oke!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Semua siap"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Selesai"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Setelan"</string>
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"Coba lagi"</string>
- <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bagus!"</string>
+ <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sip!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Selesai!"</string>
<string name="allset_hint" msgid="459504134589971527">"Geser ke atas untuk membuka Layar utama"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index bf2a211..bddca4d 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar að miðju skjásins og sleppa síðan"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Þú lærðir að strjúka frá hægri til að bakka. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Þú laukst við að kynna þér bendinguna „til baka“. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Þú laukst við að kynna þér bendinguna „til baka“"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Þú laukst við að kynna þér bendinguna „Til baka“. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Þú laukst við að kynna þér bendinguna „Til baka“"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Passaðu að strjúka ekki of nálægt neðri brún skjásins"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Til að breyta næmi til baka-bendingar ferðu í stillingar"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Strjúktu til að fara til baka"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index b30b000..a25b2bf 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -53,7 +53,7 @@
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"画面の右端または左端から中央に向かってスワイプし、指を離してください"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"「戻る」操作を完了しました。次は、アプリを切り替える方法を覚えましょう。"</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"「戻る」操作を学習しました"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"「戻る」ジェスチャーを学習しました"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"スワイプする際は画面の下部に近づきすぎないようにしましょう"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"「戻る」操作の感度を変更するには [設定] に移動します"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"スワイプで戻る"</string>
@@ -65,7 +65,7 @@
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"指を離す前にいったん止めないでください"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"まっすぐ上にスワイプしてください"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"「ホームに移動」操作を学習しました。次は、前の画面に戻る方法を覚えましょう。"</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"「ホームに移動」操作を学習しました"</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"「ホームに移動」ジェスチャーを学習しました"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"スワイプでホームに戻る"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 本の指で画面下部から上にスワイプします。この操作で常にホーム画面に戻ります。"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index afd53ac..5fc27d2 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -53,7 +53,7 @@
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ನೀವು ಬಲ ಅಥವಾ ಎಡ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್ನ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಂಡು ಬಿಟ್ಟುಬಿಡಿ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ಹಿಂದೆ ಹೋಗಲು ಬಲದಿಂದ ಸ್ವೈಪ್ ಮಾಡುವುದು ಹೇಗೆಂದು ಕಲಿತಿರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸುವುದು ಹೇಗೆಂದು ತಿಳಿಯಿರಿ."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ನೀವು ಹಿಂದಕ್ಕೆ ಹೋಗಿ ಎಂಬ ಜೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ನೀವು ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗಕ್ಕೆ ಹೆಚ್ಚು ಹತ್ತಿರ ಸ್ವೈಪ್ ಮಾಡದಂತೆ ನೋಡಿಕೊಳ್ಳಿ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ನ ಸೂಕ್ಷ್ಮತೆ ಬದಲಾಯಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"ಹಿಂದಕ್ಕೆ ಹೋಗಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -103,7 +103,7 @@
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಇನ್ನೊಂದು ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ರದ್ದುಮಾಡಿ"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಆಯ್ಕೆಯಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
<string name="split_widgets_not_supported" msgid="1355743038053053866">"ವಿಜೆಟ್ಗಳು ಪ್ರಸ್ತುತ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ, ಮತ್ತೊಂದು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ನ್ಯಾವಿಗೇಶನ್ ಟ್ಯುಟೋರಿಯಲ್ ಸ್ಕಿಪ್ ಮಾಡಬೇಕೇ?"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 821797b..d872287 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto kabisa"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto hadi katikati ya skrini na uachilie"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Sasa jifunze jinsi ya kubadilisha programu."</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Umekamilisha ishara ya kurudi nyuma. Hatua inayofuata, jifunze jinsi ya kubadilisha programu."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Umeweka ishara ya kurudi nyuma"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Umekamilisha mafunzo ya miguso ya kurudi nyuma. Hatua inayofuata, fahamu jinsi ya kubadilisha programu."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Umekamilisha mafunzo ya miguso ya kurudi nyuma"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hakikisha hutelezeshi kidole karibu sana na sehemu ya chini ya skrini"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Kubadilisha hisi ya ishara ya nyuma, nenda kwenye Mipangilio"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Telezesha kidole ili urudi nyuma"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 782a705..b221b22 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -118,6 +118,7 @@
<!-- Launcher app transition -->
<dimen name="closing_window_trans_y">115dp</dimen>
+ <dimen name="closing_freeform_window_trans_y">36dp</dimen>
<dimen name="quick_switch_scaling_scroll_threshold">100dp</dimen>
@@ -361,7 +362,6 @@
<dimen name="taskbar_running_app_indicator_width">12dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">4dp</dimen>
<dimen name="taskbar_minimized_app_indicator_width">6dp</dimen>
- <dimen name="taskbar_overflow_button_preview_stroke">2dp</dimen>
<!-- Transient taskbar -->
<dimen name="transient_taskbar_padding">12dp</dimen>
@@ -426,6 +426,9 @@
<dimen name="taskbar_pinning_popup_menu_vertical_margin">16dp</dimen>
<dimen name="taskbar_pinning_popup_menu_min_padding_from_screen_edge">16dp</dimen>
+ <!-- Taskbar Multi Instance Menu -->
+ <dimen name="taskbar_multi_instance_menu_min_padding_from_screen_edge">8dp</dimen>
+
<!--- Floating Ime Inset height-->
<dimen name="floating_ime_inset_height">60dp</dimen>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index c423d09..6ffcb9b 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -211,6 +211,7 @@
<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowShowWallpaper">false</item>
</style>
<!--
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 18337d3..e624be7 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -108,6 +108,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import android.window.DesktopModeFlags;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.WindowAnimationState;
@@ -166,11 +167,13 @@
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -214,6 +217,7 @@
public static final int CONTENT_ALPHA_DURATION = 217;
public static final int TRANSIENT_TASKBAR_TRANSITION_DURATION = 417;
+ public static final int PINNED_TASKBAR_TRANSITION_DURATION = 600;
public static final int TASKBAR_TO_APP_DURATION = 600;
// TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
// is solved.
@@ -233,6 +237,7 @@
protected final Handler mHandler;
private final float mClosingWindowTransY;
+ private final float mClosingFreeformWindowTransY;
private final float mMaxShadowRadius;
private final StartingWindowListener mStartingWindowListener =
@@ -290,6 +295,8 @@
Resources res = mLauncher.getResources();
mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
+ mClosingFreeformWindowTransY =
+ res.getDimensionPixelSize(R.dimen.closing_freeform_window_trans_y);
mMaxShadowRadius = res.getDimensionPixelSize(R.dimen.max_shadow_radius);
mLauncher.addOnDeviceProfileChangeListener(this);
@@ -1480,10 +1487,16 @@
? 0 : getWindowCornerRadius(mLauncher);
float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius;
closingAnimator.setDuration(duration);
+ boolean isFreeform = isFreeformAnimation(appTargets);
+ float translateY = isFreeform ? mClosingFreeformWindowTransY : mClosingWindowTransY;
+ float endScale = isFreeform ? 0.95f : 1f;
+ Interpolator alphaInterpolator = isFreeform
+ ? clampToDuration(LINEAR, 0, 100, duration)
+ : clampToDuration(LINEAR, 25, 125, duration);
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
- FloatProp mDy = new FloatProp(0, mClosingWindowTransY, DECELERATE_1_7);
- FloatProp mScale = new FloatProp(1f, 1f, DECELERATE_1_7);
- FloatProp mAlpha = new FloatProp(1f, 0f, clampToDuration(LINEAR, 25, 125, duration));
+ FloatProp mDy = new FloatProp(0, translateY, DECELERATE_1_7);
+ FloatProp mScale = new FloatProp(1f, endScale, DECELERATE_1_7);
+ FloatProp mAlpha = new FloatProp(1f, 0f, alphaInterpolator);
FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, DECELERATE_1_7);
@Override
@@ -1532,6 +1545,13 @@
return closingAnimator;
}
+ private boolean isFreeformAnimation(RemoteAnimationTarget[] appTargets) {
+ return DesktopModeStatus.canEnterDesktopMode(mLauncher.getApplicationContext())
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS.isTrue()
+ && Arrays.stream(appTargets)
+ .anyMatch(app -> app.taskInfo != null && app.taskInfo.isFreeform());
+ }
+
private void addCujInstrumentation(Animator anim, int cuj) {
anim.addListener(getCujAnimationSuccessListener(cuj));
}
@@ -1726,8 +1746,21 @@
return new AnimatorBackState(rectFSpringAnim, anim);
}
- public static int getTaskbarToHomeDuration() {
- if (enableScalingRevealHomeAnimation()) {
+ /** Get animation duration for taskbar for going to home. */
+ public static int getTaskbarToHomeDuration(boolean isPinnedTaskbar) {
+ return getTaskbarToHomeDuration(false, isPinnedTaskbar);
+ }
+
+ /**
+ * Get animation duration for taskbar for going to home.
+ *
+ * @param shouldOverrideToFastAnimation should overwrite scaling reveal home animation duration
+ */
+ public static int getTaskbarToHomeDuration(boolean shouldOverrideToFastAnimation,
+ boolean isPinnedTaskbar) {
+ if (isPinnedTaskbar) {
+ return PINNED_TASKBAR_TRANSITION_DURATION;
+ } else if (enableScalingRevealHomeAnimation() && !shouldOverrideToFastAnimation) {
return TASKBAR_TO_HOME_DURATION_SLOW;
} else {
return TASKBAR_TO_HOME_DURATION_FAST;
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 92d9516..8e80aa5 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -57,7 +57,7 @@
// Vertical padding of the icon that contributes to the expected cell height.
private final int mVerticalPadding;
// Extra padding that is used in the top app rows (prediction and search) that is not used in
- // the regular A-Z list. This only applies to single line label.
+ // the regular A-Z list.
private final int mTopRowExtraHeight;
// Helper to drawing the focus indicator.
@@ -140,7 +140,7 @@
// is not enabled. Otherwise, the extra height will increase by just the textHeight.
int extraHeight = (Flags.enableTwolineToggle() &&
LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext()))
- ? textHeight : mTopRowExtraHeight;
+ ? (textHeight + mTopRowExtraHeight) : mTopRowExtraHeight;
totalHeight += extraHeight;
return getVisibility() == GONE ? 0 : totalHeight + getPaddingTop() + getPaddingBottom();
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 5744464..fd0243a 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -488,6 +488,15 @@
}
});
}
+
+ public void onEnterDesktopModeTransitionStarted(int transitionDuration) {
+
+ }
+
+ @Override
+ public void onExitDesktopModeTransitionStarted(int transitionDuration) {
+
+ }
}
/** A listener for Taskbar in Desktop Mode. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 23a5a27..de42669 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -139,18 +139,42 @@
@NonNull Set<Integer> taskIdsToExclude,
boolean wasOpenedFromTaskbar) {
if (mQuickSwitchViewController != null) {
- if (!mQuickSwitchViewController.isCloseAnimationRunning()
- && mQuickSwitchViewController.wasOpenedFromTaskbar() == wasOpenedFromTaskbar) {
- return;
- }
+ if (!mQuickSwitchViewController.isCloseAnimationRunning()) {
+ if (mQuickSwitchViewController.wasOpenedFromTaskbar() == wasOpenedFromTaskbar) {
+ return;
+ }
- // Allow the KQS to be reopened during the close animation to make it more responsive.
- // Similarly, if KQS was opened in different mode (from taskbar vs. keyboard event),
- // close it so it can be reopened in the correct mode.
- // TODO(b/368119679) Consider updating list of shown tasks in place, or at least reopen
- // the view in the same vertical location.
- closeQuickSwitchView(false);
+ // Relayout the KQS view instead of recreating a new one if it is the current
+ // trigger surface is different than the previous one.
+ final int currentFocusIndexOverride =
+ currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
+ ? 0 : currentFocusedIndex;
+
+ // Skip the task reload if the list is not changed.
+ if (!mModel.isTaskListValid(mTaskListChangeId) || !taskIdsToExclude.equals(
+ mExcludedTaskIds)) {
+ mExcludedTaskIds = taskIdsToExclude;
+ mTaskListChangeId = mModel.getTasks((tasks) -> {
+ processLoadedTasks(tasks, taskIdsToExclude);
+ mQuickSwitchViewController.updateQuickSwitchView(
+ mTasks,
+ mNumHiddenTasks,
+ currentFocusIndexOverride,
+ mHasDesktopTask,
+ mWasDesktopTaskFilteredOut);
+ });
+ }
+
+ mQuickSwitchViewController.updateLayoutForSurface(wasOpenedFromTaskbar,
+ currentFocusIndexOverride);
+ return;
+ } else {
+ // Allow the KQS to be reopened during the close animation to make it more
+ // responsive.
+ closeQuickSwitchView(false);
+ }
}
+
mOverlayContext = mControllers.taskbarOverlayController.requestWindow();
if (Flags.taskbarOverflow()) {
mOverlayContext.getDragLayer().addTouchController(this);
@@ -186,13 +210,7 @@
mExcludedTaskIds = taskIdsToExclude;
mTaskListChangeId = mModel.getTasks((tasks) -> {
- mHasDesktopTask = false;
- mWasDesktopTaskFilteredOut = false;
- if (onDesktop) {
- processLoadedTasksOnDesktop(tasks, taskIdsToExclude);
- } else {
- processLoadedTasks(tasks, taskIdsToExclude);
- }
+ processLoadedTasks(tasks, taskIdsToExclude);
// Check if the first task is running after the recents model has updated so that we use
// the correct index.
mQuickSwitchViewController.openQuickSwitchView(
@@ -213,6 +231,17 @@
}
private void processLoadedTasks(List<GroupTask> tasks, Set<Integer> taskIdsToExclude) {
+ mHasDesktopTask = false;
+ mWasDesktopTaskFilteredOut = false;
+ if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ processLoadedTasksOnDesktop(tasks, taskIdsToExclude);
+ } else {
+ processLoadedTasksOutsideDesktop(tasks, taskIdsToExclude);
+ }
+ }
+
+ private void processLoadedTasksOutsideDesktop(List<GroupTask> tasks,
+ Set<Integer> taskIdsToExclude) {
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
mTasks = tasks.stream()
@@ -270,10 +299,6 @@
return;
}
mQuickSwitchViewController.closeQuickSwitchView(animate);
- if (mOnClosed != null) {
- mOnClosed.run();
- mOnClosed = null;
- }
}
/**
@@ -365,6 +390,13 @@
});
}
+ void onCloseStarted() {
+ if (mOnClosed != null) {
+ mOnClosed.run();
+ mOnClosed = null;
+ }
+ }
+
void onCloseComplete() {
if (Flags.taskbarOverflow() && mOverlayContext != null) {
mOverlayContext.getDragLayer()
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 05d34b5..1967dfd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -201,6 +201,8 @@
int currentFocusIndexOverride,
@NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks,
boolean useDesktopTaskView) {
+ mContent.removeAllViews();
+
mViewCallbacks = viewCallbacks;
Resources resources = context.getResources();
Resources.Theme theme = context.getTheme();
@@ -333,11 +335,17 @@
return closeAnimation;
}
- private void animateOpen(int currentFocusIndexOverride) {
+ protected void animateOpen(int currentFocusIndexOverride) {
if (mOpenAnimation != null) {
// Restart animation since currentFocusIndexOverride can change the initial scroll.
mOpenAnimation.cancel();
}
+
+ // Reset the alpha for the case where the KQS view is opened before.
+ setAlpha(0);
+ mScrollView.setAlpha(0);
+ mNoRecentItemsPane.setAlpha(0);
+
mOpenAnimation = new AnimatorSet();
Animator outlineAnimation = mOutlineAnimationProgress.animateToValue(1f);
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 390112e..e623b21 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -128,6 +128,23 @@
/* useDesktopTaskView= */ !onDesktop && hasDesktopTask);
}
+ protected void updateQuickSwitchView(
+ @NonNull List<GroupTask> tasks,
+ int numHiddenTasks,
+ int currentFocusIndexOverride,
+ boolean hasDesktopTask,
+ boolean wasDesktopTaskFilteredOut) {
+ mWasDesktopTaskFilteredOut = wasDesktopTaskFilteredOut;
+ mKeyboardQuickSwitchView.applyLoadPlan(
+ mOverlayContext,
+ tasks,
+ numHiddenTasks,
+ /* updateTasks= */ true,
+ currentFocusIndexOverride,
+ mViewCallbacks,
+ /* useDesktopTaskView= */ !mOnDesktop && hasDesktopTask);
+ }
+
protected void positionView(boolean wasOpenedFromTaskbar, boolean isTransientTaskbar) {
if (!wasOpenedFromTaskbar) {
// Keep the default positioning.
@@ -155,6 +172,20 @@
mKeyboardQuickSwitchView.setLayoutParams(lp);
}
+ protected void updateLayoutForSurface(boolean updateLayoutFromTaskbar,
+ int currentFocusIndexOverride) {
+ BaseDragLayer.LayoutParams lp =
+ (BaseDragLayer.LayoutParams) mKeyboardQuickSwitchView.getLayoutParams();
+
+ if (updateLayoutFromTaskbar) {
+ lp.width = BaseDragLayer.LayoutParams.WRAP_CONTENT;
+ } else {
+ lp.width = BaseDragLayer.LayoutParams.MATCH_PARENT;
+ }
+
+ mKeyboardQuickSwitchView.animateOpen(currentFocusIndexOverride);
+ }
+
boolean isCloseAnimationRunning() {
return mCloseAnimation != null;
}
@@ -167,6 +198,7 @@
// Let currently-running animation finish.
return;
}
+ mControllerCallbacks.onCloseStarted();
if (!animate) {
InteractionJankMonitorWrapper.begin(
mKeyboardQuickSwitchView, Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 4a94be7..c5be13d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -33,6 +33,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
+import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
@@ -83,6 +84,7 @@
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
dp -> {
onStashedInAppChanged(dp);
+ adjustHotseatForBubbleBar();
if (mControllers != null && mControllers.taskbarViewController != null) {
mControllers.taskbarViewController.onRotationChanged(dp);
}
@@ -152,8 +154,9 @@
@Override
protected boolean isTaskbarTouchable() {
- return !(mTaskbarLauncherStateController.isAnimatingToLauncher()
- && mTaskbarLauncherStateController.isTaskbarAlignedWithHotseat());
+ // Touching down during animation to Hotseat will end the transition and allow the touch to
+ // go through to the Hotseat directly.
+ return !isAnimatingToHotseat();
}
public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) {
@@ -210,8 +213,12 @@
}
private int getTaskbarAnimationDuration(boolean isVisible) {
- if (isVisible && !mLauncher.getPredictiveBackToHomeInProgress()) {
- return getTaskbarToHomeDuration();
+ // fast animation duration since we will not be playing workspace reveal animation.
+ boolean shouldOverrideToFastAnimation =
+ !isHotseatIconOnTopWhenAligned() || mLauncher.getPredictiveBackToHomeInProgress();
+ boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mLauncher);
+ if (isVisible || isPinnedTaskbar) {
+ return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar);
} else {
return DisplayController.isTransientTaskbar(mLauncher)
? TRANSIENT_TASKBAR_TRANSITION_DURATION
@@ -263,6 +270,14 @@
}
}
+ private void adjustHotseatForBubbleBar() {
+ Hotseat hotseat = mLauncher.getHotseat();
+ if (mControllers.bubbleControllers.isEmpty() || hotseat == null) return;
+ boolean hiddenForBubbles =
+ mControllers.bubbleControllers.get().bubbleBarViewController.isHiddenForNoBubbles();
+ hotseat.post(() -> adjustHotseatForBubbleBar(!hiddenForBubbles));
+ }
+
/**
* Create Taskbar animation when going from an app to Launcher as part of recents transition.
* @param toState If known, the state we will end up in when reaching Launcher.
@@ -426,6 +441,17 @@
}
@Override
+ public boolean isAnimatingToHotseat() {
+ return mTaskbarLauncherStateController.isAnimatingToLauncher()
+ && isIconAlignedWithHotseat();
+ }
+
+ @Override
+ public void endAnimationToHotseat() {
+ mTaskbarLauncherStateController.resetIconAlignment();
+ }
+
+ @Override
protected boolean isInOverviewUi() {
return mTaskbarLauncherStateController.isInOverviewUi();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
new file mode 100644
index 0000000..860e822
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.view.MotionEvent
+import android.view.View
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.popup.SystemShortcut
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext
+import com.android.launcher3.util.Themes
+import com.android.launcher3.util.TouchController
+import com.android.launcher3.views.ActivityContext
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.util.GroupTask
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import java.util.Collections
+import java.util.function.Predicate
+
+/**
+ * A single menu item shortcut to execute displaying open instances of an app. Default interaction
+ * for [onClick] is to open the menu in a floating window. Touching one of the displayed tasks
+ * launches it.
+ */
+class ManageWindowsTaskbarShortcut<T>(
+ private val target: T,
+ private val itemInfo: ItemInfo?,
+ private val originalView: View,
+ private val controllers: TaskbarControllers,
+) :
+ SystemShortcut<T>(
+ R.drawable.desktop_mode_ic_taskbar_menu_manage_windows,
+ R.string.manage_windows_option_taskbar,
+ target,
+ itemInfo,
+ originalView,
+ ) where T : Context?, T : ActivityContext? {
+ private lateinit var taskbarShortcutAllWindowsView: TaskbarShortcutManageWindowsView
+ private val recentsModel = RecentsModel.INSTANCE[controllers.taskbarActivityContext]
+
+ override fun onClick(v: View?) {
+ val filter =
+ Predicate<GroupTask> { task: GroupTask? ->
+ task != null && task.task1.key.packageName == itemInfo?.getTargetPackage()
+ }
+ recentsModel.getTasks(
+ { tasks: List<GroupTask> ->
+ // Since fetching thumbnails is asynchronous, use this set to gate until the tasks
+ // are ready to display
+ val pendingTaskIds =
+ Collections.synchronizedSet(tasks.map { it.task1.key.id }.toMutableSet())
+ createAndShowTaskShortcutView(tasks, pendingTaskIds)
+ },
+ filter,
+ )
+ }
+
+ /**
+ * Processes a list of tasks to generate thumbnails and create a taskbar shortcut view.
+ *
+ * Iterates through the tasks, retrieves thumbnails, and adds them to a list. When all
+ * thumbnails are processed, it creates a [TaskbarShortcutManageWindowsView] with the collected
+ * thumbnails and positions it appropriately.
+ */
+ private fun createAndShowTaskShortcutView(
+ tasks: List<GroupTask?>,
+ pendingTaskIds: MutableSet<Int>,
+ ) {
+ val taskList = arrayListOf<Pair<Int, Bitmap?>>()
+ tasks.forEach { groupTask ->
+ groupTask?.task1?.let { task ->
+ recentsModel.thumbnailCache.getThumbnailInBackground(task) {
+ thumbnailData: ThumbnailData ->
+ pendingTaskIds.remove(task.key.id)
+ // Add the current pair of task id and ThumbnailData to the list of all tasks
+ if (thumbnailData.thumbnail != null) {
+ taskList.add(task.key.id to thumbnailData.thumbnail)
+ }
+
+ // If the set is empty, all thumbnails have been fetched
+ if (pendingTaskIds.isEmpty() && taskList.isNotEmpty()) {
+ createAndPositionTaskbarShortcut(taskList)
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates and positions the [TaskbarShortcutManageWindowsView] with the provided thumbnails.
+ */
+ private fun createAndPositionTaskbarShortcut(taskList: ArrayList<Pair<Int, Bitmap?>>) {
+ val onIconClickListener =
+ ({ taskId: Int? ->
+ taskbarShortcutAllWindowsView.removeFromContainer()
+ if (taskId != null) {
+ SystemUiProxy.INSTANCE.get(target).showDesktopApp(taskId, null)
+ }
+ })
+
+ val onOutsideClickListener = { taskbarShortcutAllWindowsView.removeFromContainer() }
+
+ taskbarShortcutAllWindowsView =
+ TaskbarShortcutManageWindowsView(
+ originalView,
+ controllers.taskbarOverlayController.requestWindow(),
+ taskList,
+ onIconClickListener,
+ onOutsideClickListener,
+ controllers,
+ )
+ }
+
+ /**
+ * A view container for displaying the window of open instances of an app
+ *
+ * Handles showing the window snapshots, adding the carousel to the overlay, and closing it.
+ * Also acts as a touch controller to intercept touch events outside the carousel to close it.
+ */
+ class TaskbarShortcutManageWindowsView(
+ private val originalView: View,
+ private val taskbarOverlayContext: TaskbarOverlayContext,
+ snapshotList: ArrayList<Pair<Int, Bitmap?>>,
+ onIconClickListener: (Int) -> Unit,
+ onOutsideClickListener: () -> Unit,
+ private val controllers: TaskbarControllers,
+ ) :
+ ManageWindowsViewContainer(
+ originalView.context,
+ Themes.getAttrColor(originalView.context, R.attr.materialColorSurfaceBright),
+ ),
+ TouchController {
+ private val taskbarActivityContext = controllers.taskbarActivityContext
+
+ init {
+ createAndShowMenuView(snapshotList, onIconClickListener, onOutsideClickListener)
+ taskbarOverlayContext.dragLayer.addTouchController(this)
+ }
+
+ /** Adds the carousel menu to the taskbar overlay drag layer */
+ override fun addToContainer(menuView: ManageWindowsView) {
+ positionCarouselMenu()
+
+ controllers.taskbarAutohideSuspendController.updateFlag(
+ FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ true,
+ )
+ AbstractFloatingView.closeAllOpenViewsExcept(
+ taskbarActivityContext,
+ AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY,
+ )
+ menuView.rootView.minimumHeight = menuView.menuHeight
+ menuView.rootView.minimumWidth = menuView.menuWidth
+
+ taskbarOverlayContext.dragLayer?.addView(menuView.rootView)
+ menuView.rootView.requestFocus()
+ }
+
+ /**
+ * Positions the carousel menu relative to the taskbar and the calling app's icon.
+ *
+ * Calculates the Y position to place the carousel above the taskbar, and the X position to
+ * align with the calling app while ensuring it doesn't go beyond the screen edge.
+ */
+ private fun positionCarouselMenu() {
+ val deviceProfile = taskbarActivityContext.deviceProfile
+ val margin =
+ context.resources.getDimension(
+ R.dimen.taskbar_multi_instance_menu_min_padding_from_screen_edge
+ )
+
+ // Calculate the Y position to place the carousel above the taskbar
+ menuView.rootView.y =
+ deviceProfile.availableHeightPx -
+ menuView.menuHeight -
+ controllers.taskbarStashController.touchableHeight -
+ margin
+
+ // Calculate the X position to align with the calling app,
+ // but avoid clashing with the screen edge
+ menuView.rootView.translationX =
+ if (Utilities.isRtl(context.resources)) {
+ -(deviceProfile.availableWidthPx - menuView.menuWidth) / 2f
+ } else {
+ val maxX = deviceProfile.availableWidthPx - menuView.menuWidth - margin
+ minOf(originalView.x, maxX)
+ }
+ }
+
+ /** Closes the carousel menu and removes it from the taskbar overlay drag layer */
+ override fun removeFromContainer() {
+ controllers.taskbarAutohideSuspendController.updateFlag(
+ FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ false,
+ )
+ controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true)
+ taskbarOverlayContext.dragLayer?.removeView(menuView.rootView)
+ taskbarOverlayContext.dragLayer.removeTouchController(this)
+ }
+
+ /** TouchController implementations for closing the carousel when touched outside */
+ override fun onControllerTouchEvent(ev: MotionEvent?): Boolean {
+ return false
+ }
+
+ override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
+ ev?.let {
+ if (
+ it.action == MotionEvent.ACTION_DOWN &&
+ !taskbarOverlayContext.dragLayer.isEventOverView(menuView.rootView, it)
+ ) {
+ removeFromContainer()
+ }
+ }
+ return false
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index fbd1b6e..f9e7cf0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static android.view.KeyEvent.ACTION_UP;
import static android.view.View.AccessibilityDelegate;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -72,7 +73,6 @@
import android.graphics.drawable.RotateDrawable;
import android.inputmethodservice.InputMethodService;
import android.os.Handler;
-import android.os.SystemClock;
import android.util.Property;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -448,14 +448,16 @@
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
flags -> (flags & FLAG_IME_VISIBLE) != 0,
ROTATION_DRAWABLE_PERCENT, 1f, 0f));
- // Translate back button to be at end/start of other buttons for keyguard
+ // Translate back button to be at end/start of other buttons for keyguard (only after SUW
+ // since it is laid to align with SUW actions while in that state)
int navButtonSize = mContext.getResources().getDimensionPixelSize(
R.dimen.taskbar_nav_buttons_size);
boolean isRtl = Utilities.isRtl(mContext.getResources());
if (!mContext.isPhoneMode()) {
mPropertyHolders.add(new StatePropertyHolder(
- mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
- || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
+ mBackButton, flags -> mContext.isUserSetupComplete()
+ && ((flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
+ || (flags & FLAG_KEYGUARD_VISIBLE) != 0),
VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
}
@@ -862,17 +864,12 @@
TaskbarNavButtonController navButtonController) {
buttonView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_MOVE) return false;
- long time = SystemClock.uptimeMillis();
- int action = event.getAction();
- KeyEvent keyEvent = new KeyEvent(time, time,
- action == MotionEvent.ACTION_DOWN ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
- KeyEvent.KEYCODE_BACK, 0);
- if (event.getAction() == MotionEvent.ACTION_CANCEL) {
- keyEvent.cancel();
- }
- navButtonController.executeBack(keyEvent);
-
- if (action == MotionEvent.ACTION_UP) {
+ int motionEventAction = event.getAction();
+ int keyEventAction = motionEventAction == MotionEvent.ACTION_DOWN
+ ? KeyEvent.ACTION_DOWN : ACTION_UP;
+ boolean isCancelled = event.getAction() == MotionEvent.ACTION_CANCEL;
+ navButtonController.sendBackKeyEvent(keyEventAction, isCancelled);
+ if (motionEventAction == MotionEvent.ACTION_UP) {
buttonView.performClick();
}
return false;
@@ -1293,7 +1290,10 @@
boolean isNavbarOnRight = location.isOnLeft(mNavButtonsView.isLayoutRtl());
DeviceProfile dp = mContext.getDeviceProfile();
float navBarTargetStartX;
- if (mContext.shouldStartAlignTaskbar()) {
+ if (!mContext.isUserSetupComplete()) {
+ // Skip additional translations on the nav bar container while in SUW layout
+ return 0;
+ } else if (mContext.shouldStartAlignTaskbar()) {
int navBarSpacing = dp.inlineNavButtonsEndSpacingPx;
// If the taskbar is start aligned the navigation bar is aligned to the start or end of
// the container, depending on the bubble bar location
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 82acc0c..8149f81 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -418,7 +418,7 @@
/** Called when the visibility of the bubble bar changed. */
public void bubbleBarVisibilityChanged(boolean isVisible) {
mControllers.uiController.adjustHotseatForBubbleBar(isVisible);
- mControllers.taskbarViewController.resetIconAlignmentController();
+ mControllers.taskbarViewController.adjustTaskbarForBubbleBar();
}
public void init(@NonNull TaskbarSharedState sharedState) {
@@ -582,7 +582,9 @@
int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
- if (DisplayController.isTransientTaskbar(this) && !isRunningInTestHarness()) {
+ boolean watchOutside = DisplayController.isTransientTaskbar(this)
+ || isThreeButtonNav();
+ if (watchOutside && !isRunningInTestHarness()) {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index 8ab2ffa..bdc7f92 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -47,6 +47,8 @@
public static final int FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR = 1 << 5;
// User has hovered the taskbar.
public static final int FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS = 1 << 6;
+ // User has multi instance window open.
+ public static final int FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN = 1 << 7;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -56,6 +58,7 @@
FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+ FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {}
@@ -133,6 +136,8 @@
"FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
"FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ "FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN");
return str.toString();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index c0e921e..ea6d82b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -23,7 +23,6 @@
import android.graphics.Path
import android.graphics.RectF
import com.android.app.animation.Interpolators
-import com.android.internal.policy.ScreenDecorationsUtils
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapRange
@@ -98,12 +97,9 @@
shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
}
- if (context.areDesktopTasksVisible()) {
- fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
- cornerRadius = fullCornerRadius
- } else {
- fullCornerRadius = context.cornerRadius.toFloat()
- cornerRadius = fullCornerRadius
+ fullCornerRadius = context.cornerRadius.toFloat()
+ cornerRadius = fullCornerRadius
+ if (!context.areDesktopTasksVisible()) {
setCornerRoundness(MAX_ROUNDNESS)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 5a63ca6..db70724 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -221,10 +221,13 @@
uiController = newUiController;
uiController.init(this);
uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags);
- // if bubble controllers are present take bubble bar location, else set it to null
+ // if bubble controllers are present configure the UI controller
bubbleControllers.ifPresentOrElse(bubbleControllers -> {
BubbleBarLocation location =
bubbleControllers.bubbleBarViewController.getBubbleBarLocation();
+ boolean hiddenForBubbles =
+ bubbleControllers.bubbleBarViewController.isHiddenForNoBubbles();
+ uiController.adjustHotseatForBubbleBar(!hiddenForBubbles);
uiController.onBubbleBarLocationUpdated(location);
}, () -> uiController.onBubbleBarLocationUpdated(null));
// Notify that the ui controller has changed
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index e16c76d..8b52112 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -262,6 +262,7 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+ mControllerCallbacks.onDispatchTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 2845cee..925e10b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -23,6 +23,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemProperties;
+import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import com.android.launcher3.DeviceProfile;
@@ -325,5 +326,15 @@
}
mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas);
}
+
+ /** Handles any touch event before it is dispatched to the rest of TaskbarDragLayer. */
+ public void onDispatchTouchEvent(MotionEvent ev) {
+ if (mActivity.isThreeButtonNav() && ev.getAction() == MotionEvent.ACTION_OUTSIDE
+ && mControllers.uiController.isAnimatingToHotseat()) {
+ // When touching during animation to home, jump to the end so Hotseat can handle
+ // the touch. (Gesture Navigation handles this in AbsSwipeUpHandler.)
+ mControllers.uiController.endAnimationToHotseat();
+ }
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index fa04739..f33666a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
+import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH;
@@ -222,7 +223,9 @@
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
if (!mShouldDelayLauncherStateAnim) {
if (toState == LauncherState.NORMAL) {
- applyState(QuickstepTransitionManager.getTaskbarToHomeDuration());
+ applyState(QuickstepTransitionManager.getTaskbarToHomeDuration(
+ DisplayController.isPinnedTaskbar(
+ mControllers.taskbarActivityContext)));
} else {
applyState();
}
@@ -459,9 +462,12 @@
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
final boolean isInLauncher = isInLauncher();
+ final boolean isInOverview = mControllers.uiController.isInOverviewUi();
final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
final float toAlignment = isIconAlignedWithHotseat ? 1 : 0;
boolean handleOpenFloatingViews = false;
+ boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(
+ mControllers.taskbarActivityContext);
if (DEBUG) {
Log.d(TAG, "onStateChangeApplied - isInLauncher: " + isInLauncher
+ ", mLauncherState: " + mLauncherState
@@ -469,7 +475,7 @@
}
mControllers.bubbleControllers.ifPresent(controllers -> {
// Show the bubble bar when on launcher home (hotseat icons visible) or in overview
- boolean onOverview = mLauncherState == LauncherState.OVERVIEW;
+ boolean onOverview = isInLauncher && mLauncherState == LauncherState.OVERVIEW;
boolean hotseatIconsVisible = isInLauncher && mLauncherState.areElementsVisible(
mLauncher, HOTSEAT_ICONS);
BubbleLauncherState state = onOverview
@@ -573,10 +579,17 @@
}
float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
+ AnimatedFloat taskbarBgOffset =
+ mControllers.taskbarDragLayerController.getTaskbarBackgroundOffset();
+ boolean showTaskbar = !isInLauncher || isInOverview;
+ float taskbarBgOffsetEnd = showTaskbar ? 0f : 1f;
+ float taskbarBgOffsetStart = showTaskbar ? 1f : 0f;
// Don't animate if background has reached desired value.
if (mTaskbarBackgroundAlpha.isAnimating()
- || mTaskbarBackgroundAlpha.value != backgroundAlpha) {
+ || mTaskbarBackgroundAlpha.value != backgroundAlpha
+ || taskbarBgOffset.isAnimatingToValue(taskbarBgOffsetStart)
+ || taskbarBgOffset.value != taskbarBgOffsetEnd) {
mTaskbarBackgroundAlpha.cancelAnimation();
if (DEBUG) {
Log.d(TAG, "onStateChangeApplied - taskbarBackgroundAlpha - "
@@ -587,25 +600,35 @@
boolean isInLauncherIconNotAligned = isInLauncher && !isIconAlignedWithHotseat;
boolean notInLauncherIconNotAligned = !isInLauncher && !isIconAlignedWithHotseat;
boolean isInLauncherIconIsAligned = isInLauncher && isIconAlignedWithHotseat;
+ // When Hotseat icons are not on top don't change duration or add start delay.
+ // This will keep the duration in sync for icon alignment and background fade in/out.
+ // For example, launching app from launcher all apps.
+ boolean isHotseatIconOnTopWhenAligned =
+ mControllers.uiController.isHotseatIconOnTopWhenAligned();
float startDelay = 0;
// We want to delay the background from fading in so that the icons have time to move
// into the bounds of the background before it appears.
if (isInLauncherIconNotAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
- } else if (notInLauncherIconNotAligned) {
+ } else if (notInLauncherIconNotAligned && isHotseatIconOnTopWhenAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
}
float newDuration = duration - startDelay;
- if (isInLauncherIconIsAligned) {
+ if (isInLauncherIconIsAligned && isHotseatIconOnTopWhenAligned) {
// Make the background fade out faster so that it is gone by the time the
// icons move outside of the bounds of the background.
newDuration = duration * TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT;
}
- Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha
- .animateToValue(backgroundAlpha)
- .setDuration((long) newDuration);
- taskbarBackgroundAlpha.setStartDelay((long) startDelay);
+ Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha.animateToValue(
+ backgroundAlpha);
+ if (isPinnedTaskbar) {
+ setupPinnedTaskbarAnimation(animatorSet, showTaskbar, taskbarBgOffset,
+ taskbarBgOffsetStart, taskbarBgOffsetEnd, duration, taskbarBackgroundAlpha);
+ } else {
+ taskbarBackgroundAlpha.setDuration((long) newDuration);
+ taskbarBackgroundAlpha.setStartDelay((long) startDelay);
+ }
animatorSet.play(taskbarBackgroundAlpha);
}
@@ -671,15 +694,18 @@
+ mIconAlignment.value
+ " -> " + toAlignment + ": " + duration);
}
- if (hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
- iconAlignAnim.setInterpolator(FINAL_FRAME);
- } else {
- animatorSet.play(iconAlignAnim);
+ if (!isPinnedTaskbar) {
+ if (hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
+ iconAlignAnim.setInterpolator(FINAL_FRAME);
+ } else {
+ animatorSet.play(iconAlignAnim);
+ }
}
}
- Interpolator interpolator = enableScalingRevealHomeAnimation()
+ Interpolator interpolator = enableScalingRevealHomeAnimation() && !isPinnedTaskbar
? ScalingWorkspaceRevealAnim.SCALE_INTERPOLATOR : EMPHASIZED;
+
animatorSet.setInterpolator(interpolator);
if (start) {
@@ -688,6 +714,49 @@
return animatorSet;
}
+ private void setupPinnedTaskbarAnimation(AnimatorSet animatorSet, boolean showTaskbar,
+ AnimatedFloat taskbarBgOffset, float taskbarBgOffsetStart, float taskbarBgOffsetEnd,
+ long duration, Animator taskbarBackgroundAlpha) {
+ float targetAlpha = !showTaskbar ? 1 : 0;
+ mLauncher.getHotseat().setIconsAlpha(targetAlpha, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
+ if (mIsQsbInline) {
+ mLauncher.getHotseat().setQsbAlpha(targetAlpha,
+ ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
+ }
+
+ if ((taskbarBgOffset.value != taskbarBgOffsetEnd && !taskbarBgOffset.isAnimating())
+ || taskbarBgOffset.isAnimatingToValue(taskbarBgOffsetStart)) {
+ taskbarBgOffset.cancelAnimation();
+ Animator taskbarIconAlpha = mTaskbarAlphaForHome.animateToValue(
+ showTaskbar ? 1f : 0f);
+ AnimatedFloat taskbarIconTranslationYForHome =
+ mControllers.taskbarViewController.mTaskbarIconTranslationYForHome;
+ ObjectAnimator taskbarBackgroundOffset = taskbarBgOffset.animateToValue(
+ taskbarBgOffsetStart,
+ taskbarBgOffsetEnd);
+ ObjectAnimator taskbarIconsYTranslation = null;
+ float taskbarHeight =
+ mControllers.taskbarActivityContext.getDeviceProfile().taskbarHeight;
+ if (showTaskbar) {
+ taskbarIconsYTranslation = taskbarIconTranslationYForHome.animateToValue(
+ taskbarHeight, 0);
+ } else {
+ taskbarIconsYTranslation = taskbarIconTranslationYForHome.animateToValue(0,
+ taskbarHeight);
+ }
+
+ taskbarIconAlpha.setDuration(duration);
+ taskbarIconsYTranslation.setDuration(duration);
+ taskbarBackgroundOffset.setDuration(duration);
+
+ animatorSet.play(taskbarIconAlpha);
+ animatorSet.play(taskbarIconsYTranslation);
+ animatorSet.play(taskbarBackgroundOffset);
+ }
+ taskbarBackgroundAlpha.setInterpolator(showTaskbar ? INSTANT : FINAL_FRAME);
+ taskbarBackgroundAlpha.setDuration(duration);
+ }
+
/**
* Whether the taskbar is aligned with the hotseat in the current/target launcher state.
*
@@ -950,8 +1019,9 @@
*
* @param finishedToApp {@code true} if the recents animation finished to showing an app and
* not workspace or overview
- * @param canceled {@code true} if the recents animation was canceled instead of finishing
- * to completion
+ * @param canceled {@code true} if the recents animation was canceled instead of
+ * finishing
+ * to completion
*/
private void endGestureStateOverride(boolean finishedToApp, boolean canceled) {
mCallbacks.removeListener(this);
@@ -968,6 +1038,7 @@
/**
* Updates the visible state immediately to ensure a seamless handoff.
+ *
* @param finishedToApp True iff user is in an app.
*/
private void updateStateForUserFinishedToApp(boolean finishedToApp) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 0807ee9..d4814d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -46,6 +46,7 @@
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
+import android.util.SparseArray;
import android.view.Display;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -115,13 +116,13 @@
private final Context mContext;
private final @Nullable Context mNavigationBarPanelContext;
private WindowManager mWindowManager;
- private FrameLayout mTaskbarRootLayout;
+ private FrameLayout mDefaultRootLayout;
private boolean mAddedWindow;
- private final TaskbarNavButtonController mNavButtonController;
- private final ComponentCallbacks mComponentCallbacks;
+ private final TaskbarNavButtonController mDefaultNavButtonController;
+ private final ComponentCallbacks mDefaultComponentCallbacks;
private final SimpleBroadcastReceiver mShutdownReceiver =
- new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> destroyExistingTaskbar());
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> destroyAllTaskbars());
// The source for this provider is set when Launcher is available
// We use 'non-destroyable' version here so the original provider won't be destroyed
@@ -129,8 +130,8 @@
// It's destruction/creation will be managed by the activity.
private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
new NonDestroyableScopedUnfoldTransitionProgressProvider();
-
- private TaskbarActivityContext mTaskbarActivityContext;
+ /** DisplayId - {@link TaskbarActivityContext} map for Connected Display. */
+ private final SparseArray<TaskbarActivityContext> mTaskbars = new SparseArray<>();
private StatefulActivity mActivity;
private RecentsViewContainer mRecentsViewContainer;
@@ -167,7 +168,9 @@
private final Runnable mActivityOnDestroyCallback = new Runnable() {
@Override
public void run() {
+ int displayId = getDefaultDisplayId();
if (mActivity != null) {
+ displayId = mActivity.getDisplayId();
mActivity.removeOnDeviceProfileChangeListener(
mDebugActivityDeviceProfileChanged);
Log.d(TASKBAR_NOT_DESTROYED_TAG,
@@ -180,8 +183,9 @@
}
mActivity = null;
debugWhyTaskbarNotDestroyed("clearActivity");
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.setUIController(TaskbarUIController.DEFAULT);
}
mUnfoldProgressProvider.setSourceProvider(null);
}
@@ -236,27 +240,27 @@
mDesktopVisibilityController = desktopVisibilityController;
if (enableTaskbarNoRecreate()) {
mWindowManager = mContext.getSystemService(WindowManager.class);
- mTaskbarRootLayout = new FrameLayout(mContext) {
+ mDefaultRootLayout = new FrameLayout(mContext) {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// The motion events can be outside the view bounds of task bar, and hence
// manually dispatching them to the drag layer here.
- if (mTaskbarActivityContext != null
- && mTaskbarActivityContext.getDragLayer().isAttachedToWindow()) {
- return mTaskbarActivityContext.getDragLayer().dispatchTouchEvent(ev);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null && taskbar.getDragLayer().isAttachedToWindow()) {
+ return taskbar.getDragLayer().dispatchTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
};
}
- mNavButtonController = new TaskbarNavButtonController(
+ mDefaultNavButtonController = new TaskbarNavButtonController(
context,
navCallbacks,
SystemUiProxy.INSTANCE.get(mContext),
ContextualEduStatsManager.INSTANCE.get(mContext),
new Handler(),
ContextualSearchInvoker.newInstance(mContext));
- mComponentCallbacks = new ComponentCallbacks() {
+ mDefaultComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@Override
@@ -265,6 +269,7 @@
"onConfigurationChanged: " + newConfig);
debugWhyTaskbarNotDestroyed(
"TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
+ // TODO: adapt this logic to be specific to different displays.
DeviceProfile dp = mUserUnlocked
? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
: null;
@@ -281,12 +286,12 @@
debugWhyTaskbarNotDestroyed("ComponentCallbacks#onConfigurationChanged() "
+ "configDiff=" + Configuration.configurationDiffToString(configDiff));
- if (configDiff != 0 || mTaskbarActivityContext == null) {
+ if (configDiff != 0 || getCurrentActivityContext() == null) {
recreateTaskbar();
} else {
// Config change might be handled without re-creating the taskbar
if (dp != null && !isTaskbarEnabled(dp)) {
- destroyExistingTaskbar();
+ destroyDefaultTaskbar();
} else {
if (dp != null && isTaskbarEnabled(dp)) {
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
@@ -295,10 +300,10 @@
// block above?
recreateTaskbar();
} else {
- mTaskbarActivityContext.updateDeviceProfile(dp);
+ getCurrentActivityContext().updateDeviceProfile(dp);
}
}
- mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ getCurrentActivityContext().onConfigurationChanged(configDiff);
}
}
mOldConfig = new Configuration(newConfig);
@@ -315,7 +320,7 @@
SettingsCache.INSTANCE.get(mContext)
.register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
- mContext.registerComponentCallbacks(mComponentCallbacks);
+ mContext.registerComponentCallbacks(mDefaultComponentCallbacks);
mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
UI_HELPER_EXECUTOR.execute(() -> {
mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast(
@@ -331,13 +336,25 @@
recreateTaskbar();
}
- private void destroyExistingTaskbar() {
- debugWhyTaskbarNotDestroyed("destroyExistingTaskbar: " + mTaskbarActivityContext);
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onDestroy();
- if (!ENABLE_TASKBAR_NAVBAR_UNIFICATION || enableTaskbarNoRecreate()) {
- mTaskbarActivityContext = null;
- }
+ private void destroyAllTaskbars() {
+ for (int i = 0; i < mTaskbars.size(); i++) {
+ int displayId = mTaskbars.keyAt(i);
+ destroyTaskbarForDisplay(displayId);
+ }
+ }
+
+ private void destroyDefaultTaskbar() {
+ destroyTaskbarForDisplay(getDefaultDisplayId());
+ }
+
+ private void destroyTaskbarForDisplay(int displayId) {
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ debugWhyTaskbarNotDestroyed(
+ "destroyTaskbarForDisplay: " + taskbar + " displayId=" + displayId);
+ if (taskbar != null) {
+ taskbar.onDestroy();
+ // remove all defaults that we store
+ removeTaskbarFromMap(displayId);
}
DeviceProfile dp = mUserUnlocked ?
LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
@@ -350,8 +367,10 @@
* Show Taskbar upon receiving broadcast
*/
private void showTaskbarFromBroadcast(Intent intent) {
- if (ACTION_SHOW_TASKBAR.equals(intent.getAction()) && mTaskbarActivityContext != null) {
- mTaskbarActivityContext.showTaskbarFromBroadcast();
+ // TODO: make this code displayId specific
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (ACTION_SHOW_TASKBAR.equals(intent.getAction()) && taskbar != null) {
+ taskbar.showTaskbarFromBroadcast();
}
}
@@ -359,12 +378,13 @@
* Toggles All Apps for Taskbar or Launcher depending on the current state.
*/
public void toggleAllApps() {
- if (mTaskbarActivityContext == null || mTaskbarActivityContext.canToggleHomeAllApps()) {
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar == null || taskbar.canToggleHomeAllApps()) {
// Home All Apps should be toggled from this class, because the controllers are not
// initialized when Taskbar is disabled (i.e. TaskbarActivityContext is null).
if (mActivity instanceof Launcher l) l.toggleAllAppsSearch();
} else {
- mTaskbarActivityContext.toggleAllAppsSearch();
+ taskbar.toggleAllAppsSearch();
}
}
@@ -375,8 +395,8 @@
* progress.
*/
public AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
- return mTaskbarActivityContext == null
- ? null : mTaskbarActivityContext.createLauncherStartFromSuwAnim(duration);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ return taskbar == null ? null : taskbar.createLauncherStartFromSuwAnim(duration);
}
/**
@@ -386,7 +406,7 @@
mUserUnlocked = true;
DisplayController.INSTANCE.get(mContext).addChangeListener(mRecreationListener);
recreateTaskbar();
- addTaskbarRootViewToWindow();
+ addTaskbarRootViewToWindow(getDefaultDisplayId());
}
/**
@@ -429,8 +449,9 @@
mActivityOnDestroyCallback.run();
}
mRecentsViewContainer = recentsViewContainer;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setUIController(
+ TaskbarActivityContext taskbar = getCurrentActivityContext();
+ if (taskbar != null) {
+ taskbar.setUIController(
createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer));
}
}
@@ -472,11 +493,21 @@
/**
* This method is called multiple times (ex. initial init, then when user unlocks) in which case
- * we fully want to destroy an existing taskbar and create a new one.
+ * we fully want to destroy the existing default display's taskbar and create a new one.
* In other case (folding/unfolding) we don't need to remove and add window.
*/
@VisibleForTesting
public synchronized void recreateTaskbar() {
+ // TODO: make this recreate all taskbars in map.
+ recreateTaskbarForDisplay(getDefaultDisplayId());
+ }
+
+ /**
+ * This method is called multiple times (ex. initial init, then when user unlocks) in which case
+ * we fully want to destroy an existing taskbar for a specified display and create a new one.
+ * In other case (folding/unfolding) we don't need to remove and add window.
+ */
+ private void recreateTaskbarForDisplay(int displayId) {
Trace.beginSection("recreateTaskbar");
try {
DeviceProfile dp = mUserUnlocked ?
@@ -486,7 +517,7 @@
final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
mAllAppsActionManager.setTaskbarPresent(isLargeScreenTaskbar);
- destroyExistingTaskbar();
+ destroyTaskbarForDisplay(displayId);
boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
@@ -501,29 +532,31 @@
}
}
- if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
- mTaskbarActivityContext = new TaskbarActivityContext(mContext,
- mNavigationBarPanelContext, dp, mNavButtonController,
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (enableTaskbarNoRecreate() || taskbar == null) {
+ taskbar = new TaskbarActivityContext(mContext,
+ mNavigationBarPanelContext, dp, mDefaultNavButtonController,
mUnfoldProgressProvider, mDesktopVisibilityController);
} else {
- mTaskbarActivityContext.updateDeviceProfile(dp);
+ taskbar.updateDeviceProfile(dp);
}
mSharedState.startTaskbarVariantIsTransient =
- DisplayController.isTransientTaskbar(mTaskbarActivityContext);
+ DisplayController.isTransientTaskbar(taskbar);
mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
- mTaskbarActivityContext.init(mSharedState);
+ taskbar.init(mSharedState);
if (mRecentsViewContainer != null) {
- mTaskbarActivityContext.setUIController(
+ taskbar.setUIController(
createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer));
}
if (enableTaskbarNoRecreate()) {
- addTaskbarRootViewToWindow();
- mTaskbarRootLayout.removeAllViews();
- mTaskbarRootLayout.addView(mTaskbarActivityContext.getDragLayer());
- mTaskbarActivityContext.notifyUpdateLayoutParams();
+ addTaskbarRootViewToWindow(displayId);
+ mDefaultRootLayout.removeAllViews();
+ mDefaultRootLayout.addView(taskbar.getDragLayer());
+ taskbar.notifyUpdateLayoutParams();
}
+ addTaskbarToMap(displayId, taskbar);
} finally {
Trace.endSection();
}
@@ -535,14 +568,15 @@
mSharedState.sysuiStateFlags, QuickStepContract::getSystemUiStateString));
}
mSharedState.sysuiStateFlags = systemUiStateFlags;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.updateSysuiStateFlags(systemUiStateFlags, false /* fromInit */);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.updateSysuiStateFlags(systemUiStateFlags, false /* fromInit */);
}
}
public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) {
- if (mNavButtonController != null) {
- mNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
+ if (mDefaultNavButtonController != null) {
+ mDefaultNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
}
}
@@ -551,46 +585,53 @@
*/
public void setSetupUIVisible(boolean isVisible) {
mSharedState.setupUIVisible = isVisible;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setSetupUIVisible(isVisible);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.setSetupUIVisible(isVisible);
}
}
public void setWallpaperVisible(boolean isVisible) {
mSharedState.wallpaperVisible = isVisible;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setWallpaperVisible(isVisible);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.setWallpaperVisible(isVisible);
}
}
public void checkNavBarModes(int displayId) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.checkNavBarModes();
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.checkNavBarModes();
}
}
public void finishBarAnimations(int displayId) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.finishBarAnimations();
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.finishBarAnimations();
}
}
public void touchAutoDim(int displayId, boolean reset) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.touchAutoDim(reset);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.touchAutoDim(reset);
}
}
public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
boolean animate) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.transitionTo(barMode, animate);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.transitionTo(barMode, animate);
}
}
public void appTransitionPending(boolean pending) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.appTransitionPending(pending);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.appTransitionPending(pending);
}
}
@@ -599,8 +640,9 @@
}
public void onRotationProposal(int rotation, boolean isValid) {
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onRotationProposal(rotation, isValid);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.onRotationProposal(rotation, isValid);
}
}
@@ -608,38 +650,43 @@
mSharedState.disableNavBarDisplayId = displayId;
mSharedState.disableNavBarState1 = state1;
mSharedState.disableNavBarState2 = state2;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.disableNavBarElements(displayId, state1, state2, animate);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.disableNavBarElements(displayId, state1, state2, animate);
}
}
public void onSystemBarAttributesChanged(int displayId, int behavior) {
mSharedState.systemBarAttrsDisplayId = displayId;
mSharedState.systemBarAttrsBehavior = behavior;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.onSystemBarAttributesChanged(displayId, behavior);
}
}
public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
mSharedState.barMode = barMode;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onTransitionModeUpdated(barMode, checkBarModes);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.onTransitionModeUpdated(barMode, checkBarModes);
}
}
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
mSharedState.navButtonsDarkIntensity = darkIntensity;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null) {
+ taskbar.onNavButtonsDarkIntensityChanged(darkIntensity);
}
}
public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
mSharedState.mLumaSamplingDisplayId = displayId;
mSharedState.mIsLumaSamplingEnabled = enable;
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.onNavigationBarLumaSamplingEnabled(displayId, enable);
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (taskbar != null) {
+ taskbar.onNavigationBarLumaSamplingEnabled(displayId, enable);
}
}
@@ -666,7 +713,7 @@
debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
removeActivityCallbacksAndListeners();
mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext);
- destroyExistingTaskbar();
+ destroyAllTaskbars();
removeTaskbarRootViewFromWindow();
if (mUserUnlocked) {
DisplayController.INSTANCE.get(mContext).removeChangeListener(mRecreationListener);
@@ -676,38 +723,64 @@
SettingsCache.INSTANCE.get(mContext)
.unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
- mContext.unregisterComponentCallbacks(mComponentCallbacks);
+ mContext.unregisterComponentCallbacks(mDefaultComponentCallbacks);
mShutdownReceiver.unregisterReceiverSafely(mContext);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
- return mTaskbarActivityContext;
+ return getTaskbarForDisplay(mContext.getDisplayId());
}
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarManager:");
- if (mTaskbarActivityContext == null) {
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar == null) {
pw.println(prefix + "\tTaskbarActivityContext: null");
} else {
- mTaskbarActivityContext.dumpLogs(prefix + "\t", pw);
+ taskbar.dumpLogs(prefix + "\t", pw);
}
}
- private void addTaskbarRootViewToWindow() {
- if (enableTaskbarNoRecreate() && !mAddedWindow && mTaskbarActivityContext != null) {
- mWindowManager.addView(mTaskbarRootLayout,
- mTaskbarActivityContext.getWindowLayoutParams());
+ private void addTaskbarRootViewToWindow(int displayId) {
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
+ if (enableTaskbarNoRecreate() && !mAddedWindow && taskbar != null) {
+ mWindowManager.addView(mDefaultRootLayout, taskbar.getWindowLayoutParams());
mAddedWindow = true;
}
}
private void removeTaskbarRootViewFromWindow() {
if (enableTaskbarNoRecreate() && mAddedWindow) {
- mWindowManager.removeViewImmediate(mTaskbarRootLayout);
+ mWindowManager.removeViewImmediate(mDefaultRootLayout);
mAddedWindow = false;
}
}
+ /**
+ * Returns the {@link TaskbarActivityContext} associated with the given display ID.
+ *
+ * @param displayId The ID of the display to retrieve the taskbar for.
+ * @return The {@link TaskbarActivityContext} for the specified display, or
+ * {@code null} if no taskbar is associated with that display.
+ */
+ private TaskbarActivityContext getTaskbarForDisplay(int displayId) {
+ return mTaskbars.get(displayId);
+ }
+
+ private void addTaskbarToMap(int displayId, TaskbarActivityContext newTaskbar) {
+ if (!mTaskbars.contains(displayId)) {
+ mTaskbars.put(displayId, newTaskbar);
+ }
+ }
+
+ private void removeTaskbarFromMap(int displayId) {
+ mTaskbars.delete(displayId);
+ }
+
+ private int getDefaultDisplayId() {
+ return mContext.getDisplayId();
+ }
+
/** Temp logs for b/254119092. */
public void debugWhyTaskbarNotDestroyed(String debugReason) {
StringJoiner log = new StringJoiner("\n");
@@ -749,4 +822,9 @@
private final DeviceProfile.OnDeviceProfileChangeListener mDebugActivityDeviceProfileChanged =
dp -> debugWhyTaskbarNotDestroyed("mActivity onDeviceProfileChanged");
+
+ @VisibleForTesting
+ public Context getWindowContext() {
+ return mContext;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index c20617d..f905c5f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -208,7 +208,7 @@
private void commitHotseatItemUpdates(
ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
- mContainer.updateHotseatItems(hotseatItemInfos, recentTasks);
+ mContainer.updateItems(hotseatItemInfos, recentTasks);
mControllers.taskbarViewController.updateIconViewsRunningStates();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 0f9ede9..4881836 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -16,7 +16,8 @@
package com.android.launcher3.taskbar;
-import static android.view.MotionEvent.ACTION_UP;
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.ACTION_UP;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
@@ -38,6 +39,7 @@
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
+import android.os.SystemClock;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -78,6 +80,7 @@
private long mLastScreenPinLongPress;
private boolean mScreenPinned;
private boolean mAssistantLongPressEnabled;
+ private int mLastSentBackAction = ACTION_UP;
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
@@ -85,6 +88,8 @@
pw.println(prefix + "\tmLastScreenPinLongPress=" + mLastScreenPinLongPress);
pw.println(prefix + "\tmScreenPinned=" + mScreenPinned);
+ pw.println(prefix + "\tmLastSentBackAction="
+ + KeyEvent.actionToString(mLastSentBackAction));
}
@Retention(RetentionPolicy.SOURCE)
@@ -141,6 +146,11 @@
if (buttonType == BUTTON_SPACE) {
return;
}
+ if (predictiveBackThreeButtonNav() && mLastSentBackAction == ACTION_DOWN) {
+ Log.i(TAG, "Button click ignored while back button is pressed");
+ // prevent interactions with other buttons while back button is pressed
+ return;
+ }
// Provide the same haptic feedback that the system offers for virtual keys.
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
switch (buttonType) {
@@ -180,6 +190,13 @@
if (buttonType == BUTTON_SPACE) {
return false;
}
+ if (predictiveBackThreeButtonNav() && mLastSentBackAction == ACTION_DOWN
+ && buttonType != BUTTON_BACK && buttonType != BUTTON_RECENTS) {
+ // prevent interactions with other buttons while back button is pressed (except back
+ // and recents button for screen-unpin action).
+ Log.i(TAG, "Button long click ignored while back button is pressed");
+ return false;
+ }
// Provide the same haptic feedback that the system offers for long press.
// The haptic feedback from long pressing on the home button is handled by circle to search.
@@ -281,6 +298,10 @@
}
private void resetScreenUnpin() {
+ // if only back button was long pressed, navigate back like a single click back behavior.
+ if (mLongPressedButtons == BUTTON_BACK) {
+ executeBack(null);
+ }
mLongPressedButtons = 0;
mLastScreenPinLongPress = 0;
}
@@ -323,13 +344,27 @@
mCallbacks.onToggleOverview();
}
- void executeBack(@Nullable KeyEvent keyEvent) {
+ void sendBackKeyEvent(int action, boolean cancelled) {
+ if (action == mLastSentBackAction) {
+ // There must always be an alternating sequence of ACTION_DOWN and ACTION_UP events
+ return;
+ }
+ long time = SystemClock.uptimeMillis();
+ KeyEvent keyEvent = new KeyEvent(time, time, action, KeyEvent.KEYCODE_BACK, 0);
+ if (cancelled) {
+ keyEvent.cancel();
+ }
+ executeBack(keyEvent);
+ }
+
+ private void executeBack(@Nullable KeyEvent keyEvent) {
if (keyEvent == null || (keyEvent.getAction() == ACTION_UP && !keyEvent.isCanceled())) {
logEvent(LAUNCHER_TASKBAR_BACK_BUTTON_TAP);
mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
GestureType.BACK);
}
mSystemUiProxy.onBackEvent(keyEvent);
+ mLastSentBackAction = keyEvent != null ? keyEvent.getAction() : ACTION_UP;
}
private void onImeSwitcherPress() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
index 126e9bb..8775766 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
@@ -16,20 +16,32 @@
package com.android.launcher3.taskbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
+import androidx.core.graphics.ColorUtils;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
import com.android.launcher3.Reorderable;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.Themes;
import com.android.systemui.shared.recents.model.Task;
@@ -45,8 +57,111 @@
* each other in counter clockwise manner (icons of tasks partially overlapping with each other).
*/
public class TaskbarOverflowView extends FrameLayout implements Reorderable {
+ private static final int ALPHA_TRANSPARENT = 0;
+ private static final int ALPHA_OPAQUE = 255;
+ private static final long ANIMATION_DURATION_APPS_TO_LEAVE_BEHIND = 300L;
+ private static final long ANIMATION_DURATION_LEAVE_BEHIND_TO_APPS = 500L;
+ private static final long ANIMATION_SET_DURATION = 1000L;
+ private static final long ITEM_ICON_CENTER_OFFSET_ANIMATION_DURATION = 500L;
+ private static final long ITEM_ICON_COLOR_FILTER_OPACITY_ANIMATION_DURATION = 600L;
+ private static final long ITEM_ICON_SIZE_ANIMATION_DURATION = 500L;
+ private static final long ITEM_ICON_STROKE_WIDTH_ANIMATION_DURATION = 500L;
+ private static final long LEAVE_BEHIND_ANIMATIONS_DELAY = 500L;
+ private static final long LEAVE_BEHIND_OPACITY_ANIMATION_DURATION = 100L;
+ private static final long LEAVE_BEHIND_SIZE_ANIMATION_DURATION = 500L;
+ private static final float LEAVE_BEHIND_SIZE_SCALE_DOWN_MULTIPLIER = 0.83f;
private static final int MAX_ITEMS_IN_PREVIEW = 4;
+ // The height divided by the width of the horizontal box containing two overlapping app icons.
+ // According to the spec, this ratio is constant for different sizes of taskbar app icons.
+ // Assuming the width of this box = taskbar app icon size - 2 paddings - 2 stroke widths, and
+ // the height = width * 0.61, which is also equal to the height of a single item in the preview.
+ private static final float TWO_ITEM_ICONS_BOX_ASPECT_RATIO = 0.61f;
+
+ private static final FloatProperty<TaskbarOverflowView> ITEM_ICON_CENTER_OFFSET =
+ new FloatProperty<>("itemIconCenterOffset") {
+ @Override
+ public Float get(TaskbarOverflowView view) {
+ return view.mItemIconCenterOffset;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, float value) {
+ view.mItemIconCenterOffset = value;
+ view.invalidate();
+ }
+ };
+
+ private static final IntProperty<TaskbarOverflowView> ITEM_ICON_COLOR_FILTER_OPACITY =
+ new IntProperty<>("itemIconColorFilterOpacity") {
+ @Override
+ public Integer get(TaskbarOverflowView view) {
+ return view.mItemIconColorFilterOpacity;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, int value) {
+ view.mItemIconColorFilterOpacity = value;
+ view.invalidate();
+ }
+ };
+
+ private static final FloatProperty<TaskbarOverflowView> ITEM_ICON_SIZE =
+ new FloatProperty<>("itemIconSize") {
+ @Override
+ public Float get(TaskbarOverflowView view) {
+ return view.mItemIconSize;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, float value) {
+ view.mItemIconSize = value;
+ view.invalidate();
+ }
+ };
+
+ private static final FloatProperty<TaskbarOverflowView> ITEM_ICON_STROKE_WIDTH =
+ new FloatProperty<>("itemIconStrokeWidth") {
+ @Override
+ public Float get(TaskbarOverflowView view) {
+ return view.mItemIconStrokeWidth;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, float value) {
+ view.mItemIconStrokeWidth = value;
+ view.invalidate();
+ }
+ };
+
+ private static final IntProperty<TaskbarOverflowView> LEAVE_BEHIND_OPACITY =
+ new IntProperty<>("leaveBehindOpacity") {
+ @Override
+ public Integer get(TaskbarOverflowView view) {
+ return view.mLeaveBehindOpacity;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, int value) {
+ view.mLeaveBehindOpacity = value;
+ view.invalidate();
+ }
+ };
+
+ private static final FloatProperty<TaskbarOverflowView> LEAVE_BEHIND_SIZE =
+ new FloatProperty<>("leaveBehindSize") {
+ @Override
+ public Float get(TaskbarOverflowView view) {
+ return view.mLeaveBehindSize;
+ }
+
+ @Override
+ public void setValue(TaskbarOverflowView view, float value) {
+ view.mLeaveBehindSize = value;
+ view.invalidate();
+ }
+ };
+
private boolean mIsRtlLayout;
private final List<Task> mItems = new ArrayList<Task>();
private int mIconSize;
@@ -56,11 +171,24 @@
private float mScaleForReorderBounce = 1f;
private int mItemBackgroundColor;
private int mLeaveBehindColor;
- private float mItemPreviewStrokeWidth;
// Active means the overflow icon has been pressed, which replaces the app icons with the
// leave-behind circle and shows the KQS UI.
private boolean mIsActive = false;
+ private ValueAnimator mStateTransitionAnimationWrapper;
+
+ private float mItemIconCenterOffsetDefault;
+ private float mItemIconCenterOffset; // [0..mItemIconCenterOffsetDefault]
+ private int mItemIconColorFilterOpacity; // [ALPHA_TRANSPARENT..ALPHA_OPAQUE]
+ private float mItemIconSizeDefault;
+ private float mItemIconSizeScaledDown;
+ private float mItemIconSize; // [mItemIconSizeScaledDown..mItemIconSizeDefault]
+ private float mItemIconStrokeWidthDefault;
+ private float mItemIconStrokeWidth; // [0..mItemIconStrokeWidthDefault]
+ private int mLeaveBehindOpacity; // [ALPHA_TRANSPARENT..ALPHA_OPAQUE]
+ private float mLeaveBehindSizeScaledDown;
+ private float mLeaveBehindSizeDefault;
+ private float mLeaveBehindSize; // [mLeaveBehindSizeScaledDown..mLeaveBehindSizeDefault]
public TaskbarOverflowView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -87,6 +215,27 @@
icon.mIconSize = iconSize;
icon.mPadding = padding;
+
+ final float taskbarIconRadius =
+ iconSize * IconNormalizer.ICON_VISIBLE_AREA_FACTOR / 2f - padding;
+
+ icon.mLeaveBehindSizeDefault = taskbarIconRadius; // 1/2 of taskbar app icon size
+ icon.mLeaveBehindSizeScaledDown =
+ icon.mLeaveBehindSizeDefault * LEAVE_BEHIND_SIZE_SCALE_DOWN_MULTIPLIER;
+ icon.mLeaveBehindSize = icon.mLeaveBehindSizeScaledDown;
+
+ icon.mItemIconStrokeWidthDefault = taskbarIconRadius / 5f; // 1/10 of taskbar app icon size
+ icon.mItemIconStrokeWidth = icon.mItemIconStrokeWidthDefault;
+
+ icon.mItemIconSizeDefault = 2 * (taskbarIconRadius - icon.mItemIconStrokeWidthDefault)
+ * TWO_ITEM_ICONS_BOX_ASPECT_RATIO;
+ icon.mItemIconSizeScaledDown = icon.mLeaveBehindSizeScaledDown;
+ icon.mItemIconSize = icon.mItemIconSizeDefault;
+
+ icon.mItemIconCenterOffsetDefault = taskbarIconRadius - icon.mItemIconSizeDefault / 2f
+ - icon.mItemIconStrokeWidthDefault;
+ icon.mItemIconCenterOffset = icon.mItemIconCenterOffsetDefault;
+
return icon;
}
@@ -95,8 +244,6 @@
mItemBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mItemBackgroundColor = getContext().getColor(R.color.taskbar_background);
mLeaveBehindColor = Themes.getAttrColor(getContext(), android.R.attr.textColorTertiary);
- mItemPreviewStrokeWidth = getResources().getDimension(
- R.dimen.taskbar_overflow_button_preview_stroke);
setWillNotDraw(false);
}
@@ -105,16 +252,14 @@
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
- if (mIsActive) {
- drawLeaveBehindCircle(canvas);
- } else {
- drawAppIcons(canvas);
- }
+ drawAppIcons(canvas);
+ drawLeaveBehindCircle(canvas);
}
private void drawAppIcons(@NonNull Canvas canvas) {
mItemBackgroundPaint.setColor(mItemBackgroundColor);
float radius = mIconSize / 2f - mPadding;
+ int adjustedItemIconSize = Math.round(mItemIconSize);
int itemsToShow = Math.min(mItems.size(), MAX_ITEMS_IN_PREVIEW);
for (int i = itemsToShow - 1; i >= 0; --i) {
@@ -123,36 +268,33 @@
continue;
}
- // Set the item icon size so two items fit within the overflow icon with stroke width
- // included, and overlap of 4 stroke width sizes between base item preview items.
- // 2 * strokeWidth + 2 * itemIconSize - 4 * strokeWidth = iconSize = 2 * radius.
- float itemIconSize = radius + mItemPreviewStrokeWidth;
- // Offset item icon from center so item icon stroke edge matches the parent icon edge.
- float itemCenterOffset = radius - itemIconSize / 2 - mItemPreviewStrokeWidth;
-
- float itemCenterX = getItemXOffset(itemCenterOffset, mIsRtlLayout, i, itemsToShow);
- float itemCenterY = getItemYOffset(itemCenterOffset, i, itemsToShow);
+ float itemCenterX = getItemXOffset(mItemIconCenterOffset, mIsRtlLayout, i, itemsToShow);
+ float itemCenterY = getItemYOffset(mItemIconCenterOffset, i, itemsToShow);
Drawable iconCopy = icon.getConstantState().newDrawable().mutate();
- iconCopy.setBounds(0, 0, (int) itemIconSize, (int) itemIconSize);
+ iconCopy.setBounds(0, 0, adjustedItemIconSize, adjustedItemIconSize);
+ iconCopy.setColorFilter(new BlendModeColorFilter(
+ ColorUtils.setAlphaComponent(mLeaveBehindColor, mItemIconColorFilterOpacity),
+ BlendMode.SRC_ATOP));
canvas.save();
- float itemIconRadius = itemIconSize / 2;
+ float itemIconRadius = adjustedItemIconSize / 2f;
canvas.translate(
mPadding + itemCenterX + radius - itemIconRadius,
mPadding + itemCenterY + radius - itemIconRadius);
canvas.drawCircle(itemIconRadius, itemIconRadius,
- itemIconRadius + mItemPreviewStrokeWidth, mItemBackgroundPaint);
+ itemIconRadius + mItemIconStrokeWidth, mItemBackgroundPaint);
iconCopy.draw(canvas);
canvas.restore();
}
}
private void drawLeaveBehindCircle(@NonNull Canvas canvas) {
- mItemBackgroundPaint.setColor(mLeaveBehindColor);
+ mItemBackgroundPaint.setColor(
+ ColorUtils.setAlphaComponent(mLeaveBehindColor, mLeaveBehindOpacity));
- final var xyCenter = mIconSize / 2f;
- canvas.drawCircle(xyCenter, xyCenter, mIconSize / 4f, mItemBackgroundPaint);
+ final float xyCenter = mIconSize / 2f;
+ canvas.drawCircle(xyCenter, xyCenter, mLeaveBehindSize / 2f, mItemBackgroundPaint);
}
/**
@@ -203,10 +345,98 @@
* @param isActive The next state of the view.
*/
public void setIsActive(boolean isActive) {
- if (mIsActive != isActive) {
- mIsActive = isActive;
- invalidate();
+ if (mIsActive == isActive) {
+ return;
}
+ mIsActive = isActive;
+
+ if (mStateTransitionAnimationWrapper != null
+ && mStateTransitionAnimationWrapper.isRunning()) {
+ mStateTransitionAnimationWrapper.reverse();
+ return;
+ }
+
+ final AnimatorSet stateTransitionAnimation = getStateTransitionAnimation();
+ mStateTransitionAnimationWrapper = ValueAnimator.ofFloat(0, 1f);
+ mStateTransitionAnimationWrapper.setDuration(mIsActive
+ ? ANIMATION_DURATION_APPS_TO_LEAVE_BEHIND
+ : ANIMATION_DURATION_LEAVE_BEHIND_TO_APPS);
+ mStateTransitionAnimationWrapper.setInterpolator(
+ mIsActive ? Interpolators.STANDARD : Interpolators.EMPHASIZED);
+ mStateTransitionAnimationWrapper.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStateTransitionAnimationWrapper = null;
+ }
+ });
+ mStateTransitionAnimationWrapper.addUpdateListener(
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ stateTransitionAnimation.setCurrentPlayTime(
+ (long) (ANIMATION_SET_DURATION * animator.getAnimatedFraction()));
+ }
+ });
+ mStateTransitionAnimationWrapper.start();
+ }
+
+ private AnimatorSet getStateTransitionAnimation() {
+ final AnimatorSet animation = new AnimatorSet();
+ animation.setInterpolator(Interpolators.LINEAR);
+ animation.playTogether(
+ buildAnimator(ITEM_ICON_CENTER_OFFSET, 0f, mItemIconCenterOffsetDefault,
+ ITEM_ICON_CENTER_OFFSET_ANIMATION_DURATION, 0L,
+ ITEM_ICON_CENTER_OFFSET_ANIMATION_DURATION),
+ buildAnimator(ITEM_ICON_COLOR_FILTER_OPACITY, ALPHA_OPAQUE, ALPHA_TRANSPARENT,
+ ITEM_ICON_COLOR_FILTER_OPACITY_ANIMATION_DURATION, 0L,
+ ANIMATION_SET_DURATION - ITEM_ICON_COLOR_FILTER_OPACITY_ANIMATION_DURATION),
+ buildAnimator(ITEM_ICON_SIZE, mItemIconSizeScaledDown, mItemIconSizeDefault,
+ ITEM_ICON_SIZE_ANIMATION_DURATION, 0L,
+ ITEM_ICON_SIZE_ANIMATION_DURATION),
+ buildAnimator(ITEM_ICON_STROKE_WIDTH, 0f, mItemIconStrokeWidthDefault,
+ ITEM_ICON_STROKE_WIDTH_ANIMATION_DURATION, 0L,
+ ITEM_ICON_STROKE_WIDTH_ANIMATION_DURATION),
+ buildAnimator(LEAVE_BEHIND_OPACITY, ALPHA_OPAQUE, ALPHA_TRANSPARENT,
+ LEAVE_BEHIND_OPACITY_ANIMATION_DURATION, LEAVE_BEHIND_ANIMATIONS_DELAY,
+ ANIMATION_SET_DURATION - LEAVE_BEHIND_ANIMATIONS_DELAY
+ - LEAVE_BEHIND_OPACITY_ANIMATION_DURATION),
+ buildAnimator(LEAVE_BEHIND_SIZE, mLeaveBehindSizeDefault,
+ mLeaveBehindSizeScaledDown, LEAVE_BEHIND_SIZE_ANIMATION_DURATION,
+ LEAVE_BEHIND_ANIMATIONS_DELAY, 0L)
+ );
+ return animation;
+ }
+
+ private ObjectAnimator buildAnimator(IntProperty<TaskbarOverflowView> property,
+ int finalValueWhenAnimatingToLeaveBehind, int finalValueWhenAnimatingToAppIcons,
+ long duration, long delayWhenAnimatingToLeaveBehind,
+ long delayWhenAnimatingToAppIcons) {
+ final ObjectAnimator animator = ObjectAnimator.ofInt(this, property,
+ mIsActive ? finalValueWhenAnimatingToLeaveBehind
+ : finalValueWhenAnimatingToAppIcons);
+ applyTiming(animator, duration, delayWhenAnimatingToLeaveBehind,
+ delayWhenAnimatingToAppIcons);
+ return animator;
+ }
+
+ private ObjectAnimator buildAnimator(FloatProperty<TaskbarOverflowView> property,
+ float finalValueWhenAnimatingToLeaveBehind, float finalValueWhenAnimatingToAppIcons,
+ long duration, long delayWhenAnimatingToLeaveBehind,
+ long delayWhenAnimatingToAppIcons) {
+ final ObjectAnimator animator = ObjectAnimator.ofFloat(this, property,
+ mIsActive ? finalValueWhenAnimatingToLeaveBehind
+ : finalValueWhenAnimatingToAppIcons);
+ applyTiming(animator, duration, delayWhenAnimatingToLeaveBehind,
+ delayWhenAnimatingToAppIcons);
+ return animator;
+ }
+
+ private void applyTiming(ObjectAnimator animator, long duration,
+ long delayWhenAnimatingToLeaveBehind,
+ long delayWhenAnimatingToAppIcons) {
+ animator.setDuration(duration);
+ animator.setStartDelay(
+ mIsActive ? delayWhenAnimatingToLeaveBehind : delayWhenAnimatingToAppIcons);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 70d4bb1..2e0bae5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -201,8 +201,10 @@
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
shortcuts.add(BUBBLE);
}
+
if (Flags.enableMultiInstanceMenuTaskbar()
- && DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ && DesktopModeStatus.canEnterDesktopMode(mContext)
+ && !mControllers.taskbarStashController.isInOverview()) {
shortcuts.addAll(getMultiInstanceMenuOptions().toList());
}
return shortcuts.stream();
@@ -295,9 +297,9 @@
* Returns a stream of Multi Instance menu options if an app supports it.
*/
Stream<SystemShortcut.Factory<BaseTaskbarContext>> getMultiInstanceMenuOptions() {
- SystemShortcut.Factory<BaseTaskbarContext> factory = createNewWindowShortcutFactory();
- return factory != null ? Stream.of(factory) : Stream.empty();
-
+ SystemShortcut.Factory<BaseTaskbarContext> f1 = createNewWindowShortcutFactory();
+ SystemShortcut.Factory<BaseTaskbarContext> f2 = createManageWindowsShortcutFactory();
+ return f1 != null ? Stream.of(f1, f2) : Stream.empty();
}
/**
@@ -317,6 +319,23 @@
}
/**
+ * Creates a factory function representing a "Manage Windows" menu item only if the calling app
+ * supports multi-instance. This menu item shows the open instances of the calling app.
+ * @return A factory function to be used in populating the long-press menu.
+ */
+ public SystemShortcut.Factory<BaseTaskbarContext> createManageWindowsShortcutFactory() {
+ return (context, itemInfo, originalView) -> {
+ ComponentKey key = itemInfo.getComponentKey();
+ AppInfo app = getApp(key);
+ if (app != null && app.supportsMultiInstance()) {
+ return new ManageWindowsTaskbarShortcut<>(context, itemInfo, originalView,
+ mControllers);
+ }
+ return null;
+ };
+ }
+
+ /**
* A single menu item ("Split left," "Split right," or "Split top") that executes a split
* from the taskbar, as if the user performed a drag and drop split.
* Includes an onClick method that initiates the actual split.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c1dd216..67be8da 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -23,6 +23,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.internal.jank.InteractionJankMonitor.Configuration;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
+import static com.android.launcher3.QuickstepTransitionManager.PINNED_TASKBAR_TRANSITION_DURATION;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
@@ -398,6 +399,9 @@
* Returns how long the stash/unstash animation should play.
*/
public long getStashDuration() {
+ if (DisplayController.isPinnedTaskbar(mActivity)) {
+ return PINNED_TASKBAR_TRANSITION_DURATION;
+ }
return DisplayController.isTransientTaskbar(mActivity)
? TRANSIENT_TASKBAR_STASH_DURATION
: TASKBAR_STASH_DURATION;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index f7f5cf6..8b636dd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -195,6 +195,16 @@
return true;
}
+ public boolean isAnimatingToHotseat() {
+ return false;
+ }
+
+ /**
+ * Skips to the end of the animation to Hotseat - should only be used if
+ * {@link #isAnimatingToHotseat()} returns true.
+ */
+ public void endAnimationToHotseat() {}
+
/** Returns {@code true} if Taskbar is currently within overview. */
protected boolean isInOverviewUi() {
return false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 55bcb23..b609511 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -20,11 +20,14 @@
import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Flags.enableRecentsInTaskbar;
+import static com.android.launcher3.Flags.taskbarRecentsLayoutTransition;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
+import static java.util.function.Predicate.not;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -70,7 +73,9 @@
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -108,6 +113,8 @@
// Only non-null when device supports having a Taskbar Overflow button.
@Nullable private TaskbarOverflowView mTaskbarOverflowView;
+ private int mNextViewIndex;
+
/**
* Whether the divider is between Hotseat icons and Recents,
* instead of between All Apps button and Hotseat.
@@ -120,10 +127,13 @@
private boolean mShouldTryStartAlign;
- private final int mMaxNumIcons;
+ private int mMaxNumIcons = 0;
+ private int mIdealNumIcons = 0;
private final int mAllAppsButtonTranslationOffset;
+ private final int mNumStaticViews;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -189,7 +199,7 @@
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
- mMaxNumIcons = calculateMaxNumIcons();
+ mNumStaticViews = taskbarRecentsLayoutTransition() ? addStaticViews() : 0;
}
/**
@@ -200,11 +210,15 @@
int availableWidth = deviceProfile.widthPx;
int defaultEdgeMargin =
(int) getResources().getDimension(deviceProfile.inv.inlineNavButtonsEndSpacing);
+ int spaceForBubbleBar =
+ Math.round(mControllerCallbacks.getBubbleBarMaxCollapsedWidthIfVisible());
// Reserve space required for edge margins, or for navbar if shown. If task bar needs to be
// center aligned with nav bar shown, reserve space on both sides.
- availableWidth -= Math.max(defaultEdgeMargin, deviceProfile.hotseatBarEndOffset);
- availableWidth -= Math.max(defaultEdgeMargin,
+ availableWidth -=
+ Math.max(defaultEdgeMargin + spaceForBubbleBar, deviceProfile.hotseatBarEndOffset);
+ availableWidth -= Math.max(
+ defaultEdgeMargin + (mShouldTryStartAlign ? 0 : spaceForBubbleBar),
mShouldTryStartAlign ? 0 : deviceProfile.hotseatBarEndOffset);
// The space taken by an item icon used during layout.
@@ -231,6 +245,39 @@
return Math.floorDiv(availableWidth, iconSize) + additionalIcons;
}
+ /**
+ * Recalculates the max number of icons the taskbar view can show without entering overflow.
+ * Returns whether the max number of icons changed and the change affects the number of icons
+ * that should be shown in the taskbar.
+ */
+ boolean updateMaxNumIcons() {
+ if (!Flags.taskbarOverflow()) {
+ return false;
+ }
+ int oldMaxNumIcons = mMaxNumIcons;
+ mMaxNumIcons = calculateMaxNumIcons();
+ return oldMaxNumIcons != mMaxNumIcons
+ && (mIdealNumIcons > oldMaxNumIcons || mIdealNumIcons > mMaxNumIcons);
+ }
+
+ /**
+ * Pre-adds views that are always children of this view for LayoutTransition support.
+ * <p>
+ * Normally these views are removed and re-added when updating hotseat and recents. This
+ * approach does not behave well with LayoutTransition, so we instead need to add them
+ * initially and avoid removing them during updates.
+ */
+ private int addStaticViews() {
+ int numStaticViews = 1;
+ addView(mAllAppsButtonContainer);
+ if (mActivityContext.getDeviceProfile().isQsbInline) {
+ addView(mQsb, mIsRtl ? 1 : 0);
+ mQsb.setVisibility(View.INVISIBLE);
+ numStaticViews++;
+ }
+ return numStaticViews;
+ }
+
@Override
public void setVisibility(int visibility) {
boolean changed = getVisibility() != visibility;
@@ -328,6 +375,10 @@
&& mActivityContext.getTaskbarFeatureEvaluator().getSupportsPinningPopup()) {
setOnTouchListener(mControllerCallbacks.getTaskbarTouchListener());
}
+
+ if (Flags.taskbarOverflow()) {
+ mMaxNumIcons = calculateMaxNumIcons();
+ }
}
private void removeAndRecycle(View view) {
@@ -340,12 +391,26 @@
view.setTag(null);
}
- /**
- * Inflates/binds the Hotseat views to show in the Taskbar given their ItemInfos.
- */
- protected void updateHotseatItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
- int nextViewIndex = 0;
- int numViewsAnimated = 0;
+ /** Inflates/binds the hotseat items and recent tasks to the view. */
+ protected void updateItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
+ // Filter out unsupported items.
+ hotseatItemInfos = Arrays.stream(hotseatItemInfos)
+ .filter(Objects::nonNull)
+ .toArray(ItemInfo[]::new);
+ // TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
+ recentTasks = recentTasks.stream().filter(not(GroupTask::supportsMultipleTasks)).toList();
+
+ if (taskbarRecentsLayoutTransition()) {
+ updateItemsWithLayoutTransition(hotseatItemInfos, recentTasks);
+ } else {
+ updateItemsWithoutLayoutTransition(hotseatItemInfos, recentTasks);
+ }
+ }
+
+ private void updateItemsWithoutLayoutTransition(
+ ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
+
+ mNextViewIndex = 0;
mAddedDividerForRecents = false;
removeView(mAllAppsButtonContainer);
@@ -358,12 +423,101 @@
}
removeView(mQsb);
- // Add Hotseat icons.
- for (ItemInfo hotseatItemInfo : hotseatItemInfos) {
- if (hotseatItemInfo == null) {
- continue;
- }
+ updateHotseatItems(hotseatItemInfos);
+ if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
+ addView(mTaskbarDividerContainer, mNextViewIndex++);
+ mAddedDividerForRecents = true;
+ }
+
+ updateRecents(recentTasks);
+
+ addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
+
+ // If there are no recent tasks, add divider after All Apps (unless it's the only view).
+ if (!mAddedDividerForRecents
+ && mTaskbarDividerContainer != null
+ && getChildCount() > 1) {
+ addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
+ }
+
+ if (mActivityContext.getDeviceProfile().isQsbInline) {
+ addView(mQsb, mIsRtl ? getChildCount() : 0);
+ // Always set QSB to invisible after re-adding.
+ mQsb.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private void updateItemsWithLayoutTransition(
+ ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
+
+ // Skip static views and potential All Apps divider, if they are on the left.
+ mNextViewIndex = mIsRtl ? 0 : mNumStaticViews;
+ if (getChildAt(mNextViewIndex) == mTaskbarDividerContainer) {
+ mNextViewIndex++;
+ }
+
+ // Update left section.
+ if (mIsRtl) {
+ updateRecents(recentTasks.reversed());
+ } else {
+ updateHotseatItems(hotseatItemInfos);
+ }
+
+ // Now at theoretical position for recent apps divider.
+ updateRecentsDivider(!recentTasks.isEmpty());
+ if (getChildAt(mNextViewIndex) == mTaskbarDividerContainer) {
+ mNextViewIndex++;
+ }
+
+ // Update right section.
+ if (mIsRtl) {
+ updateHotseatItems(hotseatItemInfos);
+ } else {
+ updateRecents(recentTasks);
+ }
+
+ // Recents divider takes priority.
+ if (!mAddedDividerForRecents) {
+ updateAllAppsDivider();
+ }
+ }
+
+ private void updateRecentsDivider(boolean hasRecents) {
+ if (hasRecents && !mAddedDividerForRecents) {
+ mAddedDividerForRecents = true;
+
+ // Remove possible All Apps divider.
+ if (getChildAt(mNumStaticViews) == mTaskbarDividerContainer) {
+ mNextViewIndex--; // All Apps divider on the left. Need to account for removing it.
+ }
+ removeView(mTaskbarDividerContainer);
+
+ addView(mTaskbarDividerContainer, mNextViewIndex);
+ } else if (!hasRecents && mAddedDividerForRecents) {
+ mAddedDividerForRecents = false;
+ removeViewAt(mNextViewIndex);
+ }
+ }
+
+ private void updateAllAppsDivider() {
+ final int allAppsDividerIndex =
+ mIsRtl ? getChildCount() - mNumStaticViews : mNumStaticViews;
+ if (getChildAt(allAppsDividerIndex) == mTaskbarDividerContainer
+ && getChildCount() == mNumStaticViews + 1) {
+ // Only static views with divider so remove divider.
+ removeView(mTaskbarDividerContainer);
+ } else if (getChildAt(allAppsDividerIndex) != mTaskbarDividerContainer
+ && getChildCount() >= mNumStaticViews + 1) {
+ // Static views with at least one app icon so add divider.
+ addView(mTaskbarDividerContainer, allAppsDividerIndex);
+ }
+ }
+
+ private void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
+ int numViewsAnimated = 0;
+
+ for (ItemInfo hotseatItemInfo : hotseatItemInfos) {
// Replace any Hotseat views with the appropriate type if it's not already that type.
final int expectedLayoutResId;
boolean isCollection = false;
@@ -379,8 +533,8 @@
}
View hotseatView = null;
- while (nextViewIndex < getChildCount()) {
- hotseatView = getChildAt(nextViewIndex);
+ while (isNextViewInSection(ItemInfo.class)) {
+ hotseatView = getChildAt(mNextViewIndex);
// see if the view can be reused
if ((hotseatView.getSourceLayoutResId() != expectedLayoutResId)
@@ -421,7 +575,7 @@
}
LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
- addView(hotseatView, nextViewIndex, lp);
+ addView(hotseatView, mNextViewIndex, lp);
}
// Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
@@ -437,14 +591,15 @@
if (enableCursorHoverStates()) {
setHoverListenerForIcon(hotseatView);
}
- nextViewIndex++;
+ mNextViewIndex++;
}
- if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
- addView(mTaskbarDividerContainer, nextViewIndex++);
- mAddedDividerForRecents = true;
+ while (isNextViewInSection(ItemInfo.class)) {
+ removeAndRecycle(getChildAt(mNextViewIndex));
}
+ }
+ private void updateRecents(List<GroupTask> recentTasks) {
// At this point, the all apps button has not been added as a child view, but needs to be
// accounted for when comparing current icon count to max number of icons.
int nonTaskIconsToBeAdded = 1;
@@ -452,18 +607,11 @@
boolean supportsOverflow = Flags.taskbarOverflow();
int overflowSize = 0;
if (supportsOverflow) {
- int numberOfSupportedRecents = 0;
- for (GroupTask task : recentTasks) {
- // TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
- if (!task.supportsMultipleTasks()) {
- ++numberOfSupportedRecents;
- }
- }
+ mIdealNumIcons = mNextViewIndex + recentTasks.size() + nonTaskIconsToBeAdded;
+ overflowSize = mIdealNumIcons - mMaxNumIcons;
- overflowSize =
- nextViewIndex + numberOfSupportedRecents + nonTaskIconsToBeAdded - mMaxNumIcons;
if (overflowSize > 0 && mTaskbarOverflowView != null) {
- addView(mTaskbarOverflowView, nextViewIndex++);
+ addView(mTaskbarOverflowView, mNextViewIndex++);
} else if (mTaskbarOverflowView != null) {
mTaskbarOverflowView.clearItems();
}
@@ -472,9 +620,10 @@
List<Task> overflownTasks = null;
// An extra item needs to be added to overflow button to account for the space taken up by
// the overflow button.
- final int itemsToAddToOverflow = overflowSize > 0 ? overflowSize + 1 : 0;
+ final int itemsToAddToOverflow =
+ (overflowSize > 0) ? Math.min(overflowSize + 1, recentTasks.size()) : 0;
if (overflowSize > 0) {
- overflownTasks = new ArrayList<Task>(itemsToAddToOverflow);
+ overflownTasks = new ArrayList<>(itemsToAddToOverflow);
}
// Add Recent/Running icons.
@@ -482,10 +631,6 @@
if (mTaskbarOverflowView != null && overflownTasks != null
&& overflownTasks.size() < itemsToAddToOverflow) {
// TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
- if (task.supportsMultipleTasks()) {
- continue;
- }
-
overflownTasks.add(task.task1);
if (overflownTasks.size() == itemsToAddToOverflow) {
mTaskbarOverflowView.setItems(overflownTasks);
@@ -510,8 +655,8 @@
}
View recentIcon = null;
- while (nextViewIndex < getChildCount()) {
- recentIcon = getChildAt(nextViewIndex);
+ while (isNextViewInSection(GroupTask.class)) {
+ recentIcon = getChildAt(mNextViewIndex);
// see if the view can be reused
if ((recentIcon.getSourceLayoutResId() != expectedLayoutResId)
@@ -525,15 +670,11 @@
}
if (recentIcon == null) {
- if (isCollection) {
- // TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
- continue;
- }
-
+ // TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
recentIcon = inflate(expectedLayoutResId);
LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
recentIcon.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
- addView(recentIcon, nextViewIndex, lp);
+ addView(recentIcon, mNextViewIndex, lp);
}
if (recentIcon instanceof BubbleTextView btv) {
@@ -543,29 +684,17 @@
if (enableCursorHoverStates()) {
setHoverListenerForIcon(recentIcon);
}
- nextViewIndex++;
+ mNextViewIndex++;
}
- // Remove remaining views
- while (nextViewIndex < getChildCount()) {
- removeAndRecycle(getChildAt(nextViewIndex));
+ while (isNextViewInSection(GroupTask.class)) {
+ removeAndRecycle(getChildAt(mNextViewIndex));
}
+ }
- addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
-
- // If there are no recent tasks, add divider after All Apps (unless it's the only view).
- if (!mAddedDividerForRecents
- && mTaskbarDividerContainer != null
- && getChildCount() > 1) {
- addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
- }
-
-
- if (mActivityContext.getDeviceProfile().isQsbInline) {
- addView(mQsb, mIsRtl ? getChildCount() : 0);
- // Always set QSB to invisible after re-adding.
- mQsb.setVisibility(View.INVISIBLE);
- }
+ private boolean isNextViewInSection(Class<?> tagClass) {
+ return mNextViewIndex < getChildCount()
+ && tagClass.isInstance(getChildAt(mNextViewIndex).getTag());
}
/** Binds the GroupTask to the BubbleTextView to be ready to present to the user. */
@@ -825,6 +954,13 @@
}
/**
+ * The max number of icon views the taskbar can have when taskbar overflow is enabled.
+ */
+ int getMaxNumIconViews() {
+ return mMaxNumIcons;
+ }
+
+ /**
* Returns the all apps button in the taskbar.
*/
public TaskbarAllAppsButtonContainer getAllAppsButtonContainer() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 834f92e..f65f307 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -137,6 +137,17 @@
return null;
}
+ /**
+ * Get the max bubble bar collapsed width for the current bubble bar visibility state. Used to
+ * reserve space for the bubble bar when transitioning taskbar view into overflow.
+ */
+ public float getBubbleBarMaxCollapsedWidthIfVisible() {
+ return mControllers.bubbleControllers
+ .filter(c -> !c.bubbleBarViewController.isHiddenForNoBubbles())
+ .map(c -> c.bubbleBarViewController.getCollapsedWidthWithMaxVisibleBubbles())
+ .orElse(0f);
+ }
+
/** Returns true if bubble bar controllers present and enabled in persistent taskbar. */
public boolean isBubbleBarEnabledInPersistentTaskbar() {
return Flags.enableBubbleBarInPersistentTaskBar()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 494c472..bc5f9a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -120,7 +120,7 @@
private final TaskbarView mTaskbarView;
private final MultiValueAlpha mTaskbarIconAlpha;
private final AnimatedFloat mTaskbarIconScaleForStash = new AnimatedFloat(this::updateScale);
- private final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat(
+ public final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat(
this::updateTranslationY);
private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
this::updateTranslationY);
@@ -351,6 +351,11 @@
OneShotPreDrawListener.add(mTaskbarView, listener);
}
+ @VisibleForTesting
+ int getMaxNumIconViews() {
+ return mTaskbarView.getMaxNumIconViews();
+ }
+
public Rect getIconLayoutVisualBounds() {
return mTaskbarView.getIconLayoutVisualBounds();
}
@@ -779,9 +784,16 @@
}
}
- /** Resets the icon alignment controller so that it can be recreated again later. */
- void resetIconAlignmentController() {
+ /**
+ * Resets the icon alignment controller so that it can be recreated again later, and updates
+ * the list of icons shown in the taskbar if the bubble bar visibility changes the taskbar
+ * overflow state.
+ */
+ void adjustTaskbarForBubbleBar() {
mIconAlignControllerLazy = null;
+ if (mTaskbarView.updateMaxNumIcons()) {
+ commitRunningAppsToUI();
+ }
}
/**
@@ -789,6 +801,8 @@
*/
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
PendingAnimation setter = new PendingAnimation(100);
+ // icon alignment not needed for pinned taskbar.
+ if (DisplayController.isPinnedTaskbar(mActivity)) return setter.createPlaybackController();
mOnControllerPreCreateCallback.run();
DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index e0814d3..987937e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -115,7 +115,6 @@
private BubbleBarItem mSelectedBubble;
private TaskbarSharedState mSharedState;
- private ImeVisibilityChecker mImeVisibilityChecker;
private BubbleBarViewController mBubbleBarViewController;
private BubbleStashController mBubbleStashController;
private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController;
@@ -126,6 +125,8 @@
// Cache last sent top coordinate to avoid sending duplicate updates to shell
private int mLastSentBubbleBarTop;
+ private boolean mIsImeVisible = false;
+
/**
* Similar to {@link BubbleBarUpdate} but rather than {@link BubbleInfo}s it uses
* {@link BubbleBarBubble}s so that it can be used to update the views.
@@ -192,10 +193,8 @@
/** Initializes controllers. */
public void init(BubbleControllers bubbleControllers,
BubbleBarLocationListener bubbleBarLocationListener,
- ImeVisibilityChecker imeVisibilityChecker,
TaskbarSharedState sharedState) {
mSharedState = sharedState;
- mImeVisibilityChecker = imeVisibilityChecker;
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
@@ -234,6 +233,10 @@
boolean sysuiLocked = (flags & MASK_SYSUI_LOCKED) != 0;
mBubbleStashController.setSysuiLocked(sysuiLocked);
+ mIsImeVisible = (flags & SYSUI_STATE_IME_SHOWING) != 0;
+ if (mIsImeVisible) {
+ mBubbleBarViewController.onImeVisible();
+ }
}
//
@@ -309,8 +312,7 @@
// enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g.
// the shade is open, or we're locked.
final boolean suppressAnimation =
- update.initialState || mBubbleBarViewController.isHiddenForSysui()
- || mImeVisibilityChecker.isImeVisible();
+ update.initialState || mBubbleBarViewController.isHiddenForSysui() || mIsImeVisible;
if (update.initialState && mSharedState.hasSavedBubbles()) {
// clear restored state
@@ -572,12 +574,6 @@
mBubbleBarViewController.addBubble(bubble, isExpanding, suppressAnimation);
}
- /** Interface for checking whether the IME is visible. */
- public interface ImeVisibilityChecker {
- /** Whether the IME is visible. */
- boolean isImeVisible();
- }
-
/** Listener of {@link BubbleBarLocation} updates. */
public interface BubbleBarLocationListener {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 350f56f..833be61 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -456,7 +456,7 @@
return;
}
mDragging = dragging;
- setElevation(dragging ? mDragElevation : mBubbleElevation);
+ mController.setIsDragging(dragging);
if (!mDragging) {
// Relayout after dragging to ensure that the dragged bubble is positioned correctly
requestLayout();
@@ -1290,10 +1290,14 @@
// If there are more than 2 bubbles, the first 2 should be visible when collapsed,
// excluding the overflow.
return bubbleChildCount >= MAX_VISIBLE_BUBBLES_COLLAPSED
- ? getScaledIconSize() + mIconOverlapAmount + horizontalPadding
+ ? getCollapsedWidthWithMaxVisibleBubbles()
: getScaledIconSize() + horizontalPadding;
}
+ float getCollapsedWidthWithMaxVisibleBubbles() {
+ return getScaledIconSize() + mIconOverlapAmount + 2 * mBubbleBarPadding;
+ }
+
/** Returns the child count excluding the overflow if it's present. */
int getBubbleChildCount() {
return hasOverflow() ? getChildCount() - 1 : getChildCount();
@@ -1571,5 +1575,8 @@
/** Requests the controller to update bubble bar location to the given value */
void updateBubbleBarLocation(BubbleBarLocation location,
@BubbleBarLocation.UpdateSource int source);
+
+ /** Notifies the controller that bubble bar is being dragged */
+ void setIsDragging(boolean dragging);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 2dddb16..fd08078 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -85,6 +85,7 @@
private final BubbleBarView mBarView;
private int mIconSize;
private int mBubbleBarPadding;
+ private final int mDragElevation;
// Initialized in init.
private BubbleStashController mBubbleStashController;
@@ -152,6 +153,8 @@
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
mIconSize = activity.getResources().getDimensionPixelSize(
R.dimen.bubblebar_icon_size);
+ mDragElevation = activity.getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_drag_elevation);
mTaskbarTranslationDelta = getBubbleBarTranslationDeltaForTaskbar(activity);
}
@@ -221,6 +224,11 @@
@BubbleBarLocation.UpdateSource int source) {
mBubbleBarController.updateBubbleBarLocation(location, source);
}
+
+ @Override
+ public void setIsDragging(boolean dragging) {
+ mBubbleBarContainer.setElevation(dragging ? mDragElevation : 0);
+ }
});
mBubbleViewController = new BubbleView.Controller() {
@@ -383,6 +391,13 @@
}
}
+ /** Notifies that the IME became visible. */
+ public void onImeVisible() {
+ if (isAnimatingNewBubble()) {
+ mBubbleBarViewAnimator.interruptForIme();
+ }
+ }
+
//
// The below animators are exposed to BubbleStashController so it can manage the stashing
// animation.
@@ -473,6 +488,13 @@
}
/**
+ * @return the max collapsed width for the bubble bar.
+ */
+ public float getCollapsedWidthWithMaxVisibleBubbles() {
+ return mBarView.getCollapsedWidthWithMaxVisibleBubbles();
+ }
+
+ /**
* @return {@code true} if bubble bar is on the left edge of the screen, {@code false} if on
* the right
*/
@@ -990,10 +1012,9 @@
}
}
- /** Marks as should show education and shows the bubble bar in a collapsed state */
+ /** Marks as should show education. */
public void prepareToShowEducation() {
mShouldShowEducation = true;
- mBubbleStashController.showBubbleBar(false /* expand the bubbles */);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index d993685..cb592e6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -89,7 +89,6 @@
);
bubbleBarController.init(this,
bubbleBarLocationListeners,
- taskbarControllers.navbarButtonsViewController::isImeVisible,
taskbarSharedState);
bubbleStashedHandleViewController.ifPresent(
controller -> controller.init(/* bubbleControllers = */ this));
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index c74fa9b..92fd5e8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -351,14 +351,20 @@
.start();
}
- /** Suppresses or un-suppresses drawing the dot due to an update for this bubble. */
- public void suppressDotForBubbleUpdate(boolean suppress) {
- mDotSuppressedForBubbleUpdate = suppress;
- if (suppress) {
- setDotScale(0);
- } else {
- showDotIfNeeded(/* animate= */ false);
- }
+ /** Suppresses drawing the dot due to an update for this bubble. */
+ public void suppressDotForBubbleUpdate() {
+ mDotSuppressedForBubbleUpdate = true;
+ setDotScale(0);
+ }
+
+ /**
+ * Unsuppresses the dot after the bubble update finished animating.
+ *
+ * @param animate whether or not to animate the dot back in
+ */
+ public void unsuppressDotForBubbleUpdate(boolean animate) {
+ mDotSuppressedForBubbleUpdate = false;
+ showDotIfNeeded(animate);
}
boolean hasUnseenContent() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 6c354f3..447dad1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -473,8 +473,8 @@
ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
.withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
.withEndAction {
- if (animatingBubble?.expand == true) expandBubbleBar()
springBackAnimation.start()
+ if (animatingBubble?.expand == true) expandBubbleBar()
}
.start()
}
@@ -486,7 +486,7 @@
if (flyout != null) {
bubbleBarFlyoutController.setUpAndShowFlyout(
BubbleBarFlyoutMessage(flyout.icon, flyout.title, flyout.message),
- onInit = { bubbleView.suppressDotForBubbleUpdate(true) },
+ onInit = { bubbleView.suppressDotForBubbleUpdate() },
onEnd = {
moveToState(AnimatingBubble.State.IN)
bubbleStashController.updateTaskbarTouchRegion()
@@ -498,11 +498,12 @@
}
private fun cancelFlyout() {
- bubbleBarFlyoutController.cancelFlyout { onFlyoutRemoved() }
+ animatingBubble?.bubbleView?.unsuppressDotForBubbleUpdate(/* animate= */ true)
+ bubbleBarFlyoutController.cancelFlyout { bubbleStashController.updateTaskbarTouchRegion() }
}
private fun onFlyoutRemoved() {
- animatingBubble?.bubbleView?.suppressDotForBubbleUpdate(false)
+ animatingBubble?.bubbleView?.unsuppressDotForBubbleUpdate(/* animate= */ false)
bubbleStashController.updateTaskbarTouchRegion()
}
@@ -531,6 +532,21 @@
)
}
+ /** Interrupts the animation due to the IME becoming visible. */
+ fun interruptForIme() {
+ cancelFlyout()
+ val hideAnimation = animatingBubble?.hideAnimation ?: return
+ scheduler.cancel(hideAnimation)
+ animatingBubble = null
+ bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
+ bubbleBarView.relativePivotY = 1f
+ // stash the bubble bar since the IME is now visible
+ bubbleStashController.onNewBubbleAnimationInterrupted(
+ /* isStashed= */ true,
+ bubbleBarView.translationY,
+ )
+ }
+
fun expandedWhileAnimating() {
val animatingBubble = animatingBubble ?: return
this.animatingBubble = animatingBubble.copy(expand = true)
@@ -573,7 +589,7 @@
val flyout = bubble?.flyoutMessage
if (flyout != null) {
// the flyout is currently expanding and we need to update it with new data
- bubbleView.suppressDotForBubbleUpdate(true)
+ bubbleView.suppressDotForBubbleUpdate()
bubbleBarFlyoutController.updateFlyoutWhileExpanding(flyout)
} else {
// the flyout is expanding but we don't have new flyout data to update it with,
@@ -588,7 +604,7 @@
isExpanding: Boolean,
) {
// unsuppress the current bubble because we are about to hide its flyout
- animatingBubble.bubbleView.suppressDotForBubbleUpdate(false)
+ animatingBubble.bubbleView.unsuppressDotForBubbleUpdate(/* animate= */ false)
this.animatingBubble = animatingBubble.copy(bubbleView = bubbleView, expand = isExpanding)
// we're currently idle, waiting for the hide animation to start. update the flyout
@@ -601,7 +617,7 @@
val bubble = bubbleView.bubble as? BubbleBarBubble
val flyout = bubble?.flyoutMessage
if (flyout != null) {
- bubbleView.suppressDotForBubbleUpdate(true)
+ bubbleView.suppressDotForBubbleUpdate()
bubbleBarFlyoutController.updateFlyoutFullyExpanded(flyout) {
bubbleStashController.updateTaskbarTouchRegion()
}
@@ -616,7 +632,7 @@
isExpanding: Boolean,
) {
// unsuppress the current bubble because we are about to hide its flyout
- animatingBubble.bubbleView.suppressDotForBubbleUpdate(false)
+ animatingBubble.bubbleView.unsuppressDotForBubbleUpdate(/* animate= */ false)
this.animatingBubble = animatingBubble.copy(bubbleView = bubbleView, expand = isExpanding)
// the hide animation already started so it can't be canceled, just post it again
@@ -629,7 +645,7 @@
// the flyout is collapsing. update it with the new flyout
if (flyout != null) {
moveToState(AnimatingBubble.State.ANIMATING_IN)
- bubbleView.suppressDotForBubbleUpdate(true)
+ bubbleView.suppressDotForBubbleUpdate()
bubbleBarFlyoutController.updateFlyoutWhileCollapsing(flyout) {
moveToState(AnimatingBubble.State.IN)
bubbleStashController.updateTaskbarTouchRegion()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 7b20eea..908e97c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -21,6 +21,7 @@
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.animation.ValueAnimator
+import com.android.app.animation.InterpolatorsAndroidX
import com.android.launcher3.R
import com.android.systemui.util.addListener
@@ -35,7 +36,8 @@
) {
private companion object {
- const val ANIMATION_DURATION_MS = 250L
+ const val EXPAND_ANIMATION_DURATION_MS = 400L
+ const val COLLAPSE_ANIMATION_DURATION_MS = 350L
}
private var flyout: BubbleBarFlyoutView? = null
@@ -86,9 +88,10 @@
private fun showFlyout(animationType: AnimationType, endAction: () -> Unit) {
val flyout = this.flyout ?: return
val startValue = getCurrentAnimatedValueIfRunning() ?: 0f
- val duration = (ANIMATION_DURATION_MS * (1f - startValue)).toLong()
+ val duration = (EXPAND_ANIMATION_DURATION_MS * (1f - startValue)).toLong()
animator?.cancel()
val animator = ValueAnimator.ofFloat(startValue, 1f).setDuration(duration)
+ animator.interpolator = InterpolatorsAndroidX.EMPHASIZED
this.animator = animator
when (animationType) {
AnimationType.FADE ->
@@ -111,6 +114,7 @@
fun updateFlyoutFullyExpanded(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
val flyout = flyout ?: return
hideFlyout(AnimationType.FADE) {
+ callbacks.resetTopBoundary()
flyout.updateData(message) { showFlyout(AnimationType.FADE, onEnd) }
}
}
@@ -152,9 +156,10 @@
private fun hideFlyout(animationType: AnimationType, endAction: () -> Unit) {
val flyout = this.flyout ?: return
val startValue = getCurrentAnimatedValueIfRunning() ?: 1f
- val duration = (ANIMATION_DURATION_MS * startValue).toLong()
+ val duration = (COLLAPSE_ANIMATION_DURATION_MS * startValue).toLong()
animator?.cancel()
val animator = ValueAnimator.ofFloat(startValue, 0f).setDuration(duration)
+ animator.interpolator = InterpolatorsAndroidX.EMPHASIZED
this.animator = animator
when (animationType) {
AnimationType.FADE ->
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 418675c..f9f5a15 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -35,6 +35,7 @@
import androidx.core.animation.ArgbEvaluator
import com.android.launcher3.R
import com.android.launcher3.popup.RoundedArrowDrawable
+import kotlin.math.min
/** The flyout view used to notify the user of a new bubble notification. */
class BubbleBarFlyoutView(
@@ -46,6 +47,8 @@
private companion object {
// the minimum progress of the expansion animation before the content starts fading in.
const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f
+ // the rate multiple for the background color animation relative to the morph animation.
+ const val BACKGROUND_COLOR_CHANGE_RATE = 5
}
private val scheduler: FlyoutScheduler = scheduler ?: HandlerScheduler(this)
@@ -204,6 +207,8 @@
minExpansionProgressForTriangle =
positioner.distanceToRevealTriangle / translationToCollapsedPosition.y
+ backgroundPaint.color = collapsedColor
+
// post the request to start the expand animation to the looper so the view can measure
// itself
scheduler.runAfterLayout(expandAnimation)
@@ -307,8 +312,16 @@
height.toFloat() - triangleHeight + triangleOverlap,
)
+ // transform the flyout color between the collapsed and expanded states. the color
+ // transformation completes at a faster rate (BACKGROUND_COLOR_CHANGE_RATE) than the
+ // expansion animation. this helps make the color change smooth.
backgroundPaint.color =
- ArgbEvaluator.getInstance().evaluate(expansionProgress, collapsedColor, backgroundColor)
+ ArgbEvaluator.getInstance()
+ .evaluate(
+ min(expansionProgress * BACKGROUND_COLOR_CHANGE_RATE, 1f),
+ collapsedColor,
+ backgroundColor,
+ )
canvas.save()
canvas.translate(backgroundRectTx, backgroundRectTy)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 6632721..45f5568 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -54,7 +54,9 @@
if (field == state) return
val transitionFromHome = field == BubbleLauncherState.HOME
field = state
- if (!bubbleBarViewController.hasBubbles()) {
+ val hasBubbles = bubbleBarViewController.hasBubbles()
+ bubbleBarViewController.onBubbleBarConfigurationChanged(hasBubbles)
+ if (!hasBubbles) {
// if there are no bubbles, there's nothing to show, so just return.
return
}
@@ -65,7 +67,6 @@
// on home but in persistent taskbar elsewhere so the position is different.
animateBubbleBarY()
}
- bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
}
override var isSysuiLocked: Boolean = false
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 71303f8..22d504f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -87,8 +87,13 @@
set(state) {
if (field == state) return
field = state
- if (!bubbleBarViewController.hasBubbles()) {
- // if there are no bubbles, there's nothing to show, so just return.
+ val hasBubbles = bubbleBarViewController.hasBubbles()
+ bubbleBarViewController.onBubbleBarConfigurationChanged(hasBubbles)
+ if (!hasBubbles) {
+ // if there are no bubbles, there's no need to update the bubble bar, just keep the
+ // isStashed state up to date so that we can process state changes when bubbles are
+ // created.
+ isStashed = launcherState == BubbleLauncherState.IN_APP
return
}
if (field == BubbleLauncherState.HOME) {
@@ -103,7 +108,6 @@
// Only stash if we're in an app, otherwise we're in home or overview where we should
// be un-stashed
updateStashedAndExpandedState(field == BubbleLauncherState.IN_APP, expand = false)
- bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
}
override var isSysuiLocked: Boolean = false
@@ -485,10 +489,9 @@
val isStashed = stash && !isBubblesShowingOnHome && !isBubblesShowingOnOverview
if (this.isStashed != isStashed) {
this.isStashed = isStashed
+
// notify the view controller that the stash state is about to change so that it can
// cancel an ongoing animation if there is one.
- // note that this has to be called before updating mIsStashed with the new value,
- // otherwise interrupting an ongoing animation may update it again with the wrong state
bubbleBarViewController.onStashStateChanging()
animator?.cancel()
animator =
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index c5f8aa0..7e3b362 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -21,7 +21,6 @@
import android.content.res.ColorStateList
import android.graphics.Color.TRANSPARENT
import android.util.AttributeSet
-import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
@@ -57,7 +56,7 @@
}
init {
- LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, null, false)
+ contentDescription = context.getString(R.string.all_apps_button_label)
setUpIcon()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index 1fb835a..344f163 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -21,7 +21,6 @@
import android.content.res.ColorStateList
import android.graphics.Color.TRANSPARENT
import android.util.AttributeSet
-import android.view.LayoutInflater
import androidx.core.view.setPadding
import com.android.launcher3.R
import com.android.launcher3.Utilities.dpToPx
@@ -33,11 +32,8 @@
/** Taskbar divider view container for customizable taskbar. */
class TaskbarDividerContainer
@JvmOverloads
-constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
-) : IconButtonView(context, attrs), TaskbarContainer {
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+ IconButtonView(context, attrs), TaskbarContainer {
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
override val spaceNeeded: Int
@@ -46,7 +42,7 @@
}
init {
- LayoutInflater.from(context).inflate(R.layout.taskbar_divider, null, false)
+ contentDescription = context.getString(R.string.taskbar_divider_a11y_title)
setUpIcon()
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 4590efe..535ae1c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -418,7 +418,9 @@
mIconRingPaint.setColor(RING_SHADOW_COLOR);
mIconRingPaint.setMaskFilter(mShadowFilter);
int count = canvas.save();
- canvas.scale(mRingScale, mRingScale, canvas.getWidth() / 2f, canvas.getHeight() / 2f);
+ if (Float.compare(1, mRingScale) != 0) {
+ canvas.scale(mRingScale, mRingScale, canvas.getWidth() / 2f, canvas.getHeight() / 2f);
+ }
canvas.drawPath(mRingPath, mIconRingPaint);
mIconRingPaint.setColor(mPlateColor);
mIconRingPaint.setMaskFilter(null);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 34d9a68..1baba74 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -304,7 +304,7 @@
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
mDepthController = new DepthController(this);
- if (DesktopModeStatus.canEnterDesktopMode(this)) {
+ if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(this)) {
mSplitSelectStateController.initSplitFromDesktopController(this,
overviewComponentObserver);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 3a39cf2..8ad00bf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -95,6 +95,7 @@
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
StateAnimationConfig config) {
RecentsView overview = mContainer.getOverviewPanel();
+ boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContainer);
if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) {
overview.switchToScreenshot(() ->
overview.finishRecentsAnimation(true /* toRecents */, null));
@@ -109,7 +110,8 @@
// We sync the scrim fade with the taskbar animation duration to avoid any flickers for
// taskbar icons disappearing before hotseat icons show up.
float scrimUpperBoundFromSplit =
- QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
+ QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
+ / (float) config.duration;
scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f);
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
config.setInterpolator(ANIM_SCRIM_FADE,
@@ -139,7 +141,8 @@
// Sync scroll so that it ends before or at the same time as the taskbar animation.
if (mContainer.getDeviceProfile().isTaskbarPresent) {
config.duration = Math.min(
- config.duration, QuickstepTransitionManager.getTaskbarToHomeDuration());
+ config.duration,
+ QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar));
}
overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 97d7179..5648dad 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -56,9 +56,11 @@
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.TaskViewUtils.extractTargetsAndStates;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -77,6 +79,7 @@
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -90,6 +93,7 @@
import android.widget.Toast;
import android.window.DesktopModeFlags;
import android.window.PictureInPictureSurfaceTransaction;
+import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -100,6 +104,7 @@
import com.android.internal.util.LatencyTracker;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -142,6 +147,7 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.TransitionAnimator;
import com.android.systemui.contextualeducation.GestureType;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -151,10 +157,13 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;
+import kotlin.Unit;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -164,8 +173,6 @@
import java.util.OptionalInt;
import java.util.function.Consumer;
-import kotlin.Unit;
-
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
@@ -346,6 +353,9 @@
// Indicates whether the divider is shown, only used when split screen is activated.
private boolean mIsDividerShown = true;
private boolean mStartMovingTasks;
+ // Whether the animation to home should be handed off to another handler once the gesture is
+ // committed.
+ protected boolean mHandOffAnimationToHome = false;
@Nullable
private RemoteAnimationTargets.ReleaseCheck mSwipePipToHomeReleaseCheck = null;
@@ -667,7 +677,7 @@
TopTaskTracker.CachedTaskInfo cachedTaskInfo = mGestureState.getRunningTask();
if (mIsSwipeForSplit) {
int[] splitTaskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
- runningTasks = cachedTaskInfo.getPlaceholderTasks(splitTaskIds);
+ runningTasks = cachedTaskInfo.getSplitPlaceholderTasks(splitTaskIds);
} else {
runningTasks = cachedTaskInfo.getPlaceholderTasks();
}
@@ -944,6 +954,10 @@
mSwipePipToHomeReleaseCheck = new RemoteAnimationTargets.ReleaseCheck();
mSwipePipToHomeReleaseCheck.setCanRelease(true);
mRecentsAnimationTargets.addReleaseCheck(mSwipePipToHomeReleaseCheck);
+ if (TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()) {
+ mHandOffAnimationToHome =
+ targets.extras.getBoolean(KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION, false);
+ }
// Only initialize the device profile, if it has not been initialized before, as in some
// configurations targets.homeContentInsets may not be correct.
@@ -1373,8 +1387,9 @@
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
+ boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContext);
duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent
- ? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
+ ? QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
: StaggeredWorkspaceAnim.DURATION_MS;
ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
mGestureState.isTrackpadGesture(), GestureType.HOME);
@@ -1627,6 +1642,10 @@
}
windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+ if (mHandOffAnimationToHome) {
+ handOffAnimation(velocityPxPerMs);
+ }
+
windowAnim[0].addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
@@ -1709,6 +1728,19 @@
}
}
+ private void handOffAnimation(PointF velocityPxPerMs) {
+ if (!TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
+ || mRecentsAnimationController == null) {
+ return;
+ }
+
+ Pair<RemoteAnimationTarget[], WindowAnimationState[]> targetsAndStates =
+ extractTargetsAndStates(mRemoteTargetHandles, velocityPxPerMs);
+ mRecentsAnimationController.handOffAnimation(
+ targetsAndStates.first, targetsAndStates.second);
+ ActiveGestureProtoLogProxy.logHandOffAnimation();
+ }
+
private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget,
RecentsOrientedState orientationState) {
if (runningTaskTarget.rotationChange != 0) {
@@ -2174,8 +2206,9 @@
mSwipePipToHomeAnimator.getFinishTransaction(),
mSwipePipToHomeAnimator.getContentOverlay());
mIsSwipingPipToHome = false;
- } else if (mIsSwipeForSplit) {
+ } else if (mIsSwipeForSplit && !Flags.enablePip2()) {
// Transaction to hide the task to avoid flicker for entering PiP from split-screen.
+ // Note: PiP2 handles entering differently, so skip if enable_pip2=true
PictureInPictureSurfaceTransaction tx =
new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index a3953ca..2164bc2 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -378,6 +378,9 @@
public static void getTaskDimension(Context context, DeviceProfile dp, PointF out) {
out.x = dp.widthPx;
out.y = dp.heightPx;
+ if (dp.isTablet && !DisplayController.isTransientTaskbar(context)) {
+ out.y -= dp.taskbarHeight;
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt b/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt
new file mode 100644
index 0000000..bafb0b2
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.content.Context
+import com.android.systemui.shared.system.QuickStepContract
+
+// DesktopTaskView thumbnail's corner radius is independent of fullscreenProgress.
+open class DesktopFullscreenDrawParams
+@JvmOverloads
+constructor(context: Context, cornerRadiusProvider: (Context) -> Float = ::computeCornerRadius) :
+ FullscreenDrawParams(context, cornerRadiusProvider, cornerRadiusProvider) {
+ companion object {
+ // computeCornerRadius is used as cornerRadiusProvider, so
+ // QuickStepContract::getWindowCornerRadius can be mocked properly.
+ private fun computeCornerRadius(context: Context): Float =
+ QuickStepContract.getWindowCornerRadius(context)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FullscreenDrawParams.kt b/quickstep/src/com/android/quickstep/FullscreenDrawParams.kt
new file mode 100644
index 0000000..a5ba52a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/FullscreenDrawParams.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.content.Context
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.SafeCloseable
+import com.android.launcher3.views.ActivityContext
+import com.android.quickstep.util.TaskCornerRadius
+import com.android.systemui.shared.system.QuickStepContract
+
+/**
+ * Class for computing corner radius by interpolating between overview and fullscreen corner radius
+ * with fullscreenProgress set in [setProgress].
+ */
+open class FullscreenDrawParams
+@JvmOverloads
+constructor(
+ context: Context,
+ private val taskCornerRadiusProvider: (Context) -> Float = ::computeTaskCornerRadius,
+ private val windowCornerRadiusProvider: (Context) -> Float = ::computeWindowCornerRadius,
+) : SafeCloseable {
+ private var taskCornerRadius = 0f
+ private var windowCornerRadius = 0f
+ var currentCornerRadius = 0f
+
+ init {
+ updateCornerRadius(context)
+ }
+
+ /** Recomputes the start and end corner radius for the given Context. */
+ fun updateCornerRadius(context: Context) {
+ taskCornerRadius = taskCornerRadiusProvider(context)
+ windowCornerRadius = windowCornerRadiusProvider(context)
+ }
+
+ /** Sets the progress in range [0, 1] */
+ fun setProgress(fullscreenProgress: Float, parentScale: Float, taskViewScale: Float) {
+ currentCornerRadius =
+ Utilities.mapRange(fullscreenProgress, taskCornerRadius, windowCornerRadius) /
+ parentScale /
+ taskViewScale
+ }
+
+ override fun close() {}
+
+ companion object {
+ private fun computeTaskCornerRadius(context: Context): Float = TaskCornerRadius.get(context)
+
+ private fun computeWindowCornerRadius(context: Context): Float {
+ val activityContext: ActivityContext? = ActivityContext.lookupContextNoThrow(context)
+ return if (
+ activityContext?.deviceProfile?.isTaskbarPresent == true &&
+ DisplayController.isTransientTaskbar(context)
+ ) {
+ context.resources
+ .getDimensionPixelSize(R.dimen.persistent_taskbar_corner_radius)
+ .toFloat()
+ } else {
+ // The corner radius is fixed to match when Taskbar is persistent mode
+ QuickStepContract.getWindowCornerRadius(context)
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index cff352c..cfbcf0a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -28,6 +28,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
+import android.app.TaskInfo;
import android.content.Intent;
import android.os.SystemClock;
import android.view.MotionEvent;
@@ -45,6 +46,7 @@
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.wm.shell.shared.GroupedTaskInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -272,7 +274,7 @@
* @return the interface to the activity handing the UI updates for this gesture.
*/
public <S extends BaseState<S>, T extends RecentsViewContainer & StatefulContainer<S>>
- BaseContainerInterface getContainerInterface() {
+ BaseContainerInterface<S, T> getContainerInterface() {
return mContainerInterface;
}
@@ -330,13 +332,23 @@
if (mRunningTask == null) {
return new int[]{INVALID_TASK_ID, INVALID_TASK_ID};
} else {
- int cachedTasksSize = mRunningTask.mAllCachedTasks.size();
- int count = Math.min(cachedTasksSize, getMultipleTasks ? 2 : 1);
- int[] runningTaskIds = new int[count];
- for (int i = 0; i < count; i++) {
- runningTaskIds[i] = mRunningTask.mAllCachedTasks.get(i).taskId;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ if (mRunningTask.getVisibleTasks().isEmpty()) {
+ return new int[0];
+ }
+ GroupedTaskInfo topRunningTask = mRunningTask.getVisibleTasks().getFirst();
+ List<TaskInfo> groupedTasks = topRunningTask.getTaskInfoList();
+ return groupedTasks.stream().mapToInt(
+ groupedTask -> groupedTask.taskId).toArray();
+ } else {
+ int cachedTasksSize = mRunningTask.mAllCachedTasks.size();
+ int count = Math.min(cachedTasksSize, getMultipleTasks ? 2 : 1);
+ int[] runningTaskIds = new int[count];
+ for (int i = 0; i < count; i++) {
+ runningTaskIds[i] = mRunningTask.mAllCachedTasks.get(i).taskId;
+ }
+ return runningTaskIds;
}
- return runningTaskIds;
}
}
diff --git a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
new file mode 100644
index 0000000..bea3150
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import android.content.Context
+import android.view.MotionEvent
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.anim.AnimatedFloat
+import com.android.launcher3.statemanager.BaseState
+import com.android.launcher3.statemanager.StatefulContainer
+import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.util.LockedUserState.Companion.get
+import com.android.quickstep.inputconsumers.AccessibilityInputConsumer
+import com.android.quickstep.inputconsumers.AssistantInputConsumer
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer
+import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer
+import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer
+import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer
+import com.android.quickstep.inputconsumers.OtherActivityInputConsumer
+import com.android.quickstep.inputconsumers.OverviewInputConsumer
+import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer
+import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer
+import com.android.quickstep.inputconsumers.ResetGestureInputConsumer
+import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer
+import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer
+import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer
+import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer
+import com.android.quickstep.util.ActiveGestureErrorDetector
+import com.android.quickstep.util.ActiveGestureLog
+import com.android.quickstep.util.ActiveGestureLog.CompoundString
+import com.android.quickstep.util.ActiveGestureProtoLogProxy
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.systemui.shared.system.InputChannelCompat
+import com.android.systemui.shared.system.InputMonitorCompat
+import com.android.wm.shell.Flags
+import java.util.function.Consumer
+import java.util.function.Function
+
+/** Utility class for creating input consumers. */
+object InputConsumerUtils {
+ private const val SUBSTRING_PREFIX = "; "
+ private const val NEWLINE_PREFIX = "\n\t\t\t-> "
+
+ @JvmStatic
+ fun <S : BaseState<S>, T> newConsumer(
+ baseContext: Context,
+ tisContext: Context,
+ resetGestureInputConsumer: ResetGestureInputConsumer?,
+ overviewComponentObserver: OverviewComponentObserver,
+ deviceState: RecentsAnimationDeviceState,
+ previousGestureState: GestureState,
+ gestureState: GestureState,
+ taskAnimationManager: TaskAnimationManager,
+ inputMonitorCompat: InputMonitorCompat,
+ swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
+ onCompleteCallback: Consumer<OtherActivityInputConsumer>,
+ inputEventReceiver: InputChannelCompat.InputEventReceiver,
+ taskbarManager: TaskbarManager,
+ swipeUpProxyProvider: Function<GestureState?, AnimatedFloat?>,
+ overviewCommandHelper: OverviewCommandHelper,
+ event: MotionEvent,
+ ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
+ val tac = taskbarManager.currentActivityContext
+ val bubbleControllers = tac?.bubbleControllers
+ if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
+ val consumer: InputConsumer =
+ BubbleBarInputConsumer(tisContext, bubbleControllers, inputMonitorCompat)
+ logInputConsumerSelectionReason(
+ consumer,
+ newCompoundString("event is on bubbles, creating new input consumer"),
+ )
+ return consumer
+ }
+ val progressProxy = swipeUpProxyProvider.apply(gestureState)
+ if (progressProxy != null) {
+ val consumer: InputConsumer =
+ ProgressDelegateInputConsumer(
+ tisContext,
+ taskAnimationManager,
+ gestureState,
+ inputMonitorCompat,
+ progressProxy,
+ )
+
+ logInputConsumerSelectionReason(
+ consumer,
+ newCompoundString(
+ "mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"
+ ),
+ )
+
+ return consumer
+ }
+
+ val canStartSystemGesture =
+ if (gestureState.isTrackpadGesture) deviceState.canStartTrackpadGesture()
+ else deviceState.canStartSystemGesture()
+
+ if (!get(tisContext).isUserUnlocked) {
+ val reasonString = newCompoundString("device locked")
+ val consumer =
+ if (canStartSystemGesture) {
+ // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
+ // launched while device is locked even after exiting direct boot mode (e.g.
+ // camera).
+ createDeviceLockedInputConsumer(
+ tisContext,
+ resetGestureInputConsumer,
+ deviceState,
+ gestureState,
+ taskAnimationManager,
+ inputMonitorCompat,
+ reasonString.append("%scan start system gesture", SUBSTRING_PREFIX),
+ )
+ } else {
+ getDefaultInputConsumer(
+ resetGestureInputConsumer,
+ reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX),
+ )
+ }
+ logInputConsumerSelectionReason(consumer, reasonString)
+ return consumer
+ }
+
+ var reasonString: CompoundString
+ var base: InputConsumer
+ // When there is an existing recents animation running, bypass systemState check as this is
+ // a followup gesture and the first gesture started in a valid system state.
+ if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning) {
+ reasonString =
+ newCompoundString(
+ if (canStartSystemGesture)
+ "can start system gesture, trying to use base consumer"
+ else "recents animation was running, trying to use base consumer"
+ )
+ base =
+ newBaseConsumer<S, T>(
+ tisContext,
+ resetGestureInputConsumer,
+ overviewComponentObserver,
+ deviceState,
+ previousGestureState,
+ gestureState,
+ taskAnimationManager,
+ inputMonitorCompat,
+ swipeUpHandlerFactory,
+ onCompleteCallback,
+ inputEventReceiver,
+ event,
+ reasonString,
+ )
+ } else {
+ reasonString =
+ newCompoundString(
+ "cannot start system gesture and recents " +
+ "animation was not running, trying to use default input consumer"
+ )
+ base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+ }
+ if (deviceState.isGesturalNavMode || gestureState.isTrackpadGesture) {
+ handleOrientationSetup(base)
+ }
+ if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) {
+ val reasonPrefix =
+ "device is in gesture navigation mode or 3-button mode with a trackpad gesture"
+ if (deviceState.canTriggerAssistantAction(event)) {
+ reasonString.append(
+ "%s%s%sgesture can trigger the assistant, " +
+ "trying to use assistant input consumer",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ base =
+ tryCreateAssistantInputConsumer(
+ tisContext,
+ deviceState,
+ inputMonitorCompat,
+ base,
+ gestureState,
+ event,
+ reasonString,
+ )
+ }
+
+ // If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
+ if (tac != null && base !is AssistantInputConsumer) {
+ // Present always on large screen or on small screen w/ flag
+ val useTaskbarConsumer =
+ (tac.deviceProfile.isTaskbarPresent &&
+ !tac.isPhoneMode &&
+ !tac.isInStashedLauncherState)
+ if (canStartSystemGesture && useTaskbarConsumer) {
+ reasonString.append(
+ "%s%s%sTaskbarActivityContext != null, " +
+ "using TaskbarUnstashInputConsumer",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ base =
+ TaskbarUnstashInputConsumer(
+ tisContext,
+ base,
+ inputMonitorCompat,
+ tac,
+ overviewCommandHelper,
+ gestureState,
+ )
+ }
+ }
+ if (Flags.enableBubblesLongPressNavHandle()) {
+ // Create bubbles input consumer before NavHandleLongPressInputConsumer.
+ // This allows for nav handle to fall back to bubbles.
+ if (deviceState.isBubblesExpanded) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%sbubbles expanded, trying to use default input consumer",
+ SUBSTRING_PREFIX,
+ )
+ // Bubbles can handle home gesture itself.
+ base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+ }
+ }
+
+ val navHandle = tac?.navHandle ?: SystemUiProxy.INSTANCE[tisContext]
+ if (
+ canStartSystemGesture &&
+ !previousGestureState.isRecentsAnimationRunning &&
+ navHandle.canNavHandleBeLongPressed() &&
+ !ignoreThreeFingerTrackpadForNavHandleLongPress(gestureState)
+ ) {
+ reasonString.append(
+ "%s%s%sNot running recents animation, ",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ if (tac != null && tac.navHandle.canNavHandleBeLongPressed()) {
+ reasonString.append("stashed handle is long-pressable, ")
+ }
+ reasonString.append("using NavHandleLongPressInputConsumer")
+ base =
+ NavHandleLongPressInputConsumer(
+ tisContext,
+ base,
+ inputMonitorCompat,
+ deviceState,
+ navHandle,
+ gestureState,
+ )
+ }
+
+ if (!Flags.enableBubblesLongPressNavHandle()) {
+ // Continue overriding nav handle input consumer with bubbles
+ if (deviceState.isBubblesExpanded) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%sbubbles expanded, trying to use default input consumer",
+ SUBSTRING_PREFIX,
+ )
+ // Bubbles can handle home gesture itself.
+ base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+ }
+ }
+
+ if (deviceState.isSystemUiDialogShowing) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%ssystem dialog is showing, using SysUiOverlayInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ base = SysUiOverlayInputConsumer(baseContext, deviceState, inputMonitorCompat)
+ }
+
+ if (
+ gestureState.isTrackpadGesture &&
+ canStartSystemGesture &&
+ !previousGestureState.isRecentsAnimationRunning
+ ) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%sTrackpad 3-finger gesture, using TrackpadStatusBarInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ base = TrackpadStatusBarInputConsumer(baseContext, base, inputMonitorCompat)
+ }
+
+ if (deviceState.isScreenPinningActive) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%sscreen pinning is active, using ScreenPinnedInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ // Note: we only allow accessibility to wrap this, and it replaces the previous
+ // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
+ base = ScreenPinnedInputConsumer(tisContext, gestureState)
+ }
+
+ if (deviceState.canTriggerOneHandedAction(event)) {
+ reasonString.append(
+ "%s%s%sgesture can trigger one handed mode, " +
+ "using OneHandedModeInputConsumer",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ base = OneHandedModeInputConsumer(tisContext, deviceState, base, inputMonitorCompat)
+ }
+
+ if (deviceState.isAccessibilityMenuAvailable) {
+ reasonString.append(
+ "%s%s%saccessibility menu is available, using AccessibilityInputConsumer",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ base =
+ AccessibilityInputConsumer(
+ tisContext,
+ deviceState,
+ gestureState,
+ base,
+ inputMonitorCompat,
+ )
+ }
+ } else {
+ val reasonPrefix = "device is not in gesture navigation mode"
+ if (deviceState.isScreenPinningActive) {
+ reasonString =
+ newCompoundString(reasonPrefix)
+ .append(
+ "%sscreen pinning is active, trying to use default input consumer",
+ SUBSTRING_PREFIX,
+ )
+ base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
+ }
+
+ if (deviceState.canTriggerOneHandedAction(event)) {
+ reasonString.append(
+ "%s%s%sgesture can trigger one handed mode, " +
+ "using OneHandedModeInputConsumer",
+ NEWLINE_PREFIX,
+ reasonPrefix,
+ SUBSTRING_PREFIX,
+ )
+ base = OneHandedModeInputConsumer(tisContext, deviceState, base, inputMonitorCompat)
+ }
+ }
+ logInputConsumerSelectionReason(base, reasonString)
+ return base
+ }
+
+ @JvmStatic
+ fun tryCreateAssistantInputConsumer(
+ context: Context,
+ deviceState: RecentsAnimationDeviceState,
+ inputMonitorCompat: InputMonitorCompat,
+ gestureState: GestureState,
+ motionEvent: MotionEvent,
+ ): InputConsumer {
+ return tryCreateAssistantInputConsumer(
+ context,
+ deviceState,
+ inputMonitorCompat,
+ InputConsumer.NO_OP,
+ gestureState,
+ motionEvent,
+ CompoundString.NO_OP,
+ )
+ }
+
+ private fun tryCreateAssistantInputConsumer(
+ context: Context,
+ deviceState: RecentsAnimationDeviceState,
+ inputMonitorCompat: InputMonitorCompat,
+ base: InputConsumer,
+ gestureState: GestureState,
+ motionEvent: MotionEvent,
+ reasonString: CompoundString,
+ ): InputConsumer {
+ return if (deviceState.isGestureBlockedTask(gestureState.runningTask)) {
+ reasonString.append(
+ "%sis gesture-blocked task, using base input consumer",
+ SUBSTRING_PREFIX,
+ )
+ base
+ } else {
+ reasonString.append("%susing AssistantInputConsumer", SUBSTRING_PREFIX)
+ AssistantInputConsumer(
+ context,
+ gestureState,
+ base,
+ inputMonitorCompat,
+ deviceState,
+ motionEvent,
+ )
+ }
+ }
+
+ @VisibleForTesting
+ @JvmStatic
+ fun <S : BaseState<S>, T> newBaseConsumer(
+ context: Context,
+ resetGestureInputConsumer: ResetGestureInputConsumer?,
+ overviewComponentObserver: OverviewComponentObserver,
+ deviceState: RecentsAnimationDeviceState,
+ previousGestureState: GestureState,
+ gestureState: GestureState,
+ taskAnimationManager: TaskAnimationManager,
+ inputMonitorCompat: InputMonitorCompat,
+ swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
+ onCompleteCallback: Consumer<OtherActivityInputConsumer>,
+ inputEventReceiver: InputChannelCompat.InputEventReceiver,
+ event: MotionEvent,
+ reasonString: CompoundString,
+ ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
+ if (deviceState.isKeyguardShowingOccluded) {
+ // This handles apps showing over the lockscreen (e.g. camera)
+ return createDeviceLockedInputConsumer(
+ context,
+ resetGestureInputConsumer,
+ deviceState,
+ gestureState,
+ taskAnimationManager,
+ inputMonitorCompat,
+ reasonString.append(
+ "%skeyguard is showing occluded, " +
+ "trying to use device locked input consumer",
+ SUBSTRING_PREFIX,
+ ),
+ )
+ }
+
+ reasonString.append("%skeyguard is not showing occluded", SUBSTRING_PREFIX)
+
+ val runningTask = gestureState.runningTask
+ // Use overview input consumer for sharesheets on top of home.
+ val forceOverviewInputConsumer =
+ gestureState.getContainerInterface<S, T>().isStarted() &&
+ runningTask != null &&
+ runningTask.isRootChooseActivity
+
+ if (!Flags.enableShellTopTaskTracking()) {
+ // In the case where we are in an excluded, translucent overlay, ignore it and treat the
+ // running activity as the task behind the overlay.
+ val otherVisibleTask = runningTask?.visibleNonExcludedTask
+ if (otherVisibleTask != null) {
+ ActiveGestureProtoLogProxy.logUpdateGestureStateRunningTask(
+ otherVisibleTask.packageName ?: "MISSING",
+ runningTask.packageName ?: "MISSING",
+ )
+ gestureState.updateRunningTask(otherVisibleTask)
+ }
+ }
+
+ val previousGestureAnimatedToLauncher =
+ (previousGestureState.isRunningAnimationToLauncher ||
+ deviceState.isPredictiveBackToHomeInProgress)
+ // with shell-transitions, home is resumed during recents animation, so
+ // explicitly check against recents animation too.
+ val launcherResumedThroughShellTransition =
+ (gestureState.getContainerInterface<S, T>().isResumed() &&
+ !previousGestureState.isRecentsAnimationRunning)
+ // If a task fragment within Launcher is resumed
+ val launcherChildActivityResumed =
+ (com.android.launcher3.Flags.useActivityOverlay() &&
+ runningTask != null &&
+ runningTask.isHomeTask &&
+ overviewComponentObserver.isHomeAndOverviewSame &&
+ !launcherResumedThroughShellTransition &&
+ !previousGestureState.isRecentsAnimationRunning)
+
+ return if (gestureState.getContainerInterface<S, T>().isInLiveTileMode()) {
+ createOverviewInputConsumer<S, T>(
+ resetGestureInputConsumer,
+ deviceState,
+ inputMonitorCompat,
+ previousGestureState,
+ gestureState,
+ event,
+ reasonString.append(
+ "%sis in live tile mode, trying to use overview input consumer",
+ SUBSTRING_PREFIX,
+ ),
+ )
+ } else if (runningTask == null) {
+ getDefaultInputConsumer(
+ resetGestureInputConsumer,
+ reasonString.append("%srunning task == null", SUBSTRING_PREFIX),
+ )
+ } else if (
+ previousGestureAnimatedToLauncher ||
+ launcherResumedThroughShellTransition ||
+ forceOverviewInputConsumer
+ ) {
+ createOverviewInputConsumer<S, T>(
+ resetGestureInputConsumer,
+ deviceState,
+ inputMonitorCompat,
+ previousGestureState,
+ gestureState,
+ event,
+ reasonString.append(
+ if (previousGestureAnimatedToLauncher)
+ ("%sprevious gesture animated to launcher, " +
+ "trying to use overview input consumer")
+ else
+ (if (launcherResumedThroughShellTransition)
+ ("%slauncher resumed through a shell transition, " +
+ "trying to use overview input consumer")
+ else
+ ("%sforceOverviewInputConsumer == true, " +
+ "trying to use overview input consumer")),
+ SUBSTRING_PREFIX,
+ ),
+ )
+ } else if (deviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
+ getDefaultInputConsumer(
+ resetGestureInputConsumer,
+ reasonString.append(
+ if (launcherChildActivityResumed)
+ "%sis launcher child-task, trying to use default input consumer"
+ else "%sis gesture-blocked task, trying to use default input consumer",
+ SUBSTRING_PREFIX,
+ ),
+ )
+ } else {
+ reasonString.append("%susing OtherActivityInputConsumer", SUBSTRING_PREFIX)
+ createOtherActivityInputConsumer<S, T>(
+ context,
+ swipeUpHandlerFactory,
+ overviewComponentObserver,
+ deviceState,
+ taskAnimationManager,
+ inputMonitorCompat,
+ onCompleteCallback,
+ inputEventReceiver,
+ gestureState,
+ event,
+ )
+ }
+ }
+
+ private fun createDeviceLockedInputConsumer(
+ context: Context,
+ resetGestureInputConsumer: ResetGestureInputConsumer?,
+ deviceState: RecentsAnimationDeviceState,
+ gestureState: GestureState,
+ taskAnimationManager: TaskAnimationManager,
+ inputMonitorCompat: InputMonitorCompat,
+ reasonString: CompoundString,
+ ): InputConsumer {
+ return if (
+ (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) &&
+ gestureState.runningTask != null
+ ) {
+ reasonString.append(
+ "%sdevice is in gesture nav mode or 3-button mode with a trackpad " +
+ "gesture and running task != null, using DeviceLockedInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ DeviceLockedInputConsumer(
+ context,
+ deviceState,
+ taskAnimationManager,
+ gestureState,
+ inputMonitorCompat,
+ )
+ } else {
+ getDefaultInputConsumer(
+ resetGestureInputConsumer,
+ reasonString.append(
+ if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture)
+ "%srunning task == null, trying to use default input consumer"
+ else
+ ("%sdevice is not in gesture nav mode and it's not a trackpad gesture," +
+ " trying to use default input consumer"),
+ SUBSTRING_PREFIX,
+ ),
+ )
+ }
+ }
+
+ private fun <S : BaseState<S>, T> createOverviewInputConsumer(
+ resetGestureInputConsumer: ResetGestureInputConsumer?,
+ deviceState: RecentsAnimationDeviceState,
+ inputMonitorCompat: InputMonitorCompat,
+ previousGestureState: GestureState,
+ gestureState: GestureState,
+ event: MotionEvent,
+ reasonString: CompoundString,
+ ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
+ val container: T =
+ gestureState.getContainerInterface<S, T>().getCreatedContainer()
+ ?: return getDefaultInputConsumer(
+ resetGestureInputConsumer,
+ reasonString.append(
+ "%sactivity == null, trying to use default input consumer",
+ SUBSTRING_PREFIX,
+ ),
+ )
+
+ val rootView = container.rootView
+ val hasWindowFocus = rootView?.hasWindowFocus() ?: false
+ val isPreviousGestureAnimatingToLauncher =
+ (previousGestureState.isRunningAnimationToLauncher ||
+ deviceState.isPredictiveBackToHomeInProgress)
+ val isInLiveTileMode: Boolean =
+ gestureState.getContainerInterface<S, T>().isInLiveTileMode()
+
+ reasonString.append(
+ if (hasWindowFocus) "%sactivity has window focus"
+ else
+ (if (isPreviousGestureAnimatingToLauncher)
+ "%sprevious gesture is still animating to launcher"
+ else if (isInLiveTileMode) "%sdevice is in live mode"
+ else "%sall overview focus conditions failed"),
+ SUBSTRING_PREFIX,
+ )
+ return if (hasWindowFocus || isPreviousGestureAnimatingToLauncher || isInLiveTileMode) {
+ reasonString.append(
+ "%soverview should have focus, using OverviewInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ OverviewInputConsumer(
+ gestureState,
+ container,
+ inputMonitorCompat,
+ /* startingInActivityBounds= */ false,
+ )
+ } else {
+ reasonString.append(
+ "%soverview shouldn't have focus, using OverviewWithoutFocusInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ val disableHorizontalSwipe = deviceState.isInExclusionRegion(event)
+ OverviewWithoutFocusInputConsumer(
+ container.asContext(),
+ deviceState,
+ gestureState,
+ inputMonitorCompat,
+ disableHorizontalSwipe,
+ )
+ }
+ }
+
+ /** Returns the [ResetGestureInputConsumer] if user is unlocked, else NO_OP. */
+ private fun getDefaultInputConsumer(
+ resetGestureInputConsumer: ResetGestureInputConsumer?,
+ reasonString: CompoundString,
+ ): InputConsumer {
+ return if (resetGestureInputConsumer != null) {
+ reasonString.append(
+ "%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer",
+ SUBSTRING_PREFIX,
+ )
+ resetGestureInputConsumer
+ } 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).
+ InputConsumer.NO_OP
+ }
+ }
+
+ private fun <S : BaseState<S>, T> createOtherActivityInputConsumer(
+ context: Context,
+ swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
+ overviewComponentObserver: OverviewComponentObserver,
+ deviceState: RecentsAnimationDeviceState,
+ taskAnimationManager: TaskAnimationManager,
+ inputMonitorCompat: InputMonitorCompat,
+ onCompleteCallback: Consumer<OtherActivityInputConsumer>,
+ inputEventReceiver: InputChannelCompat.InputEventReceiver,
+ gestureState: GestureState,
+ event: MotionEvent,
+ ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
+ val shouldDefer =
+ (!overviewComponentObserver.isHomeAndOverviewSame ||
+ gestureState
+ .getContainerInterface<S, T>()
+ .deferStartingActivity(deviceState, event))
+ val disableHorizontalSwipe = deviceState.isInExclusionRegion(event)
+ return OtherActivityInputConsumer(
+ /* base= */ context,
+ deviceState,
+ taskAnimationManager,
+ gestureState,
+ /* isDeferredDownTarget= */ shouldDefer,
+ onCompleteCallback,
+ inputMonitorCompat,
+ inputEventReceiver,
+ disableHorizontalSwipe,
+ swipeUpHandlerFactory,
+ )
+ }
+
+ private fun newCompoundString(substring: String): CompoundString {
+ return CompoundString("%s%s", NEWLINE_PREFIX, substring)
+ }
+
+ private fun logInputConsumerSelectionReason(
+ consumer: InputConsumer,
+ reasonString: CompoundString,
+ ) {
+ ActiveGestureProtoLogProxy.logSetInputConsumer(consumer.name, reasonString.toString())
+ if ((consumer.type and InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
+ ActiveGestureLog.INSTANCE.trackEvent(
+ ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER
+ )
+ }
+ }
+
+ private fun ignoreThreeFingerTrackpadForNavHandleLongPress(
+ gestureState: GestureState
+ ): Boolean {
+ return (com.android.launcher3.Flags.ignoreThreeFingerTrackpadForNavHandleLongPress() &&
+ gestureState.isThreeFingerTrackpadGesture)
+ }
+
+ private fun handleOrientationSetup(baseInputConsumer: InputConsumer) {
+ baseInputConsumer.notifyOrientationSetup()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 1124aac..4bd9ffb 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+import static com.android.window.flags.Flags.predictiveBackThreeButtonNav;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -48,8 +49,8 @@
import android.window.BackEvent;
import android.window.BackMotionEvent;
import android.window.BackProgressAnimator;
+import android.window.IBackAnimationHandoffHandler;
import android.window.IOnBackInvokedCallback;
-
import com.android.app.animation.Interpolators;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.view.AppearanceRegion;
@@ -60,6 +61,8 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.quickstep.util.BackAnimState;
import com.android.systemui.shared.system.QuickStepContract;
@@ -222,6 +225,12 @@
public void setTriggerBack(boolean triggerBack) {
// TODO(b/261654570): track touch from the Launcher process.
}
+
+ @Override
+ public void setHandoffHandler(IBackAnimationHandoffHandler unused) {
+ // For now, Launcher handles this internally so it doesn't need to hand off the
+ // animation.
+ }
}
private static class RemoteAnimationRunnerStub extends IRemoteAnimationRunner.Stub {
@@ -295,8 +304,11 @@
mStartRect.set(appTarget.windowConfiguration.getMaxBounds());
- // inset bottom in case of pinned taskbar being present
- mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom);
+ // inset bottom in case of taskbar being present
+ if (!predictiveBackThreeButtonNav() || mLauncher.getDeviceProfile().isTaskbarPresent
+ || DisplayController.getNavigationMode(mLauncher) == NavigationMode.NO_BUTTON) {
+ mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom);
+ }
mLauncherTargetView = mQuickstepTransitionManager.findLauncherView(
new RemoteAnimationTarget[]{ mBackTarget });
@@ -378,10 +390,11 @@
// Move the window along the Y axis.
float top = (screenHeight - height) * 0.5f + deltaY;
// Move the window along the X axis.
- float left = event.getSwipeEdge() == BackEvent.EDGE_RIGHT
- ? progress * mWindowScaleMarginX
- : screenWidth - progress * mWindowScaleMarginX - width;
-
+ float left = switch (event.getSwipeEdge()) {
+ case BackEvent.EDGE_RIGHT -> progress * mWindowScaleMarginX;
+ case BackEvent.EDGE_LEFT -> screenWidth - progress * mWindowScaleMarginX - width;
+ default -> (screenWidth - width) / 2;
+ };
mCurrentRect.set(left, top, left + width, top + height);
float cornerRadius = Utilities.mapRange(
progress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index dacafd4..6087dc2 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -46,7 +46,6 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -54,6 +53,7 @@
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.TransitionAnimator;
import com.android.systemui.shared.system.InputConsumerController;
import java.util.Collections;
@@ -108,7 +108,9 @@
mContainer.getRootView().setForceHideBackArrow(true);
- if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
+ boolean handOffAnimation = TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
+ && mHandOffAnimationToHome;
+ if (handOffAnimation || !canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
return new LauncherHomeAnimationFactory() {
@Nullable
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 714838a..85e2b6e 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -114,12 +114,9 @@
}
@Override
- public void onTaskMovedToFront(GroupedTaskInfo[] visibleTasks) {
+ public void onTaskMovedToFront(GroupedTaskInfo taskToFront) {
mMainThreadExecutor.execute(() -> {
- // TODO(b/346588978): We currently are only sending a single task, but this will
- // be updated once we send the full set of visible tasks
- final TaskInfo info = visibleTasks[0].getTaskInfo1();
- topTaskTracker.handleTaskMovedToFront(info);
+ topTaskTracker.handleTaskMovedToFront(taskToFront.getTaskInfo1());
});
}
@@ -127,6 +124,13 @@
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
mMainThreadExecutor.execute(() -> topTaskTracker.onTaskChanged(taskInfo));
}
+
+ @Override
+ public void onVisibleTasksChanged(GroupedTaskInfo[] visibleTasks) {
+ mMainThreadExecutor.execute(() -> {
+ topTaskTracker.onVisibleTasksChanged(visibleTasks);
+ });
+ }
});
// We may receive onRunningTaskAppeared events later for tasks which have already been
// included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index dcb0108..055aadb 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -21,9 +21,11 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.PictureInPictureSurfaceTransaction;
+import android.window.WindowAnimationState;
import androidx.annotation.UiThread;
@@ -32,6 +34,7 @@
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
+import com.android.systemui.animation.TransitionAnimator;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -88,6 +91,16 @@
}
@UiThread
+ public void handOffAnimation(RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+ if (TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()) {
+ UI_HELPER_EXECUTOR.execute(() -> mController.handOffAnimation(targets, states));
+ } else {
+ Log.e(TAG, "Tried to hand off the animation, but the feature is disabled",
+ new Exception());
+ }
+ }
+
+ @UiThread
public void finishAnimationToHome() {
finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index de8be50..e296449 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -354,7 +354,11 @@
* @return whether the given running task info matches the gesture-blocked task.
*/
public boolean isGestureBlockedTask(CachedTaskInfo taskInfo) {
- return taskInfo != null && taskInfo.getTaskId() == mGestureBlockingTaskId;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return taskInfo != null && taskInfo.topGroupedTaskContainsTask(mGestureBlockingTaskId);
+ } else {
+ return taskInfo != null && taskInfo.getTaskId() == mGestureBlockingTaskId;
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 06b2972..91d0776 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -93,8 +93,7 @@
BaseContainerInterface sizingStrategy, int numHandles, boolean forDesktop) {
RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles];
for (int i = 0; i < numHandles; i++) {
- TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy);
- tvs.setIsDesktopTask(forDesktop , i);
+ TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy, forDesktop , i);
TransformParams transformParams = new TransformParams();
handles[i] = new RemoteTargetHandle(tvs, transformParams);
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 0dbdcb7..fef4c30 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -348,7 +348,7 @@
}
/** Called when the snapshot has updated its full screen drawing parameters. */
- public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {}
+ public void setFullscreenParams(FullscreenDrawParams fullscreenParams) {}
/** Sets visibility for the overlay associated elements. */
public void setVisibility(int visibility) {}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 07ee479..783c87c 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -47,12 +47,15 @@
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.util.Pair;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.View;
import android.window.TransitionInfo;
+import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -784,4 +787,43 @@
animatorHandler.accept(dockFadeAnimator);
return dockFadeAnimator;
}
+
+ /**
+ * Creates an array of {@link RemoteAnimationTarget}s and a matching array of
+ * {@link WindowAnimationState}s from the provided handles.
+ * Important: the ordering of the two arrays is the same, so the state at each index of the
+ * second applies to the target in the same index of the first.
+ *
+ * @param handles The handles wrapping each target.
+ * @param velocityPxPerMs The current velocity of the target animations.
+ */
+ @NonNull
+ public static Pair<RemoteAnimationTarget[], WindowAnimationState[]> extractTargetsAndStates(
+ @NonNull RemoteTargetHandle[] handles, @NonNull PointF velocityPxPerMs) {
+ RemoteAnimationTarget[] targets = new RemoteAnimationTarget[handles.length];
+ WindowAnimationState[] animationStates = new WindowAnimationState[handles.length];
+ long timestamp = System.currentTimeMillis();
+
+ for (int i = 0; i < handles.length; i++) {
+ targets[i] = handles[i].getTransformParams().getTargetSet().apps[i];
+
+ TaskViewSimulator taskViewSimulator = handles[i].getTaskViewSimulator();
+ RectF startRect = taskViewSimulator.getCurrentRect();
+ float cornerRadius = taskViewSimulator.getCurrentCornerRadius();
+
+ WindowAnimationState state = new WindowAnimationState();
+ state.timestamp = timestamp;
+ state.bounds = new RectF(
+ startRect.left, startRect.top, startRect.right, startRect.bottom);
+ state.topLeftRadius = cornerRadius;
+ state.topRightRadius = cornerRadius;
+ state.bottomRightRadius = cornerRadius;
+ state.bottomLeftRadius = cornerRadius;
+ state.velocityPxPerMs = velocityPxPerMs;
+
+ animationStates[i] = state;
+ }
+
+ return new Pair<>(targets, animationStates);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index c9dfe6d..210065a 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -18,17 +18,20 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.Intent.ACTION_CHOOSER;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_A;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
+import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_SPLIT;
-import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
import android.content.Context;
+import android.util.ArrayMap;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -46,8 +49,10 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.shared.GroupedTaskInfo;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -61,37 +66,58 @@
*/
public class TopTaskTracker extends ISplitScreenListener.Stub
implements TaskStackChangeListener, SafeCloseable {
-
+ private static final String TAG = "TopTaskTracker";
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
new MainThreadInitializedObject<>(TopTaskTracker::new);
private static final int HISTORY_SIZE = 5;
+ private final Context mContext;
+
+ // Only used when Flags.enableShellTopTaskTracking() is disabled
// Ordered list with first item being the most recent task.
private final LinkedList<TaskInfo> mOrderedTaskList = new LinkedList<>();
-
- private final Context mContext;
private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
private int mPinnedTaskId = INVALID_TASK_ID;
+ // Only used when Flags.enableShellTopTaskTracking() is enabled
+ // Mapping of display id to running tasks. Running tasks are ordered from top most to
+ // bottom most.
+ private ArrayMap<Integer, ArrayList<GroupedTaskInfo>> mVisibleTasks = new ArrayMap<>();
+
private TopTaskTracker(Context context) {
mContext = context;
- mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
- mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
- TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
- SystemUiProxy.INSTANCE.get(context).registerSplitScreenListener(this);
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // Just prepopulate a list for the default display tasks so we don't need to add null
+ // checks everywhere
+ mVisibleTasks.put(DEFAULT_DISPLAY, new ArrayList<>());
+ } else {
+ mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
+ mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
+
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ SystemUiProxy.INSTANCE.get(context).registerSplitScreenListener(this);
+ }
}
@Override
public void close() {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
}
@Override
public void onTaskRemoved(int taskId) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
}
@@ -100,10 +126,30 @@
handleTaskMovedToFront(taskInfo);
}
- public void handleTaskMovedToFront(TaskInfo taskInfo) {
+ void handleTaskMovedToFront(TaskInfo taskInfo) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
mOrderedTaskList.addFirst(taskInfo);
+ // Workaround for b/372067617, if the home task is being brought to front, then it will
+ // occlude all other tasks, so mark them as not-visible
+ if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
+ // We've moved the task to the front of the list above, so only iterate the tasks after
+ for (int i = 1; i < mOrderedTaskList.size(); i++) {
+ final TaskInfo info = mOrderedTaskList.get(i);
+ if (info.displayId != taskInfo.displayId) {
+ // Only fall through to reset visibility for tasks on the same display as the
+ // home task being brought forward
+ continue;
+ }
+ info.isVisible = false;
+ info.isVisibleRequested = false;
+ }
+ }
+
// Keep the home display's top running task in the first while adding a non-home
// display's task to the list, to avoid showing non-home display's task upon going to
// Recents animation.
@@ -131,8 +177,39 @@
}
}
+ /**
+ * Called when the set of visible tasks have changed.
+ */
+ public void onVisibleTasksChanged(GroupedTaskInfo[] visibleTasks) {
+ if (!com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
+ // TODO(346588978): Per-display info, just have everything in order by display
+
+ // Clear existing tasks for each display
+ mVisibleTasks.forEach((displayId, visibleTasksOnDisplay) -> visibleTasksOnDisplay.clear());
+
+ // Update the visible tasks on each display
+ for (int i = 0; i < visibleTasks.length; i++) {
+ final int displayId = visibleTasks[i].getTaskInfo1().getDisplayId();
+ final ArrayList<GroupedTaskInfo> displayTasks;
+ if (mVisibleTasks.containsKey(displayId)) {
+ displayTasks = mVisibleTasks.get(displayId);
+ } else {
+ displayTasks = new ArrayList<>();
+ mVisibleTasks.put(displayId, displayTasks);
+ }
+ displayTasks.add(visibleTasks[i]);
+ }
+ }
+
@Override
public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
mMainStagePosition.stagePosition = position;
} else {
@@ -141,6 +218,10 @@
}
public void onTaskChanged(RunningTaskInfo taskInfo) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
for (int i = 0; i < mOrderedTaskList.size(); i++) {
if (mOrderedTaskList.get(i).taskId == taskInfo.taskId) {
mOrderedTaskList.set(i, taskInfo);
@@ -151,6 +232,10 @@
@Override
public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
// If a task is not visible anymore or has been moved to undefined, stop tracking it.
if (!visible || stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
if (mMainStagePosition.taskId == taskId) {
@@ -161,7 +246,8 @@
return;
}
- if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
+ if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN
+ || (enableFlexibleSplit() && stage == STAGE_TYPE_A)) {
mMainStagePosition.taskId = taskId;
} else {
mSideStagePosition.taskId = taskId;
@@ -170,11 +256,19 @@
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
mPinnedTaskId = taskId;
}
@Override
public void onActivityUnpinned() {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
mPinnedTaskId = INVALID_TASK_ID;
}
@@ -183,21 +277,59 @@
* Will return empty array if device is not in staged split
*/
public int[] getRunningSplitTaskIds() {
- if (mMainStagePosition.taskId == INVALID_TASK_ID
- || mSideStagePosition.taskId == INVALID_TASK_ID) {
- return new int[]{};
- }
- int[] out = new int[2];
- if (mMainStagePosition.stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
- out[0] = mMainStagePosition.taskId;
- out[1] = mSideStagePosition.taskId;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): This assumes default display for now
+ final ArrayList<GroupedTaskInfo> visibleTasks = mVisibleTasks.get(DEFAULT_DISPLAY);
+ final GroupedTaskInfo splitTaskInfo = visibleTasks.stream()
+ .filter(taskInfo -> taskInfo.getType() == TYPE_SPLIT)
+ .findFirst().orElse(null);
+ if (splitTaskInfo != null && splitTaskInfo.getSplitBounds() != null) {
+ return new int[] {
+ splitTaskInfo.getSplitBounds().leftTopTaskId,
+ splitTaskInfo.getSplitBounds().rightBottomTaskId
+ };
+ }
+ return new int[0];
} else {
- out[1] = mMainStagePosition.taskId;
- out[0] = mSideStagePosition.taskId;
+ if (mMainStagePosition.taskId == INVALID_TASK_ID
+ || mSideStagePosition.taskId == INVALID_TASK_ID) {
+ return new int[]{};
+ }
+ int[] out = new int[2];
+ if (mMainStagePosition.stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ out[0] = mMainStagePosition.taskId;
+ out[1] = mSideStagePosition.taskId;
+ } else {
+ out[1] = mMainStagePosition.taskId;
+ out[0] = mSideStagePosition.taskId;
+ }
+ return out;
}
- return out;
}
+ /**
+ * Dumps the list of tasks in top task tracker.
+ */
+ public void dump(PrintWriter pw) {
+ if (!com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return;
+ }
+
+ // TODO(346588978): This assumes default display for now
+ final ArrayList<GroupedTaskInfo> displayTasks = mVisibleTasks.get(DEFAULT_DISPLAY);
+ pw.println("TopTaskTracker:");
+ pw.println(" tasks: [");
+ for (GroupedTaskInfo taskInfo : displayTasks) {
+ final TaskInfo info = taskInfo.getTaskInfo1();
+ final boolean isExcluded = (info.baseIntent.getFlags()
+ & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
+ pw.println(" " + info.taskId + ": excluded=" + isExcluded
+ + " visibleRequested=" + info.isVisibleRequested
+ + " visible=" + info.isVisible
+ + " " + info.baseIntent.getComponent());
+ }
+ pw.println(" ]");
+ }
/**
* Returns the CachedTaskInfo for the top most task
@@ -205,25 +337,35 @@
@NonNull
@UiThread
public CachedTaskInfo getCachedTopTask(boolean filterOnlyVisibleRecents) {
- if (filterOnlyVisibleRecents) {
- // Since we only know about the top most task, any filtering may not be applied on the
- // cache. The second to top task may change while the top task is still the same.
- RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.true", () ->
- ActivityManagerWrapper.getInstance().getRunningTasks(true));
- return new CachedTaskInfo(Arrays.asList(tasks));
- }
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Currently ignore filterOnlyVisibleRecents, but perhaps make this an
+ // explicit filter For things to ignore (ie. PIP/Bubbles/Assistant/etc/so that this is
+ // explicit)
+ // TODO(346588978): This assumes default display for now (as does all of Launcher)
+ final ArrayList<GroupedTaskInfo> displayTasks = mVisibleTasks.get(DEFAULT_DISPLAY);
+ return new CachedTaskInfo(new ArrayList<>(displayTasks));
+ } else {
+ if (filterOnlyVisibleRecents) {
+ // Since we only know about the top most task, any filtering may not be applied on
+ // the cache. The second to top task may change while the top task is still the
+ // same.
+ RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.true", () ->
+ ActivityManagerWrapper.getInstance().getRunningTasks(true));
+ return new CachedTaskInfo(Arrays.asList(tasks));
+ }
- if (mOrderedTaskList.isEmpty()) {
- RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.false", () ->
- ActivityManagerWrapper.getInstance().getRunningTasks(
- false /* filterOnlyVisibleRecents */));
- Collections.addAll(mOrderedTaskList, tasks);
- }
+ if (mOrderedTaskList.isEmpty()) {
+ RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.false", () ->
+ ActivityManagerWrapper.getInstance().getRunningTasks(
+ false /* filterOnlyVisibleRecents */));
+ Collections.addAll(mOrderedTaskList, tasks);
+ }
- ArrayList<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
- // Strip the pinned task and recents task
- tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
- return new CachedTaskInfo(tasks);
+ ArrayList<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
+ // Strip the pinned task and recents task
+ tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
+ return new CachedTaskInfo(tasks);
+ }
}
private static boolean isRecentsTask(TaskInfo task) {
@@ -237,24 +379,79 @@
*/
public static class CachedTaskInfo {
+ // Only used when enableShellTopTaskTracking() is disabled
@Nullable
private final TaskInfo mTopTask;
+ @Nullable
public final List<TaskInfo> mAllCachedTasks;
- CachedTaskInfo(List<TaskInfo> allCachedTasks) {
+ // Only used when enableShellTopTaskTracking() is enabled
+ @Nullable
+ private final GroupedTaskInfo mTopGroupedTask;
+ @Nullable
+ private final ArrayList<GroupedTaskInfo> mVisibleTasks;
+
+
+ // Only used when enableShellTopTaskTracking() is enabled
+ CachedTaskInfo(@NonNull ArrayList<GroupedTaskInfo> visibleTasks) {
+ mAllCachedTasks = null;
+ mTopTask = null;
+ mVisibleTasks = visibleTasks;
+ mTopGroupedTask = !mVisibleTasks.isEmpty() ? mVisibleTasks.getFirst() : null;
+
+ }
+
+ // Only used when enableShellTopTaskTracking() is disabled
+ CachedTaskInfo(@NonNull List<TaskInfo> allCachedTasks) {
+ mVisibleTasks = null;
+ mTopGroupedTask = null;
mAllCachedTasks = allCachedTasks;
mTopTask = allCachedTasks.isEmpty() ? null : allCachedTasks.get(0);
}
+ /**
+ * @return The list of visible tasks
+ */
+ public ArrayList<GroupedTaskInfo> getVisibleTasks() {
+ return mVisibleTasks;
+ }
+
+ /**
+ * @return The top task id
+ */
public int getTaskId() {
- return mTopTask == null ? INVALID_TASK_ID : mTopTask.taskId;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // Callers should use topGroupedTaskContainsTask() instead
+ return INVALID_TASK_ID;
+ } else {
+ return mTopTask != null ? mTopTask.taskId : INVALID_TASK_ID;
+ }
+ }
+
+ /**
+ * @return Whether the top grouped task contains the given {@param taskId} if
+ * Flags.enableShellTopTaskTracking() is true, otherwise it checks the top
+ * task as reported from TaskStackListener.
+ */
+ public boolean topGroupedTaskContainsTask(int taskId) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ return mTopGroupedTask != null && mTopGroupedTask.containsTask(taskId);
+ } else {
+ return mTopTask != null && mTopTask.taskId == taskId;
+ }
}
/**
* Returns true if the root of the task chooser activity
*/
public boolean isRootChooseActivity() {
- return mTopTask != null && ACTION_CHOOSER.equals(mTopTask.baseIntent.getAction());
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Update this to not make an assumption on a specific task info
+ return mTopGroupedTask != null && ACTION_CHOOSER.equals(
+ mTopGroupedTask.getTaskInfo1().baseIntent.getAction());
+ } else {
+ return mTopTask != null && ACTION_CHOOSER.equals(mTopTask.baseIntent.getAction());
+ }
}
/**
@@ -262,6 +459,10 @@
* is another running task that is not excluded from recents, returns that underlying task.
*/
public @Nullable CachedTaskInfo getVisibleNonExcludedTask() {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // Callers should not need this when the full set of visible tasks are provided
+ return null;
+ }
if (mTopTask == null
|| (mTopTask.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
// Not an excluded task.
@@ -278,24 +479,30 @@
}
/**
- * Returns true if this represents the HOME task
+ * Returns true if this represents the HOME activity type task
*/
public boolean isHomeTask() {
- return mTopTask != null && mTopTask.configuration.windowConfiguration
- .getActivityType() == ACTIVITY_TYPE_HOME;
- }
-
- public boolean isRecentsTask() {
- return TopTaskTracker.isRecentsTask(mTopTask);
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Update this to not make an assumption on a specific task info
+ return mTopGroupedTask != null
+ && mTopGroupedTask.getTaskInfo1().getActivityType() == ACTIVITY_TYPE_HOME;
+ } else {
+ return mTopTask != null && mTopTask.configuration.windowConfiguration
+ .getActivityType() == ACTIVITY_TYPE_HOME;
+ }
}
/**
- * Returns {@code true} if this task windowing mode is set to {@link
- * android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM}
+ * Returns true if this represents the RECENTS activity type task
*/
- public boolean isFreeformTask() {
- return mTopTask != null && mTopTask.configuration.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_FREEFORM;
+ public boolean isRecentsTask() {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Update this to not make an assumption on a specific task info
+ return mTopGroupedTask != null
+ && TopTaskTracker.isRecentsTask(mTopGroupedTask.getTaskInfo1());
+ } else {
+ return TopTaskTracker.isRecentsTask(mTopTask);
+ }
}
/**
@@ -303,43 +510,78 @@
* is loaded by the model
*/
public Task[] getPlaceholderTasks() {
- return mTopTask == null ? new Task[0]
- : new Task[]{Task.from(new TaskKey(mTopTask), mTopTask, false)};
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Update this to return more than a single task once the callers
+ // are refactored
+ if (mVisibleTasks.isEmpty()) {
+ return new Task[0];
+ }
+ final TaskInfo info = mVisibleTasks.getFirst().getTaskInfo1();
+ return new Task[]{Task.from(new TaskKey(info), info, false)};
+ } else {
+ return mTopTask == null ? new Task[0]
+ : new Task[]{Task.from(new TaskKey(mTopTask), mTopTask, false)};
+ }
}
/**
* Returns {@link Task} array corresponding to the provided task ids which can be used as a
* placeholder until the true object is loaded by the model
*/
- public Task[] getPlaceholderTasks(int[] taskIds) {
- if (mTopTask == null) {
- return new Task[0];
- }
- Task[] result = new Task[taskIds.length];
- for (int i = 0; i < taskIds.length; i++) {
- final int index = i;
- int taskId = taskIds[i];
- mAllCachedTasks.forEach(rti -> {
- if (rti.taskId == taskId) {
- result[index] = Task.from(new TaskKey(rti), rti, false);
- }
- });
- }
- return result;
- }
+ public Task[] getSplitPlaceholderTasks(int[] taskIds) {
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ if (mVisibleTasks.isEmpty()
+ || mVisibleTasks.getFirst().getType() != TYPE_SPLIT) {
+ return new Task[0];
+ }
- @UserIdInt
- @Nullable
- public Integer getUserId() {
- return mTopTask == null ? null : mTopTask.userId;
+ GroupedTaskInfo splitTask = mVisibleTasks.getFirst();
+ Task[] result = new Task[taskIds.length];
+ for (int i = 0; i < taskIds.length; i++) {
+ TaskInfo info = splitTask.getTaskById(taskIds[i]);
+ if (info == null) {
+ Log.w(TAG, "Requested task (" + taskIds[i] + ") not found");
+ return new Task[0];
+ }
+ result[i] = Task.from(new TaskKey(info), info, false);
+ }
+ return result;
+ } else {
+ if (mTopTask == null) {
+ return new Task[0];
+ }
+ Task[] result = new Task[taskIds.length];
+ for (int i = 0; i < taskIds.length; i++) {
+ final int index = i;
+ int taskId = taskIds[i];
+ mAllCachedTasks.forEach(rti -> {
+ if (rti.taskId == taskId) {
+ result[index] = Task.from(new TaskKey(rti), rti, false);
+ }
+ });
+ }
+ return result;
+ }
}
@Nullable
public String getPackageName() {
- if (mTopTask == null || mTopTask.baseActivity == null) {
- return null;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ // TODO(346588978): Update this to not make an assumption on a specific task info
+ if (mTopGroupedTask == null) {
+ return null;
+ }
+ final TaskInfo info = mTopGroupedTask.getTaskInfo1();
+ if (info.baseActivity == null) {
+ return null;
+ }
+ return info.baseActivity.getPackageName();
+ } else {
+ if (mTopTask == null || mTopTask.baseActivity == null) {
+ return null;
+ }
+ return mTopTask.baseActivity.getPackageName();
}
- return mTopTask.baseActivity.getPackageName();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ad5720f..d38eaf3 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
-import static com.android.launcher3.Flags.useActivityOverlay;
import static com.android.launcher3.LauncherPrefs.backedUpItem;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
@@ -35,12 +34,12 @@
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.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
+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;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
-import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
@@ -71,7 +70,6 @@
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
-import android.view.View;
import androidx.annotation.BinderThread;
import androidx.annotation.MainThread;
@@ -106,21 +104,9 @@
import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
-import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
-import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
-import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
-import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
-import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
-import com.android.quickstep.inputconsumers.OverviewInputConsumer;
-import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
-import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
-import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
-import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
-import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer;
-import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -959,7 +945,8 @@
+ "consuming gesture for assistant action");
mGestureState =
createGestureState(mGestureState, getTrackpadGestureType(event));
- mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
+ mUncheckedConsumer = tryCreateAssistantInputConsumer(
+ this, mDeviceState, mInputMonitorCompat, mGestureState, event);
} else {
reasonString.append(" but event cannot trigger Assistant, "
+ "consuming gesture as no-op");
@@ -978,7 +965,23 @@
getTrackpadGestureType(event));
mConsumer.onConsumerAboutToBeSwitched();
mGestureState = newGestureState;
- mConsumer = newConsumer(prevGestureState, mGestureState, event);
+ mConsumer = newConsumer(
+ getBaseContext(),
+ this,
+ mResetGestureInputConsumer,
+ mOverviewComponentObserver,
+ mDeviceState,
+ prevGestureState,
+ mGestureState,
+ mTaskAnimationManager,
+ mInputMonitorCompat,
+ getSwipeUpHandlerFactory(),
+ this::onConsumerInactive,
+ mInputEventReceiver,
+ mTaskbarManager,
+ mSwipeUpProxyProvider,
+ mOverviewCommandHelper,
+ event);
mUncheckedConsumer = mConsumer;
} else if ((mDeviceState.isFullyGesturalNavMode() || isTrackpadMultiFingerSwipe(event))
&& mDeviceState.canTriggerAssistantAction(event)) {
@@ -991,7 +994,8 @@
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
// should not interrupt it. QuickSwitch assumes that interruption can only
// happen if the next gesture is also quick switch.
- mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
+ mUncheckedConsumer = tryCreateAssistantInputConsumer(
+ this, mDeviceState, mInputMonitorCompat, mGestureState, event);
} else if (mDeviceState.canTriggerOneHandedAction(event)) {
reasonString.append("event can trigger one-handed action, "
+ "consuming gesture for one-handed action");
@@ -1073,28 +1077,6 @@
return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
}
- private InputConsumer tryCreateAssistantInputConsumer(
- GestureState gestureState, MotionEvent motionEvent) {
- return tryCreateAssistantInputConsumer(
- InputConsumer.NO_OP, gestureState, motionEvent, CompoundString.NO_OP);
- }
-
- private InputConsumer tryCreateAssistantInputConsumer(
- InputConsumer base,
- GestureState gestureState,
- MotionEvent motionEvent,
- CompoundString reasonString) {
- if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
- reasonString.append(
- "%sis gesture-blocked task, using base input consumer", SUBSTRING_PREFIX);
- return base;
- } else {
- reasonString.append("%susing AssistantInputConsumer", SUBSTRING_PREFIX);
- return new AssistantInputConsumer(
- this, gestureState, base, mInputMonitorCompat, mDeviceState, motionEvent);
- }
- }
-
public GestureState createGestureState(GestureState previousGestureState,
GestureState.TrackpadGestureType trackpadGestureType) {
final GestureState gestureState;
@@ -1125,310 +1107,6 @@
return gestureState;
}
- private InputConsumer newConsumer(
- GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
- TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
- BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
- if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
- InputConsumer consumer = new BubbleBarInputConsumer(this, bubbleControllers,
- mInputMonitorCompat);
- logInputConsumerSelectionReason(consumer, newCompoundString(
- "event is on bubbles, creating new input consumer"));
- return consumer;
- }
- AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
- if (progressProxy != null) {
- InputConsumer consumer = new ProgressDelegateInputConsumer(
- this, mTaskAnimationManager, mGestureState, mInputMonitorCompat, progressProxy);
-
- logInputConsumerSelectionReason(consumer, newCompoundString(
- "mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"));
-
- return consumer;
- }
-
- boolean canStartSystemGesture =
- mGestureState.isTrackpadGesture() ? mDeviceState.canStartTrackpadGesture()
- : mDeviceState.canStartSystemGesture();
-
- if (!LockedUserState.get(this).isUserUnlocked()) {
- CompoundString reasonString = newCompoundString("device locked");
- InputConsumer consumer;
- if (canStartSystemGesture) {
- // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
- // launched while device is locked even after exiting direct boot mode (e.g. camera).
- consumer = createDeviceLockedInputConsumer(
- newGestureState,
- reasonString.append("%scan start system gesture", SUBSTRING_PREFIX));
- } else {
- consumer = getDefaultInputConsumer(
- reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX));
- }
- logInputConsumerSelectionReason(consumer, reasonString);
- return consumer;
- }
-
- CompoundString reasonString;
- InputConsumer base;
- // When there is an existing recents animation running, bypass systemState check as this is
- // a followup gesture and the first gesture started in a valid system state.
- if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning()) {
- reasonString = newCompoundString(canStartSystemGesture
- ? "can start system gesture, trying to use base consumer"
- : "recents animation was running, trying to use base consumer");
- base = newBaseConsumer(previousGestureState, newGestureState, event, reasonString);
- } else {
- reasonString = newCompoundString("cannot start system gesture and recents "
- + "animation was not running, trying to use default input consumer");
- base = getDefaultInputConsumer(reasonString);
- }
- if (mDeviceState.isGesturalNavMode() || newGestureState.isTrackpadGesture()) {
- handleOrientationSetup(base);
- }
- if (mDeviceState.isFullyGesturalNavMode() || newGestureState.isTrackpadGesture()) {
- String reasonPrefix =
- "device is in gesture navigation mode or 3-button mode with a trackpad gesture";
- if (mDeviceState.canTriggerAssistantAction(event)) {
- reasonString.append("%s%s%sgesture can trigger the assistant, "
- + "trying to use assistant input consumer",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString);
- }
-
- // If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
- if (tac != null && !(base instanceof AssistantInputConsumer)) {
- // Present always on large screen or on small screen w/ flag
- boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent
- && !tac.isPhoneMode()
- && !tac.isInStashedLauncherState();
- if (canStartSystemGesture && useTaskbarConsumer) {
- reasonString.append("%s%s%sTaskbarActivityContext != null, "
- + "using TaskbarUnstashInputConsumer",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
- mOverviewCommandHelper, mGestureState);
- }
- }
- if (enableBubblesLongPressNavHandle()) {
- // Create bubbles input consumer before NavHandleLongPressInputConsumer.
- // This allows for nav handle to fall back to bubbles.
- if (mDeviceState.isBubblesExpanded()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%sbubbles expanded, trying to use default input consumer",
- SUBSTRING_PREFIX);
- // Bubbles can handle home gesture itself.
- base = getDefaultInputConsumer(reasonString);
- }
- }
-
- NavHandle navHandle = tac != null ? tac.getNavHandle()
- : SystemUiProxy.INSTANCE.get(this);
- if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
- && navHandle.canNavHandleBeLongPressed()
- && !ignoreThreeFingerTrackpadForNavHandleLongPress(mGestureState)) {
- reasonString.append("%s%s%sNot running recents animation, ",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- if (tac != null && tac.getNavHandle().canNavHandleBeLongPressed()) {
- reasonString.append("stashed handle is long-pressable, ");
- }
- reasonString.append("using NavHandleLongPressInputConsumer");
- base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
- mDeviceState, navHandle, mGestureState);
- }
-
- if (!enableBubblesLongPressNavHandle()) {
- // Continue overriding nav handle input consumer with bubbles
- if (mDeviceState.isBubblesExpanded()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%sbubbles expanded, trying to use default input consumer",
- SUBSTRING_PREFIX);
- // Bubbles can handle home gesture itself.
- base = getDefaultInputConsumer(reasonString);
- }
- }
-
- if (mDeviceState.isSystemUiDialogShowing()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%ssystem dialog is showing, using SysUiOverlayInputConsumer",
- SUBSTRING_PREFIX);
- base = new SysUiOverlayInputConsumer(
- getBaseContext(), mDeviceState, mInputMonitorCompat);
- }
-
- if (mGestureState.isTrackpadGesture()
- && canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%sTrackpad 3-finger gesture, using TrackpadStatusBarInputConsumer",
- SUBSTRING_PREFIX);
- base = new TrackpadStatusBarInputConsumer(getBaseContext(), base,
- mInputMonitorCompat);
- }
-
- if (mDeviceState.isScreenPinningActive()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%sscreen pinning is active, using ScreenPinnedInputConsumer",
- SUBSTRING_PREFIX);
- // Note: we only allow accessibility to wrap this, and it replaces the previous
- // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
- base = new ScreenPinnedInputConsumer(this, newGestureState);
- }
-
- if (mDeviceState.canTriggerOneHandedAction(event)) {
- reasonString.append("%s%s%sgesture can trigger one handed mode, "
- + "using OneHandedModeInputConsumer",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- base = new OneHandedModeInputConsumer(
- this, mDeviceState, base, mInputMonitorCompat);
- }
-
- if (mDeviceState.isAccessibilityMenuAvailable()) {
- reasonString.append(
- "%s%s%saccessibility menu is available, using AccessibilityInputConsumer",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- base = new AccessibilityInputConsumer(
- this, mDeviceState, mGestureState, base, mInputMonitorCompat);
- }
- } else {
- String reasonPrefix = "device is not in gesture navigation mode";
- if (mDeviceState.isScreenPinningActive()) {
- reasonString = newCompoundString(reasonPrefix).append(
- "%sscreen pinning is active, trying to use default input consumer",
- SUBSTRING_PREFIX);
- base = getDefaultInputConsumer(reasonString);
- }
-
- if (mDeviceState.canTriggerOneHandedAction(event)) {
- reasonString.append("%s%s%sgesture can trigger one handed mode, "
- + "using OneHandedModeInputConsumer",
- NEWLINE_PREFIX,
- reasonPrefix,
- SUBSTRING_PREFIX);
- base = new OneHandedModeInputConsumer(
- this, mDeviceState, base, mInputMonitorCompat);
- }
- }
- logInputConsumerSelectionReason(base, reasonString);
- return base;
- }
-
- private CompoundString newCompoundString(String substring) {
- return new CompoundString("%s%s", NEWLINE_PREFIX, substring);
- }
-
- private boolean ignoreThreeFingerTrackpadForNavHandleLongPress(GestureState gestureState) {
- return Flags.ignoreThreeFingerTrackpadForNavHandleLongPress()
- && gestureState.isThreeFingerTrackpadGesture();
- }
-
- private void logInputConsumerSelectionReason(
- InputConsumer consumer, CompoundString reasonString) {
- ActiveGestureProtoLogProxy.logSetInputConsumer(consumer.getName(), reasonString.toString());
- if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
- ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER);
- }
- }
-
- private void handleOrientationSetup(InputConsumer baseInputConsumer) {
- baseInputConsumer.notifyOrientationSetup();
- }
-
- private InputConsumer newBaseConsumer(
- GestureState previousGestureState,
- GestureState gestureState,
- MotionEvent event,
- CompoundString reasonString) {
- if (mDeviceState.isKeyguardShowingOccluded()) {
- // This handles apps showing over the lockscreen (e.g. camera)
- return createDeviceLockedInputConsumer(gestureState, reasonString.append(
- "%skeyguard is showing occluded, trying to use device locked input consumer",
- SUBSTRING_PREFIX));
- }
-
- reasonString.append("%skeyguard is not showing occluded", SUBSTRING_PREFIX);
-
- TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask();
- // Use overview input consumer for sharesheets on top of home.
- boolean forceOverviewInputConsumer = gestureState.getContainerInterface().isStarted()
- && runningTask != null
- && runningTask.isRootChooseActivity();
-
- // In the case where we are in an excluded, translucent overlay, ignore it and treat the
- // running activity as the task behind the overlay.
- TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null
- ? null
- : runningTask.getVisibleNonExcludedTask();
- if (otherVisibleTask != null) {
- ActiveGestureProtoLogProxy.logUpdateGestureStateRunningTask(
- otherVisibleTask.getPackageName(), runningTask.getPackageName());
- gestureState.updateRunningTask(otherVisibleTask);
- }
-
- boolean previousGestureAnimatedToLauncher =
- previousGestureState.isRunningAnimationToLauncher()
- || mDeviceState.isPredictiveBackToHomeInProgress();
- // with shell-transitions, home is resumed during recents animation, so
- // explicitly check against recents animation too.
- boolean launcherResumedThroughShellTransition =
- gestureState.getContainerInterface().isResumed()
- && !previousGestureState.isRecentsAnimationRunning();
- // If a task fragment within Launcher is resumed
- boolean launcherChildActivityResumed = useActivityOverlay()
- && runningTask != null
- && runningTask.isHomeTask()
- && mOverviewComponentObserver.isHomeAndOverviewSame()
- && !launcherResumedThroughShellTransition
- && !previousGestureState.isRecentsAnimationRunning();
-
- if (gestureState.getContainerInterface().isInLiveTileMode()) {
- return createOverviewInputConsumer(
- previousGestureState,
- gestureState,
- event,
- forceOverviewInputConsumer,
- reasonString.append(
- "%sis in live tile mode, trying to use overview input consumer",
- SUBSTRING_PREFIX));
- } else if (runningTask == null) {
- return getDefaultInputConsumer(reasonString.append(
- "%srunning task == null", SUBSTRING_PREFIX));
- } else if (previousGestureAnimatedToLauncher
- || launcherResumedThroughShellTransition
- || forceOverviewInputConsumer) {
- return createOverviewInputConsumer(
- previousGestureState,
- gestureState,
- event,
- forceOverviewInputConsumer,
- reasonString.append(previousGestureAnimatedToLauncher
- ? "%sprevious gesture animated to launcher, "
- + "trying to use overview input consumer"
- : (launcherResumedThroughShellTransition
- ? "%slauncher resumed through a shell transition, "
- + "trying to use overview input consumer"
- : "%sforceOverviewInputConsumer == true, "
- + "trying to use overview input consumer"),
- SUBSTRING_PREFIX));
- } else if (mDeviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
- return getDefaultInputConsumer(reasonString.append(launcherChildActivityResumed
- ? "%sis launcher child-task, trying to use default input consumer"
- : "%sis gesture-blocked task, trying to use default input consumer",
- SUBSTRING_PREFIX));
- } else {
- reasonString.append("%susing OtherActivityInputConsumer", SUBSTRING_PREFIX);
- return createOtherActivityInputConsumer(gestureState, event);
- }
- }
-
public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
boolean recentsInWindow =
Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow();
@@ -1437,80 +1115,6 @@
? mRecentsWindowSwipeHandlerFactory : mFallbackSwipeHandlerFactory);
}
- private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
- MotionEvent event) {
-
- final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory();
- final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
- || gestureState.getContainerInterface().deferStartingActivity(mDeviceState, event);
- final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
- return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
- gestureState, shouldDefer, this::onConsumerInactive,
- mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
- }
-
- private InputConsumer createDeviceLockedInputConsumer(
- GestureState gestureState, CompoundString reasonString) {
- if ((mDeviceState.isFullyGesturalNavMode() || gestureState.isTrackpadGesture())
- && gestureState.getRunningTask() != null) {
- reasonString.append("%sdevice is in gesture nav mode or 3-button mode with a trackpad "
- + "gesture and running task != null, using DeviceLockedInputConsumer",
- SUBSTRING_PREFIX);
- return new DeviceLockedInputConsumer(
- this, mDeviceState, mTaskAnimationManager, gestureState, mInputMonitorCompat);
- } else {
- return getDefaultInputConsumer(reasonString.append(
- mDeviceState.isFullyGesturalNavMode() || gestureState.isTrackpadGesture()
- ? "%srunning task == null, trying to use default input consumer"
- : "%sdevice is not in gesture nav mode and it's not a trackpad gesture,"
- + " trying to use default input consumer",
- SUBSTRING_PREFIX));
- }
- }
-
- public InputConsumer createOverviewInputConsumer(
- GestureState previousGestureState,
- GestureState gestureState,
- MotionEvent event,
- boolean forceOverviewInputConsumer,
- CompoundString reasonString) {
- RecentsViewContainer container = gestureState.getContainerInterface().getCreatedContainer();
- if (container == null) {
- return getDefaultInputConsumer(reasonString.append(
- "%sactivity == null, trying to use default input consumer", SUBSTRING_PREFIX));
- }
-
- View rootview = container.getRootView();
- boolean hasWindowFocus = rootview != null && rootview.hasWindowFocus();
- boolean isPreviousGestureAnimatingToLauncher =
- previousGestureState.isRunningAnimationToLauncher()
- || mDeviceState.isPredictiveBackToHomeInProgress();
- boolean isInLiveTileMode = gestureState.getContainerInterface().isInLiveTileMode();
-
- reasonString.append(hasWindowFocus
- ? "%sactivity has window focus"
- : (isPreviousGestureAnimatingToLauncher
- ? "%sprevious gesture is still animating to launcher"
- : isInLiveTileMode
- ? "%sdevice is in live mode"
- : "%sall overview focus conditions failed"), SUBSTRING_PREFIX);
- if (hasWindowFocus
- || isPreviousGestureAnimatingToLauncher
- || isInLiveTileMode) {
- reasonString.append(
- "%soverview should have focus, using OverviewInputConsumer", SUBSTRING_PREFIX);
- return new OverviewInputConsumer(gestureState, container, mInputMonitorCompat,
- false /* startingInActivityBounds */);
- } else {
- reasonString.append(
- "%soverview shouldn't have focus, using OverviewWithoutFocusInputConsumer",
- SUBSTRING_PREFIX);
- final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
- return new OverviewWithoutFocusInputConsumer(container.asContext(), mDeviceState,
- gestureState, mInputMonitorCompat, disableHorizontalSwipe);
- }
- }
-
/**
* To be called by the consumer when it's no longer active. This can be called by any consumer
* in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
@@ -1672,6 +1276,7 @@
ContextualSearchStateManager.INSTANCE.get(this).dump("\t", pw);
SystemUiProxy.INSTANCE.get(this).dump(pw);
DeviceConfigWrapper.get().dump(" ", pw);
+ TopTaskTracker.INSTANCE.get(this).dump(pw);
}
private AbsSwipeUpHandler createLauncherSwipeHandler(
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index 4f9d837..c1d3f6e 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -149,7 +149,8 @@
if (mActiveAnimationFactory != null) {
return;
}
- setHomeScaleAndAlpha(builder, app, mCurrentShift.value, 0);
+ setHomeScaleAndAlpha(builder, app, mCurrentShift.value,
+ Utilities.boundToRange(1 - mCurrentShift.value, 0, 1));
}
private void setHomeScaleAndAlpha(SurfaceProperties builder,
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index dd11d48..b78e214 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -36,9 +36,6 @@
import com.android.quickstep.task.viewmodel.TaskOverlayViewModel
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModelImpl
-import com.android.quickstep.task.viewmodel.TaskViewData
-import com.android.quickstep.task.viewmodel.TaskViewModel
-import com.android.quickstep.views.TaskViewType
import com.android.systemui.shared.recents.model.Task
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
@@ -186,17 +183,11 @@
}
}
RecentsViewData::class.java -> RecentsViewData()
- TaskViewModel::class.java -> TaskViewModel(taskViewData = inject(scopeId, extras))
- TaskViewData::class.java -> {
- val taskViewType = extras["TaskViewType"] as TaskViewType
- TaskViewData(taskViewType)
- }
TaskContainerData::class.java -> TaskContainerData()
TaskThumbnailViewData::class.java -> TaskThumbnailViewData()
TaskThumbnailViewModel::class.java ->
TaskThumbnailViewModelImpl(
recentsViewData = inject(),
- taskViewData = inject(scopeId, extras),
taskContainerData = inject(scopeId),
dispatcherProvider = inject(),
getThumbnailPositionUseCase = inject(),
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt
index 87446b0..6ccf372 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt
@@ -22,9 +22,6 @@
class RecentsViewData {
val fullscreenProgress = MutableStateFlow(1f)
- // This is typically a View concern but it is used to invalidate rendering in other Views
- val scale = MutableStateFlow(1f)
-
// Whether the current RecentsView state supports task overlays.
// TODO(b/331753115): Derive from RecentsView state flow once migrated to MVVM.
val overlayEnabled = MutableStateFlow(false)
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index c511005..cfebb81 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -34,10 +34,6 @@
recentsTasksRepository.setVisibleTasks(visibleTaskIdList.toSet())
}
- fun updateScale(scale: Float) {
- recentsViewData.scale.value = scale
- }
-
fun updateFullscreenProgress(fullscreenProgress: Float) {
recentsViewData.fullscreenProgress.value = fullscreenProgress
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index a8c8659..0c783d3 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -17,7 +17,6 @@
package com.android.quickstep.task.thumbnail
import android.content.Context
-import android.content.res.Configuration
import android.graphics.Color
import android.graphics.Outline
import android.graphics.Rect
@@ -29,7 +28,6 @@
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isInvisible
import com.android.launcher3.R
-import com.android.launcher3.Utilities
import com.android.launcher3.util.ViewPool
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
@@ -39,9 +37,7 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
-import com.android.quickstep.util.TaskCornerRadius
import com.android.quickstep.views.FixedSizeImageView
-import com.android.systemui.shared.system.QuickStepContract
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -63,18 +59,15 @@
private val splashIcon: FixedSizeImageView by lazy { findViewById(R.id.splash_icon) }
private var uiState: TaskThumbnailUiState = Uninitialized
- private var inheritedScale: Float = 1f
- private val _measuredBounds = Rect()
- private val measuredBounds: Rect
- get() {
- _measuredBounds.set(0, 0, measuredWidth, measuredHeight)
- return _measuredBounds
+ private val bounds = Rect()
+
+ var cornerRadius: Float = 0f
+ set(value) {
+ field = value
+ invalidateOutline()
}
- private var overviewCornerRadius: Float = TaskCornerRadius.get(context)
- private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
-
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
@@ -114,19 +107,12 @@
splashIcon.alpha = splashAlpha
}
.launchIn(viewAttachedScope)
- viewModel.cornerRadiusProgress.onEach { invalidateOutline() }.launchIn(viewAttachedScope)
- viewModel.inheritedScale
- .onEach { viewModelInheritedScale ->
- inheritedScale = viewModelInheritedScale
- invalidateOutline()
- }
- .launchIn(viewAttachedScope)
clipToOutline = true
outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(measuredBounds, getCurrentCornerRadius())
+ outline.setRoundRect(bounds, cornerRadius)
}
}
}
@@ -157,6 +143,8 @@
if (uiState is SnapshotSplash) {
setImageMatrix()
}
+ bounds.set(0, 0, w, h)
+ invalidateOutline()
}
override fun setScaleX(scaleX: Float) {
@@ -171,14 +159,6 @@
splashIcon.scaleY = 1 / scaleY
}
- override fun onConfigurationChanged(newConfig: Configuration?) {
- super.onConfigurationChanged(newConfig)
-
- overviewCornerRadius = TaskCornerRadius.get(context)
- fullscreenCornerRadius = QuickStepContract.getWindowCornerRadius(context)
- invalidateOutline()
- }
-
private fun resetViews() {
liveTileView.isInvisible = true
thumbnailView.isInvisible = true
@@ -214,13 +194,6 @@
thumbnailView.imageMatrix = viewModel.getThumbnailPositionState(width, height, isLayoutRtl)
}
- private fun getCurrentCornerRadius() =
- Utilities.mapRange(
- viewModel.cornerRadiusProgress.value,
- overviewCornerRadius,
- fullscreenCornerRadius,
- ) / inheritedScale
-
private companion object {
const val TAG = "TaskThumbnailView"
}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
index f55462a..a048a1d 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
@@ -19,19 +19,9 @@
import android.graphics.Matrix
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
/** ViewModel for representing TaskThumbnails */
interface TaskThumbnailViewModel {
- /**
- * Progress for changes in corner radius. progress: 0 = overview corner radius; 1 = fullscreen
- * corner radius.
- */
- val cornerRadiusProgress: StateFlow<Float>
-
- /** The accumulated View.scale value for parent Views up to and including RecentsView */
- val inheritedScale: Flow<Float>
-
/** Provides the level of dimming that the View should have */
val dimProgress: Flow<Float>
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
index 8b15a82..b6cb984 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
@@ -38,7 +38,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
@@ -50,7 +49,6 @@
@OptIn(ExperimentalCoroutinesApi::class)
class TaskThumbnailViewModelImpl(
recentsViewData: RecentsViewData,
- taskViewData: TaskViewData,
taskContainerData: TaskContainerData,
dispatcherProvider: DispatcherProvider,
private val tasksRepository: RecentTasksRepository,
@@ -61,15 +59,6 @@
private val splashProgress = MutableStateFlow(flowOf(0f))
private var taskId: Int = INVALID_TASK_ID
- override val cornerRadiusProgress =
- if (taskViewData.isOutlineFormedByThumbnailView) recentsViewData.fullscreenProgress
- else MutableStateFlow(1f).asStateFlow()
-
- override val inheritedScale =
- combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
- recentsScale * taskScale
- }
-
override val dimProgress: Flow<Float> =
combine(taskContainerData.taskMenuOpenProgress, recentsViewData.tintAmount) {
taskMenuOpenProgress,
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
deleted file mode 100644
index 7a9ecf2..0000000
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.task.viewmodel
-
-import com.android.quickstep.views.TaskViewType
-import kotlinx.coroutines.flow.MutableStateFlow
-
-class TaskViewData(taskViewType: TaskViewType) {
- // This is typically a View concern but it is used to invalidate rendering in other Views
- val scale = MutableStateFlow(1f)
-
- // TODO(b/331753115): This property should not be in TaskViewData once TaskView is MVVM.
- /** Whether outline of TaskView is formed by outline thumbnail view(s). */
- val isOutlineFormedByThumbnailView: Boolean = taskViewType != TaskViewType.DESKTOP
-}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
deleted file mode 100644
index ec75d59..0000000
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.task.viewmodel
-
-import androidx.lifecycle.ViewModel
-
-class TaskViewModel(private val taskViewData: TaskViewData) : ViewModel() {
- fun updateScale(scale: Float) {
- taskViewData.scale.value = scale
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 7388d59..1312aa4 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -409,8 +409,8 @@
);
} else {
// Tapped an app pair while in a single app
- int runningTaskId = topTaskTracker
- .getCachedTopTask(false /* filterOnlyVisibleRecents */).getTaskId();
+ final TopTaskTracker.CachedTaskInfo runningTask = topTaskTracker
+ .getCachedTopTask(false /* filterOnlyVisibleRecents */);
mSplitSelectStateController.findLastActiveTasksAndRunCallback(
componentKeys,
@@ -418,10 +418,21 @@
foundTasks -> {
Task foundTask1 = foundTasks[0];
Task foundTask2 = foundTasks[1];
- boolean task1IsOnScreen =
- foundTask1 != null && foundTask1.getKey().getId() == runningTaskId;
- boolean task2IsOnScreen =
- foundTask2 != null && foundTask2.getKey().getId() == runningTaskId;
+ boolean task1IsOnScreen;
+ boolean task2IsOnScreen;
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ task1IsOnScreen = foundTask1 != null
+ && runningTask.topGroupedTaskContainsTask(
+ foundTask1.getKey().getId());
+ task2IsOnScreen = foundTask2 != null
+ && runningTask.topGroupedTaskContainsTask(
+ foundTask2.getKey().getId());
+ } else {
+ task1IsOnScreen = foundTask1 != null && foundTask1.getKey().getId()
+ == runningTask.getTaskId();
+ task2IsOnScreen = foundTask2 != null && foundTask2.getKey().getId()
+ == runningTask.getTaskId();
+ }
if (!task1IsOnScreen && !task2IsOnScreen) {
// Neither App A nor App B are on-screen, launch the app pair normally.
diff --git a/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java b/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java
index 083f192..334ff06 100644
--- a/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_SEARCH_SCREEN;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
@@ -78,7 +77,6 @@
this::onContextualSearchSettingChanged;
protected final EventLogArray mEventLogArray = new EventLogArray(TAG, MAX_DEBUG_EVENT_SIZE);
- @Nullable private SettingsCache mSettingsCache;
// Cached value whether the ContextualSearch intent filter matched any enabled components.
private boolean mIsContextualSearchIntentAvailable;
private boolean mIsContextualSearchSettingEnabled;
@@ -108,11 +106,10 @@
context, mContextualSearchPackage, Intent.ACTION_PACKAGE_ADDED,
Intent.ACTION_PACKAGE_CHANGED, Intent.ACTION_PACKAGE_REMOVED);
- mSettingsCache = SettingsCache.INSTANCE.get(context);
- mSettingsCache.register(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI,
+ SettingsCache.INSTANCE.get(context).register(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI,
mContextualSearchSettingChangedListener);
onContextualSearchSettingChanged(
- mSettingsCache.getValue(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI));
+ SettingsCache.INSTANCE.get(context).getValue(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI));
SystemUiProxy.INSTANCE.get(mContext).addOnStateChangeListener(mSysUiStateChangeListener);
}
@@ -266,11 +263,8 @@
public void close() {
mContextualSearchPackageReceiver.unregisterReceiverSafely(mContext);
unregisterSearchScreenSystemAction();
-
- if (mSettingsCache != null) {
- mSettingsCache.unregister(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI,
- mContextualSearchSettingChangedListener);
- }
+ SettingsCache.INSTANCE.get(mContext).unregister(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI,
+ mContextualSearchSettingChangedListener);
SystemUiProxy.INSTANCE.get(mContext).removeOnStateChangeListener(mSysUiStateChangeListener);
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index ea582c4..d35a36a 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -163,6 +163,8 @@
*/
private Pair<InstanceId, com.android.launcher3.logging.InstanceId> mSessionInstanceIds;
+ private boolean mIsDestroyed = false;
+
private final BackPressHandler mSplitBackHandler = new BackPressHandler() {
@Override
public boolean canHandleBack() {
@@ -199,6 +201,7 @@
public void onDestroy() {
mContainer = null;
+ mIsDestroyed = true;
mActivityBackCallback = null;
mAppPairsController.onDestroy();
mSplitSelectDataHolder.onDestroy();
@@ -744,7 +747,9 @@
*/
public void resetState() {
mSplitSelectDataHolder.resetState();
- mContainer.<RecentsView>getOverviewPanel().resetDesktopTaskFromSplitSelectState();
+ if (!mIsDestroyed) {
+ mContainer.<RecentsView>getOverviewPanel().resetDesktopTaskFromSplitSelectState();
+ }
dispatchOnSplitSelectionExit();
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 997a842..12ca257 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -49,6 +49,7 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DynamicResource;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.ResourceProvider;
@@ -63,8 +64,7 @@
private static final int APP_CLOSE_ROW_START_DELAY_MS = 10;
// Should be used for animations running alongside this StaggeredWorkspaceAnim.
public static final int DURATION_MS = 250;
- public static final int DURATION_TASKBAR_MS =
- QuickstepTransitionManager.getTaskbarToHomeDuration();
+ private final int mTaskbarDurationInMs;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -81,6 +81,8 @@
public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity,
boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) {
+ mTaskbarDurationInMs = QuickstepTransitionManager.getTaskbarToHomeDuration(
+ DisplayController.isPinnedTaskbar(launcher));
prepareToAnimate(launcher, animateOverviewScrim);
mIgnoredView = ignoredView;
@@ -93,7 +95,7 @@
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);
DeviceProfile grid = launcher.getDeviceProfile();
- long duration = grid.isTaskbarPresent ? DURATION_TASKBAR_MS : DURATION_MS;
+ long duration = grid.isTaskbarPresent ? mTaskbarDurationInMs : DURATION_MS;
if (staggerWorkspace) {
Workspace<?> workspace = launcher.getWorkspace();
Hotseat hotseat = launcher.getHotseat();
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index a4b8fec..706cfe4 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -50,9 +50,10 @@
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.BaseContainerInterface;
+import com.android.quickstep.DesktopFullscreenDrawParams;
+import com.android.quickstep.FullscreenDrawParams;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
-import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
@@ -116,20 +117,25 @@
private SplitBounds mSplitBounds;
private Boolean mDrawsBelowRecents = null;
private boolean mIsGridTask;
- private boolean mIsDesktopTask;
+ private final boolean mIsDesktopTask;
private boolean mScaleToCarouselTaskSize = false;
private int mTaskRectTranslationX;
private int mTaskRectTranslationY;
private int mDesktopTaskIndex = 0;
- public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy) {
+ public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy,
+ boolean isDesktop, int desktopTaskIndex) {
mContext = context;
mSizeStrategy = sizeStrategy;
+ mIsDesktopTask = isDesktop;
+ mDesktopTaskIndex = desktopTaskIndex;
mOrientationState = TraceHelper.allowIpcs("TaskViewSimulator.init",
() -> new RecentsOrientedState(context, sizeStrategy, i -> { }));
mOrientationState.setGestureActive(true);
- mCurrentFullscreenParams = new FullscreenDrawParams(context);
+ mCurrentFullscreenParams = mIsDesktopTask
+ ? new DesktopFullscreenDrawParams(context)
+ : new FullscreenDrawParams(context);
mOrientationStateId = mOrientationState.getStateId();
Resources resources = context.getResources();
mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
@@ -289,14 +295,6 @@
}
/**
- * Sets whether this task is part of desktop tasks in overview.
- */
- public void setIsDesktopTask(boolean desktop, int index) {
- mIsDesktopTask = desktop;
- mDesktopTaskIndex = index;
- }
-
- /**
* Apply translations on TaskRect's starting location.
*/
public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) {
@@ -558,7 +556,7 @@
* TaskView
*/
public float getCurrentCornerRadius() {
- float visibleRadius = mCurrentFullscreenParams.getCurrentDrawnCornerRadius();
+ float visibleRadius = mCurrentFullscreenParams.getCurrentCornerRadius();
mTempPoint[0] = visibleRadius;
mTempPoint[1] = 0;
mInversePositionMatrix.mapVectors(mTempPoint);
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt
index 481acac..ef044f4 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt
@@ -23,14 +23,15 @@
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.FrameLayout
-import com.android.quickstep.views.TaskView.FullscreenDrawParams
class DesktopTaskContentView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) {
- private val currentFullscreenParams = FullscreenDrawParams(context)
- private val taskCornerRadius: Float
- get() = currentFullscreenParams.cornerRadius
+ var cornerRadius: Float = 0f
+ set(value) {
+ field = value
+ invalidateOutline()
+ }
private val bounds = Rect()
@@ -39,7 +40,7 @@
outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(bounds, taskCornerRadius)
+ outline.setRoundRect(bounds, cornerRadius)
}
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 5e842aa..576a56e 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -20,13 +20,10 @@
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
import android.util.Log
import android.view.Gravity
import android.view.View
-import android.widget.FrameLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.updateLayoutParams
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
@@ -39,6 +36,8 @@
import com.android.launcher3.util.ViewPool
import com.android.launcher3.util.rects.set
import com.android.quickstep.BaseContainerInterface
+import com.android.quickstep.DesktopFullscreenDrawParams
+import com.android.quickstep.FullscreenDrawParams
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.ViewUtils
import com.android.quickstep.task.thumbnail.TaskThumbnailView
@@ -47,14 +46,13 @@
/** TaskView that contains all tasks that are part of the desktop. */
class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
- TaskView(context, attrs, type = TaskViewType.DESKTOP) {
-
- private val snapshotDrawParams =
- object : FullscreenDrawParams(context) {
- // DesktopTaskView thumbnail's corner radius is independent of fullscreenProgress.
- override fun computeTaskCornerRadius(context: Context) =
- computeWindowCornerRadius(context)
- }
+ TaskView(
+ context,
+ attrs,
+ type = TaskViewType.DESKTOP,
+ thumbnailFullscreenParams = DesktopFullscreenDrawParams(context),
+ ) {
+ private val contentViewFullscreenParams = FullscreenDrawParams(context)
private val taskThumbnailViewDeprecatedPool =
if (!enableRefactorTaskThumbnail()) {
@@ -80,28 +78,12 @@
private val tempPointF = PointF()
private val tempRect = Rect()
- private lateinit var backgroundView: View
private lateinit var iconView: TaskViewIcon
- private lateinit var contentView: FrameLayout
+ private lateinit var contentView: DesktopTaskContentView
+ private lateinit var backgroundView: View
override fun onFinishInflate() {
super.onFinishInflate()
- backgroundView =
- findViewById<View>(R.id.background).apply {
- updateLayoutParams<LayoutParams> {
- topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
- }
- background =
- ShapeDrawable(RoundRectShape(FloatArray(8) { taskCornerRadius }, null, null))
- .apply {
- setTint(
- resources.getColor(
- android.R.color.system_neutral2_300,
- context.theme,
- )
- )
- }
- }
iconView =
getOrInflateIconView(R.id.icon).apply {
setIcon(
@@ -115,10 +97,15 @@
setText(resources.getText(R.string.recent_task_desktop))
}
contentView =
- findViewById<FrameLayout>(R.id.desktop_content).apply {
+ findViewById<DesktopTaskContentView>(R.id.desktop_content).apply {
updateLayoutParams<LayoutParams> {
topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
}
+ cornerRadius = contentViewFullscreenParams.currentCornerRadius
+ backgroundView = findViewById(R.id.background)
+ backgroundView.setBackgroundColor(
+ resources.getColor(android.R.color.system_neutral2_300, context.theme)
+ )
}
}
@@ -135,6 +122,7 @@
Log.d(TAG, sb.toString())
}
cancelPendingLoadTasks()
+ val backgroundViewIndex = contentView.indexOfChild(backgroundView)
taskContainers =
tasks.map { task ->
val snapshotView =
@@ -143,7 +131,7 @@
} else {
taskThumbnailViewDeprecatedPool!!.view
}
- contentView.addView(snapshotView, 0)
+ contentView.addView(snapshotView, backgroundViewIndex + 1)
TaskContainer(
this,
@@ -157,8 +145,7 @@
taskOverlayFactory,
)
}
- taskContainers.forEach { it.bind() }
- setOrientationState(orientedState)
+ onBind(orientedState)
}
override fun onRecycle() {
@@ -242,8 +229,12 @@
}
}
- override fun needsUpdate(dataChange: Int, flag: Int) =
- if (flag == FLAG_UPDATE_CORNER_RADIUS) false else super.needsUpdate(dataChange, flag)
+ override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) {
+ super.onTaskListVisibilityChanged(visible, changes)
+ if (needsUpdate(changes, FLAG_UPDATE_CORNER_RADIUS)) {
+ contentViewFullscreenParams.updateCornerRadius(context)
+ }
+ }
override fun onIconLoaded(taskContainer: TaskContainer) {
// Update contentDescription of snapshotView only, individual task icon is unused.
@@ -258,9 +249,9 @@
override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) {
if (relativeToDragLayer) {
- container.dragLayer.getDescendantRectRelativeToSelf(backgroundView, bounds)
+ container.dragLayer.getDescendantRectRelativeToSelf(contentView, bounds)
} else {
- bounds.set(backgroundView)
+ bounds.set(contentView)
}
}
@@ -306,13 +297,12 @@
backgroundView.alpha = 1 - fullscreenProgress
}
- override fun updateCurrentFullscreenParams() {
- super.updateCurrentFullscreenParams()
- updateFullscreenParams(snapshotDrawParams)
+ override fun updateFullscreenParams() {
+ super.updateFullscreenParams()
+ updateFullscreenParams(contentViewFullscreenParams)
+ contentView.cornerRadius = contentViewFullscreenParams.currentCornerRadius
}
- override fun getThumbnailFullscreenParams() = snapshotDrawParams
-
override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
super.addChildrenForAccessibility(outChildren)
ViewUtils.addAccessibleChildToList(backgroundView, outChildren)
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 92c1e93..0d9583d 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -104,7 +104,7 @@
R.id.show_windows,
R.id.digital_wellbeing_toast,
STAGE_POSITION_TOP_OR_LEFT,
- taskOverlayFactory
+ taskOverlayFactory,
),
createTaskContainer(
secondaryTask,
@@ -113,14 +113,12 @@
R.id.show_windows_right,
R.id.bottomRight_digital_wellbeing_toast,
STAGE_POSITION_BOTTOM_OR_RIGHT,
- taskOverlayFactory
- )
+ taskOverlayFactory,
+ ),
)
- taskContainers.forEach { it.bind() }
-
this.splitBoundsConfig = splitBoundsConfig
taskContainers.forEach { it.digitalWellBeingToast?.splitBounds = splitBoundsConfig }
- setOrientationState(orientedState)
+ onBind(orientedState)
}
override fun setOrientationState(orientationState: RecentsOrientedState) {
@@ -131,7 +129,7 @@
container.deviceProfile,
it,
layoutParams.width,
- layoutParams.height
+ layoutParams.height,
)
val iconViewMarginStart =
resources.getDimensionPixelSize(
@@ -168,7 +166,7 @@
container.deviceProfile,
splitBoundsConfig,
layoutParams.width,
- layoutParams.height
+ layoutParams.height,
)
pagedOrientationHandler.setSplitIconParams(
taskContainers[0].iconView.asView(),
@@ -181,7 +179,7 @@
isRtl,
container.deviceProfile,
splitBoundsConfig,
- inSplitSelection
+ inSplitSelection,
)
} else {
pagedOrientationHandler.setSplitIconParams(
@@ -195,7 +193,7 @@
isRtl,
container.deviceProfile,
splitBoundsConfig,
- inSplitSelection
+ inSplitSelection,
)
}
}
@@ -216,7 +214,7 @@
InteractionJankMonitorWrapper.begin(
this,
Cuj.CUJ_SPLIT_SCREEN_ENTER,
- "Enter form GroupedTaskView"
+ "Enter form GroupedTaskView",
)
launchTaskInternal(isQuickSwitch = false, launchingExistingTaskView = true) {
endCallback.executeAllAndDestroy()
@@ -230,7 +228,7 @@
override fun launchWithoutAnimation(
isQuickSwitch: Boolean,
- callback: (launched: Boolean) -> Unit
+ callback: (launched: Boolean) -> Unit,
) {
launchTaskInternal(isQuickSwitch, launchingExistingTaskView = false, callback)
}
@@ -244,7 +242,7 @@
private fun launchTaskInternal(
isQuickSwitch: Boolean,
launchingExistingTaskView: Boolean,
- callback: (launched: Boolean) -> Unit
+ callback: (launched: Boolean) -> Unit,
) {
recentsView?.let {
it.splitSelectController.launchExistingSplitPair(
@@ -254,11 +252,11 @@
STAGE_POSITION_TOP_OR_LEFT,
callback,
isQuickSwitch,
- snapPosition
+ snapPosition,
)
Log.d(
TAG,
- "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}, launchingExistingTaskView: $launchingExistingTaskView"
+ "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}, launchingExistingTaskView: $launchingExistingTaskView",
)
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3a4e328..9cc42b4 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -417,9 +417,6 @@
public void setValue(RecentsView view, float scale) {
view.setScaleX(scale);
view.setScaleY(scale);
- if (enableRefactorTaskThumbnail()) {
- view.mRecentsViewModel.updateScale(scale);
- }
view.mLastComputedTaskStartPushOutDistance = null;
view.mLastComputedTaskEndPushOutDistance = null;
view.runActionOnRemoteHandles(new Consumer<RemoteTargetHandle>() {
@@ -610,6 +607,8 @@
private int mKeyboardTaskFocusSnapAnimationDuration;
private int mKeyboardTaskFocusIndex = INVALID_PAGE;
+ private int[] mDismissPrimaryTranslations;
+
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
*/
@@ -690,8 +689,6 @@
protected int mRunningTaskViewId = -1;
private int mTaskViewIdCount;
protected boolean mRunningTaskTileHidden;
- @Nullable
- private Task[] mTmpRunningTasks;
protected int mFocusedTaskViewId = INVALID_TASK_ID;
private boolean mTaskIconScaledDown = false;
@@ -847,6 +844,8 @@
private final RecentsViewModelHelper mHelper;
private final RecentsViewUtils mUtils = new RecentsViewUtils();
+ private final Matrix mTmpMatrix = new Matrix();
+
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseContainerInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
@@ -1416,7 +1415,7 @@
if (showAsGrid()) {
int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
int screenEnd = screenStart + getPagedOrientationHandler().getMeasuredSize(this);
- return isTaskViewWithinBounds(tv, screenStart, screenEnd);
+ return isTaskViewWithinBounds(tv, screenStart, screenEnd, /*taskViewTranslation=*/ 0);
} else {
// For now, just check if it's the active task or an adjacent task
return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
@@ -1463,14 +1462,28 @@
return clearAllScroll + (mIsRtl ? distance : -distance);
}
- private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
- int taskStart = getPagedOrientationHandler().getChildStart(tv)
- + (int) tv.getOffsetAdjustment(showAsGrid());
- int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(tv)
- * tv.getSizeAdjustment(showAsFullscreen()));
+ /*
+ * Returns if TaskView is within screen bounds defined in [screenStart, screenEnd].
+ *
+ * @param taskViewTranslation taskView is considered within bounds if either translated or
+ * original position of taskView is within screen bounds.
+ */
+ private boolean isTaskViewWithinBounds(TaskView taskView, int screenStart, int screenEnd,
+ int taskViewTranslation) {
+ int taskStart = getPagedOrientationHandler().getChildStart(taskView)
+ + (int) taskView.getOffsetAdjustment(showAsGrid());
+ int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(taskView)
+ * taskView.getSizeAdjustment(showAsFullscreen()));
int taskEnd = taskStart + taskSize;
- return (taskStart >= start && taskStart <= end) || (taskEnd >= start
- && taskEnd <= end);
+
+ int translatedTaskStart = taskStart + taskViewTranslation;
+ int translatedTaskEnd = taskEnd + taskViewTranslation;
+
+ taskStart = Math.min(taskStart, translatedTaskStart);
+ taskEnd = Math.max(taskEnd, translatedTaskEnd);
+
+ return (taskStart >= screenStart && taskStart <= screenEnd) || (taskEnd >= screenStart
+ && taskEnd <= screenEnd);
}
private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
@@ -1548,9 +1561,6 @@
updateTaskStackListenerState();
mOrientationState.setRotationWatcherEnabled(enabled);
if (!enabled) {
- // Reset the running task when leaving overview since it can still have a reference to
- // its thumbnail
- mTmpRunningTasks = null;
mSplitBoundsConfig = null;
mTaskOverlayFactory.clearAllActiveState();
}
@@ -1966,7 +1976,7 @@
// 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);
+ showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan");
} else {
setRunningTaskViewId(INVALID_TASK_ID);
}
@@ -2468,7 +2478,8 @@
}
boolean visible;
if (showAsGrid()) {
- visible = isTaskViewWithinBounds(taskView, visibleStart, visibleEnd);
+ visible = isTaskViewWithinBounds(taskView, visibleStart, visibleEnd,
+ mDismissPrimaryTranslations != null ? mDismissPrimaryTranslations[i] : 0);
} else {
visible = lower <= i && i <= upper;
}
@@ -2477,13 +2488,6 @@
List<Task> tasksToUpdate = containers.stream()
.map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
- if (mTmpRunningTasks != null) {
- for (Task t : mTmpRunningTasks) {
- // Skip loading if this is the task that we are animating into
- // TODO(b/280812109) change this equality check to use A.equals(B)
- tasksToUpdate.removeIf(task -> task == t);
- }
- }
if (enableRefactorTaskThumbnail()) {
visibleTaskIds.addAll(
tasksToUpdate.stream().map((task) -> task.key.id).toList());
@@ -2491,6 +2495,7 @@
if (tasksToUpdate.isEmpty()) {
continue;
}
+ int visibilityChanges = 0;
for (Task task : tasksToUpdate) {
if (!mHasVisibleTaskData.get(task.key.id)) {
// Ignore thumbnail update if it's current running task during the gesture
@@ -2499,21 +2504,28 @@
if (taskView == getRunningTaskView() && isGestureActive()) {
changes &= ~TaskView.FLAG_UPDATE_THUMBNAIL;
}
- taskView.onTaskListVisibilityChanged(true /* visible */, changes);
+ visibilityChanges |= changes;
}
mHasVisibleTaskData.put(task.key.id, true);
}
+ if (visibilityChanges != 0) {
+ taskView.onTaskListVisibilityChanged(true /* visible */, visibilityChanges);
+ }
} else {
+ int visibilityChanges = 0;
for (TaskContainer container : containers) {
if (container == null) {
continue;
}
if (mHasVisibleTaskData.get(container.getTask().key.id)) {
- taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
+ visibilityChanges = dataChanges;
}
mHasVisibleTaskData.delete(container.getTask().key.id);
}
+ if (visibilityChanges != 0) {
+ taskView.onTaskListVisibilityChanged(false /* visible */, visibilityChanges);
+ }
}
}
if (enableRefactorTaskThumbnail()) {
@@ -2749,7 +2761,7 @@
updateSizeAndPadding();
}
- showCurrentTask(mActiveGestureRunningTasks);
+ showCurrentTask(mActiveGestureRunningTasks, "onGestureAnimationStart");
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
@@ -2930,8 +2942,9 @@
* All subsequent calls to reload will keep the task as the first item until {@link #reset()}
* is called. Also scrolls the view to this task.
*/
- private void showCurrentTask(Task[] runningTasks) {
- Log.d(TAG, "showCurrentTask - runningTasks: " + Arrays.toString(runningTasks));
+ private void showCurrentTask(Task[] runningTasks, String caller) {
+ Log.d(TAG, "showCurrentTask(" + caller + ") - runningTasks: "
+ + Arrays.toString(runningTasks));
if (runningTasks.length == 0) {
return;
}
@@ -2945,23 +2958,18 @@
final TaskView taskView;
if (needDesktopTask) {
taskView = getTaskViewFromPool(TaskViewType.DESKTOP);
- mTmpRunningTasks = Arrays.copyOf(runningTasks, runningTasks.length);
- ((DesktopTaskView) taskView).bind(Arrays.asList(mTmpRunningTasks),
+ ((DesktopTaskView) taskView).bind(Arrays.asList(runningTasks),
mOrientationState, mTaskOverlayFactory);
} else if (needGroupTaskView) {
taskView = getTaskViewFromPool(TaskViewType.GROUPED);
- mTmpRunningTasks = new Task[]{runningTasks[0], runningTasks[1]};
// When we create a placeholder task view mSplitBoundsConfig will be null, but with
// the actual app running we won't need to show the thumbnail until all the tasks
// load later anyways
- ((GroupedTaskView) taskView).bind(mTmpRunningTasks[0], mTmpRunningTasks[1],
+ ((GroupedTaskView) taskView).bind(runningTasks[0], runningTasks[1],
mOrientationState, mTaskOverlayFactory, mSplitBoundsConfig);
} else {
taskView = getTaskViewFromPool(TaskViewType.SINGLE);
- // The temporary running task is only used for the duration between the start of the
- // gesture and the task list is loaded and applied
- mTmpRunningTasks = new Task[]{runningTasks[0]};
- taskView.bind(mTmpRunningTasks[0], mOrientationState, mTaskOverlayFactory);
+ taskView.bind(runningTasks[0], mOrientationState, mTaskOverlayFactory);
}
addView(taskView, 0);
runningTaskViewId = taskView.getTaskViewId();
@@ -3834,6 +3842,7 @@
stagingTranslation += mIsRtl ? newClearAllShortTotalWidthTranslation
: -newClearAllShortTotalWidthTranslation;
}
+ mDismissPrimaryTranslations = new int[taskCount];
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
@@ -3851,7 +3860,7 @@
Math.abs(i - dismissedIndex),
scrollDiff,
anim,
- splitTimings);
+ splitTimings, i);
needsCurveUpdates = true;
}
} else if (child instanceof TaskView taskView) {
@@ -3912,10 +3921,12 @@
primaryTranslation += mIsRtl ? stagingTranslation : -stagingTranslation;
if (primaryTranslation != 0) {
+ float finalTranslation = mIsRtl ? primaryTranslation : -primaryTranslation;
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
- mIsRtl ? primaryTranslation : -primaryTranslation,
+ finalTranslation,
clampToProgress(dismissInterpolator, animationStartProgress,
animationEndProgress));
+ mDismissPrimaryTranslations[i] = (int) finalTranslation;
distanceFromDismissedTask++;
}
}
@@ -3934,7 +3945,7 @@
if (animateTaskView && dismissedTaskView != null) {
dismissedTaskView.setTranslationZ(0.1f);
}
-
+ loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
@@ -4152,6 +4163,7 @@
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
+ mDismissPrimaryTranslations = null;
}
});
}
@@ -4190,7 +4202,8 @@
int indexDiff,
int scrollDiffPerPage,
PendingAnimation pendingAnimation,
- SplitAnimationTimings splitTimings) {
+ SplitAnimationTimings splitTimings,
+ int index) {
FloatProperty translationProperty = view instanceof TaskView
? ((TaskView) view).getPrimaryDismissTranslationProperty()
: getPagedOrientationHandler().getPrimaryViewTranslate();
@@ -4224,6 +4237,9 @@
)
);
+ if (view instanceof TaskView) {
+ mDismissPrimaryTranslations[index] = scrollDiffPerPage;
+ }
if (mEnableDrawingLiveTile && view instanceof TaskView
&& ((TaskView) view).isRunningTask()) {
pendingAnimation.addOnFrameCallback(() -> {
@@ -5006,7 +5022,7 @@
private void updateTaskViewsSnapshotRadius() {
for (TaskView taskView : getTaskViews()) {
- taskView.updateSnapshotRadius();
+ taskView.updateFullscreenParams();
}
}
@@ -5139,7 +5155,7 @@
if (!enableRefactorTaskThumbnail()) {
taskContainer.getThumbnailViewDeprecated().refreshSplashView();
}
- mSplitHiddenTaskView.updateSnapshotRadius();
+ mSplitHiddenTaskView.updateFullscreenParams();
});
} else if (isInitiatingSplitFromTaskView) {
if (Flags.enableHoverOfChildElementsInTaskview()) {
@@ -5807,6 +5823,14 @@
// mSyncTransactionApplier doesn't get transferred over
runActionOnRemoteHandles(remoteTargetHandle -> {
final TransformParams params = remoteTargetHandle.getTransformParams();
+ if (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow()) {
+ params.setHomeBuilderProxy((builder, app, transformParams) -> {
+ mTmpMatrix.setScale(
+ 1f, 1f, app.localBounds.exactCenterX(), app.localBounds.exactCenterY());
+ builder.setMatrix(mTmpMatrix).setAlpha(1f).setShow();
+ });
+ }
+
if (mSyncTransactionApplier != null) {
params.setSyncTransactionApplier(mSyncTransactionApplier);
params.getTargetSet().addReleaseCheck(mSyncTransactionApplier);
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 5dbc2ef..9f2bb9a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -50,9 +50,9 @@
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
import com.android.launcher3.util.ViewPool;
+import com.android.quickstep.FullscreenDrawParams;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
-import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
@@ -107,7 +107,7 @@
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
- private TaskView.FullscreenDrawParams mFullscreenParams;
+ private FullscreenDrawParams mFullscreenParams;
private ImageView mSplashView;
private Drawable mSplashViewDrawable;
private TaskView mTaskView;
@@ -279,7 +279,7 @@
canvas.save();
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(),
- mFullscreenParams.getCurrentDrawnCornerRadius());
+ mFullscreenParams.getCurrentCornerRadius());
canvas.restore();
}
@@ -287,7 +287,7 @@
return mPreviewPositionHelper;
}
- public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {
+ public void setFullscreenParams(FullscreenDrawParams fullscreenParams) {
mFullscreenParams = fullscreenParams;
invalidate();
}
@@ -473,7 +473,7 @@
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.getMatrix());
mPaint.setShader(mBitmapShader);
}
- mTaskView.updateCurrentFullscreenParams();
+ mTaskView.updateFullscreenParams();
invalidate();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index b1cb407..7e489ea 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -59,13 +59,11 @@
import com.android.launcher3.testing.TestLogging
import com.android.launcher3.testing.shared.TestProtocol
import com.android.launcher3.util.CancellableTask
-import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.Executors
import com.android.launcher3.util.MultiPropertyFactory
import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
import com.android.launcher3.util.MultiValueAlpha
import com.android.launcher3.util.RunnableList
-import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
@@ -74,16 +72,13 @@
import com.android.launcher3.util.TransformingTouchDelegate
import com.android.launcher3.util.ViewPool
import com.android.launcher3.util.rects.set
-import com.android.launcher3.views.ActivityContext
+import com.android.quickstep.FullscreenDrawParams
import com.android.quickstep.RecentsModel
import com.android.quickstep.RemoteAnimationTargets
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
-import com.android.quickstep.recents.di.RecentsDependencies
-import com.android.quickstep.recents.di.get
import com.android.quickstep.task.thumbnail.TaskThumbnailView
-import com.android.quickstep.task.viewmodel.TaskViewModel
import com.android.quickstep.util.ActiveGestureErrorDetector
import com.android.quickstep.util.ActiveGestureLog
import com.android.quickstep.util.BorderAnimator
@@ -95,7 +90,6 @@
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.system.ActivityManagerWrapper
-import com.android.systemui.shared.system.QuickStepContract
/** A task in the Recents view. */
open class TaskView
@@ -108,6 +102,7 @@
focusBorderAnimator: BorderAnimator? = null,
hoverBorderAnimator: BorderAnimator? = null,
private val type: TaskViewType = TaskViewType.SINGLE,
+ protected val thumbnailFullscreenParams: FullscreenDrawParams = FullscreenDrawParams(context),
) : FrameLayout(context, attrs), ViewPool.Reusable {
/**
* Used in conjunction with [onTaskListVisibilityChanged], providing more granularity on which
@@ -117,8 +112,6 @@
@IntDef(FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL, FLAG_UPDATE_CORNER_RADIUS)
annotation class TaskDataChanges
- private lateinit var taskViewModel: TaskViewModel
-
val taskIds: IntArray
/** Returns a copy of integer array containing taskIds of all tasks in the TaskView. */
get() = taskContainers.map { it.task.key.id }.toIntArray()
@@ -142,9 +135,6 @@
this == recentsView?.focusedTaskView ||
(enableLargeDesktopWindowingTile() && type == TaskViewType.DESKTOP)
- val taskCornerRadius: Float
- get() = currentFullscreenParams.cornerRadius
-
val recentsView: RecentsView<*, *>?
get() = parent as? RecentsView<*, *>
@@ -157,15 +147,9 @@
get() = taskContainers[0].task
@get:Deprecated("Use [taskContainers] instead.")
- val firstSnapshotView: View
- /** Returns the first snapshotView of the TaskView. */
- get() = taskContainers[0].snapshotView
-
- @get:Deprecated("Use [taskContainers] instead.")
val firstItemInfo: ItemInfo
get() = taskContainers[0].itemInfo
- private val currentFullscreenParams = FullscreenDrawParams(context)
protected val container: RecentsViewContainer =
RecentsViewContainer.containerFromContext(context)
protected val lastTouchDownPosition = PointF()
@@ -489,17 +473,13 @@
init {
setOnClickListener { _ -> onClick() }
- if (enableRefactorTaskThumbnail()) {
- taskViewModel = RecentsDependencies.get(this, "TaskViewType" to type)
- }
-
val cursorHoverStatesEnabled = enableCursorHoverStates()
setWillNotDraw(!cursorHoverStatesEnabled)
context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use {
this.focusBorderAnimator =
focusBorderAnimator
?: createSimpleBorderAnimator(
- currentFullscreenParams.cornerRadius.toInt(),
+ TaskCornerRadius.get(context).toInt(),
context.resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_border_width
),
@@ -514,7 +494,7 @@
hoverBorderAnimator
?: if (cursorHoverStatesEnabled)
createSimpleBorderAnimator(
- currentFullscreenParams.cornerRadius.toInt(),
+ TaskCornerRadius.get(context).toInt(),
context.resources.getDimensionPixelSize(
R.dimen.task_hover_border_width
),
@@ -716,7 +696,16 @@
taskOverlayFactory,
)
)
- taskContainers.forEach { it.bind() }
+ onBind(orientedState)
+ }
+
+ open fun onBind(orientedState: RecentsOrientedState) {
+ taskContainers.forEach {
+ it.bind()
+ if (enableRefactorTaskThumbnail()) {
+ it.thumbnailView.cornerRadius = thumbnailFullscreenParams.currentCornerRadius
+ }
+ }
setOrientationState(orientedState)
}
@@ -935,7 +924,7 @@
}
}
if (needsUpdate(changes, FLAG_UPDATE_CORNER_RADIUS)) {
- currentFullscreenParams.updateCornerRadius(context)
+ thumbnailFullscreenParams.updateCornerRadius(context)
}
}
@@ -1514,10 +1503,7 @@
val scale = persistentScale * dismissScale
scaleX = scale
scaleY = scale
- if (enableRefactorTaskThumbnail()) {
- taskViewModel.updateScale(scale)
- }
- updateSnapshotRadius()
+ updateFullscreenParams()
}
protected open fun applyThumbnailSplashAlpha() {
@@ -1560,30 +1546,25 @@
}
focusTransitionFullscreen.value =
FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(1 - fullscreenProgress)
- updateSnapshotRadius()
+ updateFullscreenParams()
}
- protected open fun updateSnapshotRadius() {
- updateCurrentFullscreenParams()
+ protected open fun updateFullscreenParams() {
+ updateFullscreenParams(thumbnailFullscreenParams)
taskContainers.forEach {
- if (!enableRefactorTaskThumbnail()) {
- it.thumbnailViewDeprecated.setFullscreenParams(getThumbnailFullscreenParams())
+ if (enableRefactorTaskThumbnail()) {
+ it.thumbnailView.cornerRadius = thumbnailFullscreenParams.currentCornerRadius
+ } else {
+ it.thumbnailViewDeprecated.setFullscreenParams(thumbnailFullscreenParams)
}
- it.overlay.setFullscreenParams(getThumbnailFullscreenParams())
+ it.overlay.setFullscreenParams(thumbnailFullscreenParams)
}
}
- protected open fun updateCurrentFullscreenParams() {
- updateFullscreenParams(currentFullscreenParams)
- }
-
protected fun updateFullscreenParams(fullscreenParams: FullscreenDrawParams) {
recentsView?.let { fullscreenParams.setProgress(fullscreenProgress, it.scaleX, scaleX) }
}
- protected open fun getThumbnailFullscreenParams(): FullscreenDrawParams =
- currentFullscreenParams
-
private fun onModalnessUpdated(modalness: Float) {
taskContainers.forEach {
it.iconView.setModalAlpha(1 - modalness)
@@ -1630,56 +1611,6 @@
private fun getNonGridTrans(endTranslation: Float) =
endTranslation - getGridTrans(endTranslation)
- /** We update and subsequently draw these in [fullscreenProgress]. */
- open class FullscreenDrawParams(context: Context) : SafeCloseable {
- var cornerRadius = 0f
- private var windowCornerRadius = 0f
- var currentDrawnCornerRadius = 0f
-
- init {
- updateCornerRadius(context)
- }
-
- /** Recomputes the start and end corner radius for the given Context. */
- fun updateCornerRadius(context: Context) {
- cornerRadius = computeTaskCornerRadius(context)
- windowCornerRadius = computeWindowCornerRadius(context)
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
- open fun computeTaskCornerRadius(context: Context): Float {
- return TaskCornerRadius.get(context)
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
- open fun computeWindowCornerRadius(context: Context): Float {
- val activityContext: ActivityContext? = ActivityContext.lookupContextNoThrow(context)
-
- // The corner radius is fixed to match when Taskbar is persistent mode
- return if (
- activityContext != null &&
- activityContext.deviceProfile?.isTaskbarPresent == true &&
- DisplayController.isTransientTaskbar(context)
- ) {
- context.resources
- .getDimensionPixelSize(R.dimen.persistent_taskbar_corner_radius)
- .toFloat()
- } else {
- QuickStepContract.getWindowCornerRadius(context)
- }
- }
-
- /** Sets the progress in range [0, 1] */
- fun setProgress(fullscreenProgress: Float, parentScale: Float, taskViewScale: Float) {
- currentDrawnCornerRadius =
- Utilities.mapRange(fullscreenProgress, cornerRadius, windowCornerRadius) /
- parentScale /
- taskViewScale
- }
-
- override fun close() {}
- }
-
private fun MotionEvent.isWithinThumbnailBounds(): Boolean {
return thumbnailBounds.contains(x.toInt(), y.toInt())
}
diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
index f43a125..0091036 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
@@ -96,6 +96,12 @@
+ "force finish recents animation complete; clearing state callback.");
}
+ public static void logHandOffAnimation() {
+ ActiveGestureLog.INSTANCE.addLog("AbsSwipeUpHandler.handOffAnimation");
+ if (!enableActiveGestureProtoLog()) return;
+ ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.handOffAnimation");
+ }
+
public static void logFinishRecentsAnimationOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimationOnTasksAppeared");
if (!enableActiveGestureProtoLog()) return;
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/FakeTaskThumbnailViewModel.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/FakeTaskThumbnailViewModel.kt
index ff5d8bd..47d2bfc 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/FakeTaskThumbnailViewModel.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/FakeTaskThumbnailViewModel.kt
@@ -22,8 +22,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
class FakeTaskThumbnailViewModel : TaskThumbnailViewModel {
- override val cornerRadiusProgress = MutableStateFlow(0f)
- override val inheritedScale = MutableStateFlow(1f)
override val dimProgress = MutableStateFlow(0f)
override val splashAlpha = MutableStateFlow(0f)
override val uiState = MutableStateFlow<TaskThumbnailUiState>(Uninitialized)
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
index 75769e9..49fe614 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
@@ -66,11 +66,13 @@
val di = RecentsDependencies.initialize(context)
val taskThumbnailView =
LayoutInflater.from(context).inflate(R.layout.task_thumbnail, null, false)
+ as TaskThumbnailView
+ taskThumbnailView.cornerRadius = CORNER_RADIUS
val ttvDiScopeId = di.getScope(taskThumbnailView).scopeId
di.provide(TaskThumbnailViewData::class.java, ttvDiScopeId) { TaskThumbnailViewData() }
di.provide(TaskThumbnailViewModel::class.java, ttvDiScopeId) { taskThumbnailViewModel }
- return taskThumbnailView as TaskThumbnailView
+ return taskThumbnailView
}
companion object {
@@ -82,5 +84,7 @@
isDarkTheme = false,
isLandscape = false,
)
+
+ const val CORNER_RADIUS = 56f
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 4b04dba..c682990 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -15,9 +15,11 @@
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_THREE_BUTTON_NAV;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -28,6 +30,10 @@
import static org.mockito.Mockito.when;
import android.os.Handler;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.Flags;
@@ -43,8 +49,10 @@
import com.android.systemui.contextualeducation.GestureType;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -76,6 +84,9 @@
@Mock
View mockView;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private int mHomePressCount;
private int mOverviewToggleCount;
private final TaskbarNavButtonCallbacks mCallbacks = new TaskbarNavButtonCallbacks() {
@@ -333,4 +344,46 @@
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_BACK_BUTTON_LONGPRESS);
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_BACK_BUTTON_TAP);
}
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_THREE_BUTTON_NAV)
+ public void testPredictiveBackInvoked() {
+ ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class);
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN, false);
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_UP, false);
+ verify(mockSystemUiProxy, times(2)).onBackEvent(keyEventCaptor.capture());
+ verifyKeyEvent(keyEventCaptor.getAllValues().getFirst(), KeyEvent.ACTION_DOWN, false);
+ verifyKeyEvent(keyEventCaptor.getAllValues().getLast(), KeyEvent.ACTION_UP, false);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_THREE_BUTTON_NAV)
+ public void testPredictiveBackCancelled() {
+ ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class);
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN, false);
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_UP, true);
+ verify(mockSystemUiProxy, times(2)).onBackEvent(keyEventCaptor.capture());
+ verifyKeyEvent(keyEventCaptor.getAllValues().getFirst(), KeyEvent.ACTION_DOWN, false);
+ verifyKeyEvent(keyEventCaptor.getAllValues().getLast(), KeyEvent.ACTION_UP, true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_THREE_BUTTON_NAV)
+ public void testButtonsDisabledWhileBackPressed() {
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN, false);
+ mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
+ mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
+ mNavButtonController.onButtonLongClick(BUTTON_A11Y, mockView);
+ mNavButtonController.onButtonClick(BUTTON_IME_SWITCH, mockView);
+ mNavButtonController.sendBackKeyEvent(KeyEvent.ACTION_UP, false);
+ assertThat(mHomePressCount).isEqualTo(0);
+ verify(mockSystemUiProxy, never()).notifyAccessibilityButtonLongClicked();
+ assertThat(mOverviewToggleCount).isEqualTo(0);
+ verify(mockSystemUiProxy, never()).onImeSwitcherPressed();
+ }
+
+ private void verifyKeyEvent(KeyEvent keyEvent, int action, boolean isCancelled) {
+ assertEquals(isCancelled, keyEvent.isCanceled());
+ assertEquals(action, KeyEvent.ACTION_DOWN, keyEvent.getAction());
+ }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
new file mode 100644
index 0000000..cc8582c
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.ComponentName
+import android.content.Intent
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.Flags.FLAG_TASKBAR_OVERFLOW
+import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
+import com.android.launcher3.taskbar.rules.MockedRecentsModelTestRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.util.TestUtil.getOnUiThread
+import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.util.DesktopTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS
+import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR
+import com.android.wm.shell.desktopmode.IDesktopTaskListener
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+@EnableFlags(
+ FLAG_TASKBAR_OVERFLOW,
+ FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS,
+ FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ FLAG_ENABLE_BUBBLE_BAR,
+)
+class TaskbarOverflowTest {
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+
+ @get:Rule(order = 1)
+ val context =
+ TaskbarWindowSandboxContext.create { builder ->
+ builder.bindSystemUiProxy(
+ object : SystemUiProxy(this) {
+ override fun setDesktopTaskListener(listener: IDesktopTaskListener?) {
+ desktopTaskListener = listener
+ }
+ }
+ )
+ }
+
+ @get:Rule(order = 2) val recentsModel = MockedRecentsModelTestRule(context)
+
+ @get:Rule(order = 3) val taskbarModeRule = TaskbarModeRule(context)
+
+ @get:Rule(order = 4) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var taskbarViewController: TaskbarViewController
+ @InjectController lateinit var recentAppsController: TaskbarRecentAppsController
+ @InjectController lateinit var bubbleBarViewController: BubbleBarViewController
+ @InjectController lateinit var bubbleStashController: BubbleStashController
+
+ private var desktopTaskListener: IDesktopTaskListener? = null
+
+ @Before
+ fun ensureRunningAppsShowing() {
+ runOnMainSync {
+ if (!recentAppsController.canShowRunningApps) {
+ recentAppsController.onDestroy()
+ recentAppsController.canShowRunningApps = true
+ recentAppsController.init(taskbarUnitTestRule.activityContext.controllers)
+ }
+ recentsModel.resolvePendingTaskRequests()
+ }
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testTaskbarWithMaxNumIcons_pinned() {
+ addRunningAppsAndVerifyOverflowState(0)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin).isAtLeast(navButtonEndSpacing)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testTaskbarWithMaxNumIcons_transient() {
+ addRunningAppsAndVerifyOverflowState(0)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin).isAtLeast(navButtonEndSpacing)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOverflownTaskbar_pinned() {
+ addRunningAppsAndVerifyOverflowState(5)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin).isAtLeast(navButtonEndSpacing)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testOverflownTaskbar_transient() {
+ addRunningAppsAndVerifyOverflowState(5)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin).isAtLeast(navButtonEndSpacing)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testBubbleBarReducesTaskbarMaxNumIcons_pinned() {
+ var initialMaxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(initialMaxNumIconViews).isGreaterThan(0)
+
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+
+ val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
+ assertThat(maxNumIconViews).isLessThan(initialMaxNumIconViews)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testBubbleBarReducesTaskbarMaxNumIcons_transient() {
+ var initialMaxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(initialMaxNumIconViews).isGreaterThan(0)
+
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+
+ val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
+ assertThat(maxNumIconViews).isLessThan(initialMaxNumIconViews)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin)
+ .isAtLeast(
+ navButtonEndSpacing +
+ bubbleBarViewController.collapsedWidthWithMaxVisibleBubbles.toInt()
+ )
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testBubbleBarReducesTaskbarMaxNumIcons_transientBubbleInitiallyStashed() {
+ var initialMaxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(initialMaxNumIconViews).isGreaterThan(0)
+ runOnMainSync {
+ bubbleStashController.stashBubbleBarImmediate()
+ bubbleBarViewController.setHiddenForBubbles(false)
+ }
+
+ val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
+ assertThat(maxNumIconViews).isLessThan(initialMaxNumIconViews)
+
+ assertThat(taskbarIconsCentered).isTrue()
+ assertThat(taskbarEndMargin)
+ .isAtLeast(
+ navButtonEndSpacing +
+ bubbleBarViewController.collapsedWidthWithMaxVisibleBubbles.toInt()
+ )
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testStashingBubbleBarMaintainsMaxNumIcons_transient() {
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+
+ val initialNumIcons = currentNumberOfTaskbarIcons
+ val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
+
+ runOnMainSync { bubbleStashController.stashBubbleBarImmediate() }
+ assertThat(maxNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(taskbarOverflowIconIndex).isEqualTo(initialNumIcons.coerceAtLeast(2))
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testHidingBubbleBarIncreasesMaxNumIcons_pinned() {
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+
+ val initialNumIcons = currentNumberOfTaskbarIcons
+ val initialMaxNumIconViews = addRunningAppsAndVerifyOverflowState(5)
+
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(true) }
+
+ val maxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(maxNumIconViews).isGreaterThan(initialMaxNumIconViews)
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(taskbarOverflowIconIndex).isEqualTo(initialNumIcons.coerceAtLeast(2))
+
+ assertThat(taskbarIconsCentered).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testHidingBubbleBarIncreasesMaxNumIcons_transient() {
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+
+ val initialNumIcons = currentNumberOfTaskbarIcons
+ val initialMaxNumIconViews = addRunningAppsAndVerifyOverflowState(5)
+
+ runOnMainSync { bubbleBarViewController.setHiddenForBubbles(true) }
+
+ val maxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(maxNumIconViews).isGreaterThan(initialMaxNumIconViews)
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(taskbarOverflowIconIndex).isEqualTo(initialNumIcons.coerceAtLeast(2))
+
+ assertThat(taskbarIconsCentered).isTrue()
+ }
+
+ private fun createDesktopTask(tasksToAdd: Int) {
+ val tasks =
+ (0..<tasksToAdd).map {
+ Task(Task.TaskKey(it, 0, Intent(), ComponentName("", ""), 0, 2000))
+ }
+ recentsModel.updateRecentTasks(listOf(DesktopTask(tasks)))
+ desktopTaskListener?.onTasksVisibilityChanged(
+ context.virtualDisplay.display.displayId,
+ tasksToAdd,
+ )
+ runOnMainSync { recentsModel.resolvePendingTaskRequests() }
+ }
+
+ private val navButtonEndSpacing: Int
+ get() {
+ return taskbarUnitTestRule.activityContext.resources.getDimensionPixelSize(
+ taskbarUnitTestRule.activityContext.deviceProfile.inv.inlineNavButtonsEndSpacing
+ )
+ }
+
+ private val taskbarOverflowIconIndex: Int
+ get() {
+ return getOnUiThread {
+ taskbarViewController.iconViews.indexOfFirst { it is TaskbarOverflowView }
+ }
+ }
+
+ private val maxNumberOfTaskbarIcons: Int
+ get() = getOnUiThread { taskbarViewController.maxNumIconViews }
+
+ private val currentNumberOfTaskbarIcons: Int
+ get() = getOnUiThread { taskbarViewController.iconViews.size }
+
+ private val taskbarIconsCentered: Boolean
+ get() {
+ return getOnUiThread {
+ val iconLayoutBounds = taskbarViewController.iconLayoutBounds
+ val availableWidth = taskbarUnitTestRule.activityContext.deviceProfile.widthPx
+ iconLayoutBounds.left - (availableWidth - iconLayoutBounds.right) < 2
+ }
+ }
+
+ private val taskbarEndMargin: Int
+ get() {
+ return getOnUiThread {
+ taskbarUnitTestRule.activityContext.deviceProfile.widthPx -
+ taskbarViewController.iconLayoutBounds.right
+ }
+ }
+
+ /**
+ * Adds enough running apps for taskbar to enter overflow of `targetOverflowSize`, and verifies
+ * * max number of icons in the taskbar remains unchanged
+ * * number of icons in the taskbar is at most max number of icons
+ * * whether the taskbar overflow icon is shown, and its position in taskbar.
+ *
+ * Returns max number of icons.
+ */
+ private fun addRunningAppsAndVerifyOverflowState(targetOverflowSize: Int): Int {
+ val maxNumIconViews = maxNumberOfTaskbarIcons
+ assertThat(maxNumIconViews).isGreaterThan(0)
+ // Assume there are at least all apps and divider icon, as they would appear once running
+ // apps are added, even if not present initially.
+ val initialIconCount = currentNumberOfTaskbarIcons.coerceAtLeast(2)
+ assertThat(initialIconCount).isLessThan(maxNumIconViews)
+
+ createDesktopTask(maxNumIconViews - initialIconCount + targetOverflowSize)
+
+ assertThat(maxNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
+ assertThat(taskbarOverflowIconIndex)
+ .isEqualTo(if (targetOverflowSize > 0) initialIconCount else -1)
+ return maxNumIconViews
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
index 71f4ef4..5e438bd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
@@ -21,6 +21,7 @@
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.QuickstepTransitionManager.PINNED_TASKBAR_TRANSITION_DURATION
import com.android.launcher3.R
import com.android.launcher3.taskbar.StashedHandleViewController.ALPHA_INDEX_STASHED
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
@@ -158,7 +159,7 @@
@Test
@TaskbarMode(PINNED)
fun testGetStashDuration_pinnedMode() {
- assertThat(stashController.stashDuration).isEqualTo(TASKBAR_STASH_DURATION)
+ assertThat(stashController.stashDuration).isEqualTo(PINNED_TASKBAR_TRANSITION_DURATION)
}
@Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt
new file mode 100644
index 0000000..0bb404b
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.platform.test.flag.junit.FlagsParameterization
+import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf
+import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.Flags.FLAG_TASKBAR_RECENTS_LAYOUT_TRANSITION
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.TaskbarIconType.ALL_APPS
+import com.android.launcher3.taskbar.TaskbarIconType.DIVIDER
+import com.android.launcher3.taskbar.TaskbarIconType.HOTSEAT
+import com.android.launcher3.taskbar.TaskbarIconType.RECENT
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.assertThat
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.createHotseatItems
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.createRecents
+import com.android.launcher3.taskbar.rules.TaskbarDeviceEmulationRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.ForceRtl
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit.Companion.isRunningInRobolectric
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+@RunWith(ParameterizedAndroidJunit4::class)
+class TaskbarViewTest(deviceName: String, flags: FlagsParameterization) {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0},{1}")
+ fun getParams(): List<Array<Any>> {
+ val devices =
+ if (isRunningInRobolectric) {
+ listOf("pixelFoldable2023", "pixelTablet2023")
+ } else {
+ listOf("onDevice") // Unused.
+ }
+ val flags = allCombinationsOf(FLAG_TASKBAR_RECENTS_LAYOUT_TRANSITION)
+ return devices.flatMap { d -> flags.map { f -> arrayOf(d, f) } } // Cartesian product.
+ }
+ }
+
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule(flags)
+ @get:Rule(order = 1) val context = TaskbarWindowSandboxContext.create()
+ @get:Rule(order = 2) val deviceEmulationRule = TaskbarDeviceEmulationRule(context, deviceName)
+ @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ private lateinit var taskbarView: TaskbarView
+
+ @Before
+ fun obtainView() {
+ taskbarView = taskbarUnitTestRule.activityContext.dragLayer.findViewById(R.id.taskbar_view)
+ }
+
+ @Test
+ fun testUpdateItems_noItems_hasOnlyAllApps() {
+ runOnMainSync { taskbarView.updateItems(emptyArray(), emptyList()) }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS)
+ }
+
+ @Test
+ fun testUpdateItems_hotseatItems_hasDividerBetweenAllAppsAndHotseat() {
+ runOnMainSync { taskbarView.updateItems(createHotseatItems(2), emptyList()) }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, DIVIDER, HOTSEAT, HOTSEAT)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtlWithHotseatItems_hasDividerBetweenHotseatAndAllApps() {
+ runOnMainSync { taskbarView.updateItems(createHotseatItems(2), emptyList()) }
+ assertThat(taskbarView).hasIconTypes(HOTSEAT, HOTSEAT, DIVIDER, ALL_APPS)
+ }
+
+ @Test
+ fun testUpdateItems_withNullHotseatItem_filtersNullItem() {
+ runOnMainSync {
+ taskbarView.updateItems(arrayOf(*createHotseatItems(2), null), emptyList())
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, DIVIDER, HOTSEAT, HOTSEAT)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtlWithNullHotseatItem_filtersNullItem() {
+ runOnMainSync {
+ taskbarView.updateItems(arrayOf(*createHotseatItems(2), null), emptyList())
+ }
+ assertThat(taskbarView).hasIconTypes(HOTSEAT, HOTSEAT, DIVIDER, ALL_APPS)
+ }
+
+ @Test
+ fun testUpdateItems_recentsItems_hasDividerBetweenAllAppsAndRecents() {
+ runOnMainSync { taskbarView.updateItems(emptyArray(), createRecents(4)) }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, DIVIDER, *RECENT * 4)
+ }
+
+ @Test
+ fun testUpdateItems_hotseatItemsAndRecents_hasDividerBetweenHotseatAndRecents() {
+ runOnMainSync { taskbarView.updateItems(createHotseatItems(3), createRecents(2)) }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, *HOTSEAT * 3, DIVIDER, *RECENT * 2)
+ }
+
+ @Test
+ fun testUpdateItems_addHotseatItem_updatesHotseat() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(2), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, *HOTSEAT * 2, DIVIDER, RECENT)
+ }
+
+ @Test
+ fun testUpdateItems_removeHotseatItem_updatesHotseat() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(2), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, HOTSEAT, DIVIDER, RECENT)
+ }
+
+ @Test
+ fun testUpdateItems_addRecentsItem_updatesRecents() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(2))
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, HOTSEAT, DIVIDER, *RECENT * 2)
+ }
+
+ @Test
+ fun testUpdateItems_removeRecentsItem_updatesRecents() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(2))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, HOTSEAT, DIVIDER, RECENT)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
new file mode 100644
index 0000000..a6bdbb0
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.taskbar.TaskbarIconType.ALL_APPS
+import com.android.launcher3.taskbar.TaskbarIconType.DIVIDER
+import com.android.launcher3.taskbar.TaskbarIconType.HOTSEAT
+import com.android.launcher3.taskbar.TaskbarIconType.OVERFLOW
+import com.android.launcher3.taskbar.TaskbarIconType.RECENT
+import com.android.quickstep.util.GroupTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Truth.assertAbout
+import com.google.common.truth.Truth.assertThat
+
+/** Common utilities for testing [TaskbarView]. */
+object TaskbarViewTestUtil {
+
+ /** Begins an assertion about a [TaskbarView]. */
+ fun assertThat(view: TaskbarView): TaskbarViewSubject {
+ return assertAbout(::TaskbarViewSubject).that(view)
+ }
+
+ /** Creates an array of fake hotseat items. */
+ fun createHotseatItems(size: Int): Array<ItemInfo> {
+ return Array(size) {
+ WorkspaceItemInfo(
+ AppInfo(TEST_COMPONENT, "Test App $it", Process.myUserHandle(), Intent())
+ )
+ .apply { id = it }
+ }
+ }
+
+ /** Creates a list of fake recent tasks. */
+ fun createRecents(size: Int): List<GroupTask> {
+ return List(size) {
+ GroupTask(
+ Task().apply {
+ key =
+ TaskKey(
+ it,
+ 5,
+ TEST_INTENT,
+ TEST_COMPONENT,
+ Process.myUserHandle().identifier,
+ System.currentTimeMillis(),
+ )
+ }
+ )
+ }
+ }
+}
+
+/** A `Truth` [Subject] with extensions for verifying [TaskbarView]. */
+class TaskbarViewSubject(failureMetadata: FailureMetadata, private val view: TaskbarView) :
+ Subject(failureMetadata, view) {
+
+ /** Verifies that the types of icons match [expectedTypes] in order. */
+ fun hasIconTypes(vararg expectedTypes: TaskbarIconType) {
+ val actualTypes =
+ view.iconViews.map {
+ when (it) {
+ view.allAppsButtonContainer -> ALL_APPS
+ view.taskbarDividerViewContainer -> DIVIDER
+ view.taskbarOverflowView -> OVERFLOW
+ else ->
+ when (it.tag) {
+ is ItemInfo -> HOTSEAT
+ is GroupTask -> RECENT
+ else -> throw IllegalStateException("Unknown type for $it")
+ }
+ }
+ }
+ assertThat(actualTypes).containsExactly(*expectedTypes).inOrder()
+ }
+
+ /** Verifies that recents from [startIndex] have IDs that match [expectedIds] in order. */
+ fun hasRecentsOrder(startIndex: Int, expectedIds: List<Int>) {
+ val actualIds =
+ view.iconViews.slice(startIndex..<expectedIds.size).map {
+ assertThat(it.tag).isInstanceOf(GroupTask::class.java)
+ (it.tag as? GroupTask)?.task1?.key?.id
+ }
+ assertThat(actualIds).containsExactlyElementsIn(expectedIds).inOrder()
+ }
+}
+
+/** Types of icons in the [TaskbarView]. */
+enum class TaskbarIconType {
+ ALL_APPS,
+ DIVIDER,
+ HOTSEAT,
+ RECENT,
+ OVERFLOW;
+
+ operator fun times(size: Int) = Array(size) { this }
+}
+
+private const val TEST_PACKAGE = "com.android.launcher3.taskbar"
+private val TEST_COMPONENT = ComponentName(TEST_PACKAGE, "Activity")
+private val TEST_INTENT = Intent().apply { `package` = TEST_PACKAGE }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt
new file mode 100644
index 0000000..15ded8d
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.Flags.FLAG_TASKBAR_RECENTS_LAYOUT_TRANSITION
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.TaskbarIconType.ALL_APPS
+import com.android.launcher3.taskbar.TaskbarIconType.DIVIDER
+import com.android.launcher3.taskbar.TaskbarIconType.HOTSEAT
+import com.android.launcher3.taskbar.TaskbarIconType.RECENT
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.assertThat
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.createHotseatItems
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.createRecents
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.ForceRtl
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+@EnableFlags(FLAG_TASKBAR_RECENTS_LAYOUT_TRANSITION)
+class TaskbarViewWithLayoutTransitionTest {
+
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+ @get:Rule(order = 1) val context = TaskbarWindowSandboxContext.create()
+ @get:Rule(order = 2) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ private lateinit var taskbarView: TaskbarView
+
+ @Before
+ fun obtainView() {
+ taskbarView = taskbarUnitTestRule.activityContext.dragLayer.findViewById(R.id.taskbar_view)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_hotseatItems_hasDividerBetweenHotseatAndAllApps() {
+ runOnMainSync { taskbarView.updateItems(createHotseatItems(2), emptyList()) }
+ assertThat(taskbarView).hasIconTypes(*HOTSEAT * 2, DIVIDER, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_recentsItems_hasDividerBetweenRecentsAndAllApps() {
+ runOnMainSync { taskbarView.updateItems(emptyArray(), createRecents(4)) }
+ assertThat(taskbarView).hasIconTypes(*RECENT * 4, DIVIDER, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_recentsItems_recentsAreReversed() {
+ runOnMainSync { taskbarView.updateItems(emptyArray(), createRecents(4)) }
+ assertThat(taskbarView).hasRecentsOrder(startIndex = 0, expectedIds = listOf(3, 2, 1, 0))
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_hotseatItemsAndRecents_hasDividerBetweenRecentsAndHotseat() {
+ runOnMainSync { taskbarView.updateItems(createHotseatItems(3), createRecents(2)) }
+ assertThat(taskbarView).hasIconTypes(*RECENT * 2, DIVIDER, *HOTSEAT * 3, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_addHotseatItem_updatesHotseat() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(2), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(RECENT, DIVIDER, *HOTSEAT * 2, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_removeHotseatItem_updatesHotseat() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(2), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(RECENT, DIVIDER, HOTSEAT, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_addRecentsItem_updatesRecents() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(2))
+ }
+ assertThat(taskbarView).hasIconTypes(*RECENT * 2, DIVIDER, HOTSEAT, ALL_APPS)
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_removeRecentsItem_updatesRecents() {
+ runOnMainSync {
+ taskbarView.updateItems(createHotseatItems(1), createRecents(2))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(RECENT, DIVIDER, HOTSEAT, ALL_APPS)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 48f3fc2..e12876f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -48,12 +48,15 @@
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
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.atLeastOnce
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -764,10 +767,12 @@
whenever(bubbleStashController.bubbleBarTranslationY)
.thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
- val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
-
+ val semaphore = Semaphore(0)
var notifiedExpanded = false
- val onExpanded = Runnable { notifiedExpanded = true }
+ val onExpanded = Runnable {
+ notifiedExpanded = true
+ semaphore.release()
+ }
val animator =
BubbleBarViewAnimator(
bubbleBarView,
@@ -792,7 +797,12 @@
// the lift animation is complete; the spring back animation should start now
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
- barAnimator.assertIsRunning()
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+ assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
+ // we should be expanded now
+ assertThat(bubbleBarView.isExpanded).isTrue()
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
// verify there is no hide animation
@@ -800,7 +810,6 @@
assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
- assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
assertThat(notifiedExpanded).isTrue()
}
@@ -1123,7 +1132,7 @@
animator.animateBubbleInForStashed(updatedBubble, isExpanding = false)
// the flyout should now reverse and expand
- animatorTestRule.advanceTimeBy(100)
+ animatorTestRule.advanceTimeBy(400)
}
assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1266,6 +1275,50 @@
verify(bubbleStashController).stashBubbleBarImmediate()
}
+ @Test
+ fun interruptForIme() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ flyoutController,
+ onExpandedNoOp,
+ animatorScheduler,
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+ handleAnimator.assertIsRunning()
+ assertThat(animator.isAnimating).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.interruptForIme() }
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+ assertThat(animator.isAnimating).isFalse()
+ verify(bubbleStashController).onNewBubbleAnimationInterrupted(eq(true), any())
+
+ // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
+ // again
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ handleAnimator.assertIsNotRunning()
+ }
+
private fun setUpBubbleBar() {
bubbleBarView = BubbleBarView(context)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -1362,21 +1415,21 @@
private fun waitForFlyoutToShow() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(250)
+ animatorTestRule.advanceTimeBy(400)
}
assertThat(flyoutView).isNotNull()
}
private fun waitForFlyoutToHide() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(250)
+ animatorTestRule.advanceTimeBy(350)
}
assertThat(flyoutView).isNull()
}
private fun waitForFlyoutToFadeOutAndBackIn() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(500)
+ animatorTestRule.advanceTimeBy(750)
}
assertThat(flyoutView).isNotNull()
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
index 2997ac9..103c769 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -50,6 +50,9 @@
private var onLeft = true
private var flyoutTy = 50f
+ private val showAnimationDuration = 400L
+ private val hideAnimationDuration = 350L
+
@Before
fun setUp() {
flyoutContainer = FrameLayout(context)
@@ -118,7 +121,7 @@
assertThat(flyoutController.hasFlyout()).isTrue()
assertThat(flyoutContainer.childCount).isEqualTo(1)
flyoutController.collapseFlyout {}
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(hideAnimationDuration)
}
assertThat(flyoutContainer.childCount).isEqualTo(0)
assertThat(flyoutController.hasFlyout()).isFalse()
@@ -135,7 +138,7 @@
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
}
assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
}
@@ -148,7 +151,7 @@
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
}
assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(0)
}
@@ -159,7 +162,7 @@
setupAndShowFlyout()
assertThat(flyoutContainer.childCount).isEqualTo(1)
flyoutController.collapseFlyout {}
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(hideAnimationDuration)
}
assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
}
@@ -172,7 +175,7 @@
val flyoutView = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
assertThat(flyoutView.alpha).isEqualTo(1f)
flyoutController.cancelFlyout {}
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(hideAnimationDuration)
assertThat(flyoutView.alpha).isEqualTo(0f)
}
assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
@@ -185,7 +188,7 @@
assertThat(flyoutContainer.childCount).isEqualTo(1)
val flyoutView = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
assertThat(flyoutView.alpha).isEqualTo(1f)
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
flyoutView.performClick()
}
assertThat(flyoutCallbacks.flyoutClicked).isTrue()
@@ -221,7 +224,7 @@
fun updateFlyoutFullyExpanded() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
setupAndShowFlyout()
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
}
assertThat(flyoutController.hasFlyout()).isTrue()
@@ -234,13 +237,13 @@
flyoutController.updateFlyoutFullyExpanded(newFlyoutMessage) {}
// advance the timer so that the fade out animation plays
- animatorTestRule.advanceTimeBy(250)
+ animatorTestRule.advanceTimeBy(hideAnimationDuration)
assertThat(flyout.alpha).isEqualTo(0)
assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
.isEqualTo("new message")
// advance the timer so that the fade in animation plays
- animatorTestRule.advanceTimeBy(250)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
assertThat(flyout.alpha).isEqualTo(1)
}
assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
@@ -250,7 +253,7 @@
fun updateFlyoutWhileCollapsing() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
setupAndShowFlyout()
- animatorTestRule.advanceTimeBy(300)
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
}
assertThat(flyoutController.hasFlyout()).isTrue()
@@ -265,9 +268,10 @@
var flyoutReversed = false
flyoutController.updateFlyoutWhileCollapsing(newFlyoutMessage) { flyoutReversed = true }
- // the collapse animation ran for 125ms when it was updated, so reversing it should only
- // run for the same amount of time
- animatorTestRule.advanceTimeBy(125)
+ // the collapse and expand animations use an emphasized interpolator, so the reverse
+ // path does not take the same time. advance the timer the by full duration of the show
+ // animation to ensure it completes
+ animatorTestRule.advanceTimeBy(showAnimationDuration)
val flyout = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
assertThat(flyout.alpha).isEqualTo(1)
assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index b7ee6c4..f795ab1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -86,6 +86,20 @@
}
@Test
+ fun updateLauncherState_noBubbles_controllerNotified() {
+ // Given bubble bar has no bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+
+ // When switch to home screen
+ getInstrumentation().runOnMainSync {
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.HOME
+ }
+
+ // Then bubble bar view controller is notified
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ false)
+ }
+
+ @Test
fun setBubblesShowingOnHomeUpdatedToFalse_barPositionYUpdated_controllersNotified() {
// Given bubble bar is on home and has bubbles
whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index 64416dd..1bbd12a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -119,6 +119,20 @@
}
@Test
+ fun updateLauncherState_noBubbles_controllerNotified() {
+ // Given bubble bar has no bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+
+ // When switch to home screen
+ getInstrumentation().runOnMainSync {
+ mTransientBubbleStashController.launcherState = BubbleLauncherState.HOME
+ }
+
+ // Then bubble bar view controller is notified
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ false)
+ }
+
+ @Test
fun setBubblesShowingOnHomeUpdatedToTrue_barPositionYUpdated_controllersNotified() {
// Given bubble bar is on home and has bubbles
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/MockedRecentsModelTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/MockedRecentsModelTestRule.kt
new file mode 100644
index 0000000..ed1443d
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/MockedRecentsModelTestRule.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.rules
+
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.RecentsModel.RecentTasksChangedListener
+import com.android.quickstep.TaskIconCache
+import com.android.quickstep.util.GroupTask
+import java.util.function.Consumer
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+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
+
+class MockedRecentsModelTestRule(private val context: TaskbarWindowSandboxContext) : TestRule {
+
+ private val mockIconCache: TaskIconCache = mock()
+
+ private val mockRecentsModel: RecentsModel = mock {
+ on { iconCache } doReturn mockIconCache
+
+ on { unregisterRecentTasksChangedListener() } doAnswer { recentTasksChangedListener = null }
+
+ on { registerRecentTasksChangedListener(any<RecentTasksChangedListener>()) } doAnswer
+ {
+ recentTasksChangedListener = it.getArgument<RecentTasksChangedListener>(0)
+ }
+
+ on { getTasks(anyOrNull(), anyOrNull()) } doAnswer
+ {
+ val request = it.getArgument<Consumer<List<GroupTask>>?>(0)
+ if (request != null) {
+ taskRequests.add { response -> request.accept(response) }
+ }
+ taskListId
+ }
+
+ on { getTasks(anyOrNull()) } doAnswer
+ {
+ val request = it.getArgument<Consumer<List<GroupTask>>?>(0)
+ if (request != null) {
+ taskRequests.add { response -> request.accept(response) }
+ }
+ taskListId
+ }
+
+ on { isTaskListValid(any()) } doAnswer { taskListId == it.getArgument(0) }
+ }
+
+ private var recentTasks: List<GroupTask> = emptyList()
+ private var taskListId = 0
+ private var recentTasksChangedListener: RecentTasksChangedListener? = null
+ private var taskRequests: MutableList<(List<GroupTask>) -> Unit> = mutableListOf()
+
+ override fun apply(base: Statement?, description: Description?): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ context.putObject(RecentsModel.INSTANCE, mockRecentsModel)
+ base?.evaluate()
+ }
+ }
+ }
+
+ // NOTE: For the update to take effect, `resolvePendingTaskRequests()` needs to be called, so
+ // calbacks to any pending `RecentsModel.getTasks()` get called with the updated task list.
+ fun updateRecentTasks(tasks: List<GroupTask>) {
+ ++taskListId
+ recentTasks = tasks
+ recentTasksChangedListener?.onRecentTasksChanged()
+ }
+
+ fun resolvePendingTaskRequests() {
+ val requests = mutableListOf<(List<GroupTask>) -> Unit>()
+ requests.addAll(taskRequests)
+ taskRequests.clear()
+
+ requests.forEach { it(recentTasks) }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
index 096f879..cd4e78b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
@@ -37,6 +37,7 @@
import com.android.quickstep.AllAppsActionManager
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
+import java.util.Locale
import java.util.Optional
import org.junit.Assume.assumeTrue
import org.junit.rules.TestRule
@@ -119,6 +120,15 @@
}
}
+ if (description.getAnnotation(ForceRtl::class.java) != null) {
+ // Needs to be set on window context instead of sandbox context, because it does
+ // does not propagate between them. However, this change will impact created
+ // TaskbarActivityContext instances, since they wrap the window context.
+ taskbarManager.windowContext.resources.configuration.setLayoutDirection(
+ RTL_LOCALE
+ )
+ }
+
try {
TaskbarViewController.enableModelLoadingForTests(false)
@@ -191,4 +201,11 @@
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class NavBarKidsMode
+
+ /** Forces RTL UI for tests. */
+ @Retention(AnnotationRetention.RUNTIME)
+ @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
+ annotation class ForceRtl
}
+
+private val RTL_LOCALE = Locale.of("ar", "XB")
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
index 7daa142..b8b0b5d 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
@@ -19,11 +19,13 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.Utilities
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.TaskbarKeyguardController
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.taskbar.TaskbarStashController
import com.android.launcher3.taskbar.bubbles.BubbleBarController
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.ForceRtl
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.NavBarKidsMode
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.UserSetupMode
@@ -197,6 +199,14 @@
}
}
+ @Test
+ fun testForceRtlAnnotation_setsActivityContextLayoutDirection() {
+ @ForceRtl class Rtl
+ onSetup(description = Description.createSuiteDescription(Rtl::class.java)) {
+ assertThat(Utilities.isRtl(activityContext.resources)).isTrue()
+ }
+ }
+
/**
* Executes [runTest] after the [testRule] setup phase completes.
*
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index dc5223c..970bdec 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -17,6 +17,7 @@
package com.android.quickstep;
import static com.android.quickstep.AbsSwipeUpHandler.STATE_HANDLER_INVALIDATED;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
@@ -28,6 +29,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -40,6 +42,9 @@
import android.graphics.Rect;
import android.os.Bundle;
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.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.ViewTreeObserver;
@@ -58,6 +63,7 @@
import com.android.quickstep.util.ContextInitListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.Flags;
import com.android.systemui.shared.system.InputConsumerController;
import org.junit.Before;
@@ -80,8 +86,6 @@
protected final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
- protected final RecentsAnimationDeviceState mRecentsAnimationDeviceState =
- new RecentsAnimationDeviceState(mContext, true);
protected final InputConsumerController mInputConsumerController =
InputConsumerController.getRecentsAnimationInputConsumer();
protected final ActivityManager.RunningTaskInfo mRunningTaskInfo =
@@ -105,15 +109,10 @@
/* startBounds= */ null,
/* taskInfo= */ mRunningTaskInfo,
/* allowEnterPip= */ false);
- protected final RecentsAnimationTargets mRecentsAnimationTargets = new RecentsAnimationTargets(
- new RemoteAnimationTarget[] {mRemoteAnimationTarget},
- new RemoteAnimationTarget[] {mRemoteAnimationTarget},
- new RemoteAnimationTarget[] {mRemoteAnimationTarget},
- /* homeContentInsets= */ new Rect(),
- /* minimizedHomeBounds= */ null,
- new Bundle());
+ protected RecentsAnimationTargets mRecentsAnimationTargets;
protected TaskAnimationManager mTaskAnimationManager;
+ protected RecentsAnimationDeviceState mRecentsAnimationDeviceState;
@Mock protected CONTAINER_INTERFACE mActivityInterface;
@Mock protected ContextInitListener<?> mContextInitListener;
@@ -128,6 +127,22 @@
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Before
+ public void setUpAnimationTargets() {
+ Bundle extras = new Bundle();
+ extras.putBoolean(KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION, true);
+ mRecentsAnimationTargets = new RecentsAnimationTargets(
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ /* homeContentInsets= */ new Rect(),
+ /* minimizedHomeBounds= */ null,
+ extras);
+ }
+
@Before
public void setUpRunningTaskInfo() {
mRunningTaskInfo.baseIntent = new Intent(Intent.ACTION_MAIN)
@@ -176,6 +191,12 @@
}).when(recentsContainer).runOnBindToTouchInteractionService(any());
}
+ @Before
+ public void setUpRecentsAnimationDeviceState() {
+ runOnMainSync(() ->
+ mRecentsAnimationDeviceState = new RecentsAnimationDeviceState(mContext, true));
+ }
+
@Test
public void testInitWhenReady_registersActivityInitListener() {
String reasonString = "because i said so";
@@ -232,6 +253,30 @@
});
}
+ @EnableFlags({Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED})
+ @Test
+ public void testHomeGesture_handsOffAnimation() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME);
+
+ runOnMainSync(() -> {
+ verify(mRecentsAnimationController).handOffAnimation(any(), any());
+ verifyRecentsAnimationFinishedAndCallCallback();
+ });
+ }
+
+ @DisableFlags({Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED})
+ @Test
+ public void testHomeGesture_doesNotHandOffAnimation_withFlagsDisabled() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME);
+
+ runOnMainSync(() -> {
+ verify(mRecentsAnimationController, never()).handOffAnimation(any(), any());
+ verifyRecentsAnimationFinishedAndCallCallback();
+ });
+ }
+
@Test
public void testHomeGesture_invalidatesHandlerAfterParallelAnim() {
ValueAnimator parallelAnim = new ValueAnimator();
@@ -306,8 +351,6 @@
}
private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
- when(mActivityInterface.getOverviewWindowBounds(any(), any())).thenReturn(new Rect());
-
runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
mRecentsAnimationController, mRecentsAnimationTargets));
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/DesktopFullscreenDrawParamsTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/DesktopFullscreenDrawParamsTest.kt
new file mode 100644
index 0000000..e62455f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/DesktopFullscreenDrawParamsTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+/** Test for [DesktopFullscreenDrawParams] class. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DesktopFullscreenDrawParamsTest() {
+ private val params =
+ DesktopFullscreenDrawParams(mock<Context>(), cornerRadiusProvider = { CORNER_RADIUS })
+
+ @Test
+ fun setMiddleProgress_invariantCornerRadiusForDesktop() {
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(CORNER_RADIUS)
+
+ params.setProgress(fullscreenProgress = 0.67f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(CORNER_RADIUS)
+
+ params.setProgress(fullscreenProgress = 1f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(CORNER_RADIUS)
+ }
+
+ companion object {
+ const val CORNER_RADIUS = 32f
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index 5d62a4c..99b81e0 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -20,21 +20,17 @@
import androidx.test.filters.SmallTest
import com.android.launcher3.FakeInvariantDeviceProfileTest
import com.android.quickstep.util.TaskCornerRadius
-import com.android.quickstep.views.TaskView.FullscreenDrawParams
import com.android.systemui.shared.system.QuickStepContract
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
+import org.mockito.kotlin.mock
-/** Test for FullscreenDrawParams class. */
+/** Test for [FullscreenDrawParams] class. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class FullscreenDrawParamsTest : FakeInvariantDeviceProfileTest() {
-
private lateinit var params: FullscreenDrawParams
@Before
@@ -46,115 +42,108 @@
fun setStartProgress_correctCornerRadiusForTablet() {
initializeVarsForTablet()
- params.setProgress(
- /* fullscreenProgress= */ 0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1.0f, taskViewScale = 1.0f)
val expectedRadius = TaskCornerRadius.get(context)
- assertThat(params.currentDrawnCornerRadius).isEqualTo(expectedRadius)
+ assertThat(params.currentCornerRadius).isEqualTo(expectedRadius)
}
@Test
fun setFullProgress_correctCornerRadiusForTablet() {
initializeVarsForTablet()
- params.setProgress(
- /* fullscreenProgress= */ 1.0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
+ params.setProgress(fullscreenProgress = 1.0f, parentScale = 1f, taskViewScale = 1f)
val expectedRadius = QuickStepContract.getWindowCornerRadius(context)
- assertThat(params.currentDrawnCornerRadius).isEqualTo(expectedRadius)
+ assertThat(params.currentCornerRadius).isEqualTo(expectedRadius)
}
@Test
fun setStartProgress_correctCornerRadiusForPhone() {
initializeVarsForPhone()
- params.setProgress(
- /* fullscreenProgress= */ 0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1f, taskViewScale = 1f)
val expectedRadius = TaskCornerRadius.get(context)
- assertThat(params.currentDrawnCornerRadius).isEqualTo(expectedRadius)
+ assertThat(params.currentCornerRadius).isEqualTo(expectedRadius)
}
@Test
fun setFullProgress_correctCornerRadiusForPhone() {
initializeVarsForPhone()
- params.setProgress(
- /* fullscreenProgress= */ 1.0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
+ params.setProgress(fullscreenProgress = 1.0f, parentScale = 1f, taskViewScale = 1f)
val expectedRadius = QuickStepContract.getWindowCornerRadius(context)
- assertThat(params.currentDrawnCornerRadius).isEqualTo(expectedRadius)
+ assertThat(params.currentCornerRadius).isEqualTo(expectedRadius)
}
@Test
fun setStartProgress_correctCornerRadiusForMultiDisplay() {
- val display1Context = context
- val display2Context = mock(Context::class.java)
- val spyParams = spy(params)
+ val display1Context = mock<Context>()
+ val display2Context = mock<Context>()
+ val display1TaskRadius = TASK_CORNER_RADIUS + 1
+ val display2TaskRadius = TASK_CORNER_RADIUS + 2
- val display1TaskRadius = TaskCornerRadius.get(display1Context)
- val display1WindowRadius = QuickStepContract.getWindowCornerRadius(display1Context)
- val display2TaskRadius = display1TaskRadius * 2 + 1 // Arbitrarily different.
- val display2WindowRadius = display1WindowRadius * 2 + 1 // Arbitrarily different.
- doReturn(display2TaskRadius).`when`(spyParams).computeTaskCornerRadius(display2Context)
- doReturn(display2WindowRadius).`when`(spyParams).computeWindowCornerRadius(display2Context)
+ val params =
+ FullscreenDrawParams(
+ context,
+ taskCornerRadiusProvider = { context ->
+ when (context) {
+ display1Context -> display1TaskRadius
+ display2Context -> display2TaskRadius
+ else -> TASK_CORNER_RADIUS
+ }
+ },
+ windowCornerRadiusProvider = { 0f },
+ )
- spyParams.updateCornerRadius(display1Context)
- spyParams.setProgress(
- /* fullscreenProgress= */ 0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
- assertThat(spyParams.currentDrawnCornerRadius).isEqualTo(display1TaskRadius)
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(TASK_CORNER_RADIUS)
- spyParams.updateCornerRadius(display2Context)
- spyParams.setProgress(
- /* fullscreenProgress= */ 0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
- assertThat(spyParams.currentDrawnCornerRadius).isEqualTo(display2TaskRadius)
+ params.updateCornerRadius(display1Context)
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(display1TaskRadius)
+
+ params.updateCornerRadius(display2Context)
+ params.setProgress(fullscreenProgress = 0f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(display2TaskRadius)
}
@Test
fun setFullProgress_correctCornerRadiusForMultiDisplay() {
- val display1Context = context
- val display2Context = mock(Context::class.java)
- val spyParams = spy(params)
+ val display1Context = mock<Context>()
+ val display2Context = mock<Context>()
+ val display1WindowRadius = WINDOW_CORNER_RADIUS + 1
+ val display2WindowRadius = WINDOW_CORNER_RADIUS + 2
- val display1TaskRadius = TaskCornerRadius.get(display1Context)
- val display1WindowRadius = QuickStepContract.getWindowCornerRadius(display1Context)
- val display2TaskRadius = display1TaskRadius * 2 + 1 // Arbitrarily different.
- val display2WindowRadius = display1WindowRadius * 2 + 1 // Arbitrarily different.
- doReturn(display2TaskRadius).`when`(spyParams).computeTaskCornerRadius(display2Context)
- doReturn(display2WindowRadius).`when`(spyParams).computeWindowCornerRadius(display2Context)
+ val params =
+ FullscreenDrawParams(
+ context,
+ taskCornerRadiusProvider = { 0f },
+ windowCornerRadiusProvider = { context ->
+ when (context) {
+ display1Context -> display1WindowRadius
+ display2Context -> display2WindowRadius
+ else -> WINDOW_CORNER_RADIUS
+ }
+ },
+ )
- spyParams.updateCornerRadius(display1Context)
- spyParams.setProgress(
- /* fullscreenProgress= */ 1.0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f
- )
- assertThat(spyParams.currentDrawnCornerRadius).isEqualTo(display1WindowRadius)
+ params.setProgress(fullscreenProgress = 1f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(WINDOW_CORNER_RADIUS)
- spyParams.updateCornerRadius(display2Context)
- spyParams.setProgress(
- /* fullscreenProgress= */ 1.0f,
- /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f,
- )
- assertThat(spyParams.currentDrawnCornerRadius).isEqualTo(display2WindowRadius)
+ params.updateCornerRadius(display1Context)
+ params.setProgress(fullscreenProgress = 1f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(display1WindowRadius)
+
+ params.updateCornerRadius(display2Context)
+ params.setProgress(fullscreenProgress = 1f, parentScale = 1f, taskViewScale = 1f)
+ assertThat(params.currentCornerRadius).isEqualTo(display2WindowRadius)
+ }
+
+ companion object {
+ const val TASK_CORNER_RADIUS = 56f
+ const val WINDOW_CORNER_RADIUS = 32f
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
index e3a6adf..a777bd4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
@@ -37,8 +37,6 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskContainerData
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModelImpl
-import com.android.quickstep.task.viewmodel.TaskViewData
-import com.android.quickstep.views.TaskViewType
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import com.google.common.truth.Truth.assertThat
@@ -57,9 +55,7 @@
private val dispatcher = StandardTestDispatcher()
private val testScope = TestScope(dispatcher)
- private var taskViewType = TaskViewType.SINGLE
private val recentsViewData = RecentsViewData()
- private val taskViewData by lazy { TaskViewData(taskViewType) }
private val taskContainerData = TaskContainerData()
private val dispatcherProvider = TestDispatcherProvider(dispatcher)
private val tasksRepository = FakeTasksRepository()
@@ -69,7 +65,6 @@
private val systemUnderTest by lazy {
TaskThumbnailViewModelImpl(
recentsViewData,
- taskViewData,
taskContainerData,
dispatcherProvider,
tasksRepository,
@@ -124,40 +119,6 @@
}
@Test
- fun setRecentsFullscreenProgress_thenCornerRadiusProgressIsPassedThrough() =
- testScope.runTest {
- recentsViewData.fullscreenProgress.value = 0.5f
-
- assertThat(systemUnderTest.cornerRadiusProgress.first()).isEqualTo(0.5f)
-
- recentsViewData.fullscreenProgress.value = 0.6f
-
- assertThat(systemUnderTest.cornerRadiusProgress.first()).isEqualTo(0.6f)
- }
-
- @Test
- fun setRecentsFullscreenProgress_thenCornerRadiusProgressIsConstantForDesktop() =
- testScope.runTest {
- taskViewType = TaskViewType.DESKTOP
- recentsViewData.fullscreenProgress.value = 0.5f
-
- assertThat(systemUnderTest.cornerRadiusProgress.first()).isEqualTo(1f)
-
- recentsViewData.fullscreenProgress.value = 0.6f
-
- assertThat(systemUnderTest.cornerRadiusProgress.first()).isEqualTo(1f)
- }
-
- @Test
- fun setAncestorScales_thenScaleIsCalculated() =
- testScope.runTest {
- recentsViewData.scale.value = 0.5f
- taskViewData.scale.value = 0.6f
-
- assertThat(systemUnderTest.inheritedScale.first()).isEqualTo(0.3f)
- }
-
- @Test
fun bindRunningTaskThenStoppedTaskWithoutThumbnail_thenStateChangesToBackgroundOnly() =
testScope.runTest {
val runningTaskId = 1
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index 541a48d..ee70e0a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -202,7 +202,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -226,7 +226,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -250,7 +250,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -274,7 +274,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -298,7 +298,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -322,7 +322,7 @@
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -341,12 +341,16 @@
whenever(mockTaskKey1.getId()).thenReturn(1)
whenever(mockTaskKey2.getId()).thenReturn(2)
// ... with app 1 already on screen
- whenever(mockCachedTaskInfo.taskId).thenReturn(1)
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ whenever(mockCachedTaskInfo.topGroupedTaskContainsTask(eq(1))).thenReturn(true)
+ } else {
+ whenever(mockCachedTaskInfo.taskId).thenReturn(1)
+ }
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -365,12 +369,16 @@
whenever(mockTaskKey1.getId()).thenReturn(1)
whenever(mockTaskKey2.getId()).thenReturn(2)
// ... with app 2 already on screen
- whenever(mockCachedTaskInfo.taskId).thenReturn(2)
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ whenever(mockCachedTaskInfo.topGroupedTaskContainsTask(eq(2))).thenReturn(true)
+ } else {
+ whenever(mockCachedTaskInfo.taskId).thenReturn(2)
+ }
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
@@ -389,12 +397,16 @@
whenever(mockTaskKey1.getId()).thenReturn(1)
whenever(mockTaskKey2.getId()).thenReturn(2)
// ... with app 3 already on screen
- whenever(mockCachedTaskInfo.taskId).thenReturn(3)
+ if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
+ whenever(mockCachedTaskInfo.topGroupedTaskContainsTask(eq(3))).thenReturn(true)
+ } else {
+ whenever(mockCachedTaskInfo.taskId).thenReturn(3)
+ }
// Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
spyAppPairsController.handleAppPairLaunchInApp(
mockAppPairIcon,
- listOf(mockItemInfo1, mockItemInfo2)
+ listOf(mockItemInfo1, mockItemInfo2),
)
verify(splitSelectStateController)
.findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 72cfd92..fa81680 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -202,7 +202,7 @@
mDeviceProfile.updateInsets(mLauncherInsets);
TaskViewSimulator tvs = new TaskViewSimulator(helper.sandboxContext,
- FallbackActivityInterface.INSTANCE);
+ FallbackActivityInterface.INSTANCE, false, 0);
tvs.setDp(mDeviceProfile);
int launcherRotation = info.rotation;
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
new file mode 100644
index 0000000..5dc6932
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.quickstep.InputConsumerUtils.newBaseConsumer;
+import static com.android.quickstep.InputConsumerUtils.newConsumer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+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.MotionEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleCreator;
+import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
+import com.android.launcher3.taskbar.bubbles.BubbleDragController;
+import com.android.launcher3.taskbar.bubbles.BubblePinController;
+import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.util.LockedUserState;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
+import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
+import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
+import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
+import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
+import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
+import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
+import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
+import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
+import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
+import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.util.NavBarPosition;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.inject.Provider;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputConsumerUtilsTest {
+
+ @NonNull private final MainThreadInitializedObject.SandboxContext mContext =
+ new MainThreadInitializedObject.SandboxContext(getApplicationContext());
+ @NonNull private final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(
+ mContext, mock(RecentsWindowManager.class));
+ @NonNull private final InputMonitorCompat mInputMonitorCompat = new InputMonitorCompat("", 0);
+
+ private InputChannelCompat.InputEventReceiver mInputEventReceiver;
+ @Nullable private ResetGestureInputConsumer mResetGestureInputConsumer;
+ @NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null;
+
+ @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext;
+ @NonNull @Mock private OverviewComponentObserver mOverviewComponentObserver;
+ @NonNull @Mock private RecentsAnimationDeviceState mDeviceState;
+ @NonNull @Mock private AbsSwipeUpHandler.Factory mSwipeUpHandlerFactory;
+ @NonNull @Mock private TaskbarManager mTaskbarManager;
+ @NonNull @Mock private OverviewCommandHelper mOverviewCommandHelper;
+ @NonNull @Mock private GestureState mPreviousGestureState;
+ @NonNull @Mock private GestureState mCurrentGestureState;
+ @NonNull @Mock private LockedUserState mLockedUserState;
+ @NonNull @Mock private TopTaskTracker.CachedTaskInfo mRunningTask;
+ @NonNull @Mock private BaseContainerInterface<?, ?> mContainerInterface;
+ @NonNull @Mock private BaseDragLayer<?> mBaseDragLayer;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setupMainThreadInitializedObjects() {
+ mContext.putObject(LockedUserState.INSTANCE, mLockedUserState);
+ }
+
+ @Before
+ public void setUpInputEventReceiver() {
+ runOnMainSync(() ->
+ mInputEventReceiver = mInputMonitorCompat.getInputReceiver(
+ Looper.getMainLooper(),
+ Choreographer.getInstance(),
+ event -> {}));
+ }
+
+ @Before
+ public void setUpTaskbarActivityContext() {
+ NavHandle navHandle = mock(NavHandle.class);
+
+ when(navHandle.canNavHandleBeLongPressed()).thenReturn(true);
+
+ when(mTaskbarActivityContext.getDeviceProfile()).thenReturn(new DeviceProfile());
+ when(mTaskbarActivityContext.getNavHandle()).thenReturn(navHandle);
+ }
+
+ @Before
+ public void setUpTaskbarManager() {
+ when(mTaskbarManager.getCurrentActivityContext()).thenReturn(mTaskbarActivityContext);
+ }
+
+ @Before
+ public void setUpResetGestureInputConsumer() {
+ mResetGestureInputConsumer = new ResetGestureInputConsumer(
+ mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
+ }
+
+ @Before
+ public void setupLockedUserState() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(true);
+ }
+
+ @Before
+ public void setupGestureStates() {
+ when(mCurrentGestureState.getRunningTask()).thenReturn(mRunningTask);
+ doReturn(mContainerInterface).when(mCurrentGestureState).getContainerInterface();
+ }
+
+ @Before
+ public void setUpContainerInterface() {
+ RecentsViewContainer recentsViewContainer = mock(RecentsViewContainer.class);
+
+ when(recentsViewContainer.getDragLayer()).thenReturn(mBaseDragLayer);
+ when(recentsViewContainer.getRootView()).thenReturn(mBaseDragLayer);
+ when(recentsViewContainer.asContext()).thenReturn(mContext);
+
+ doReturn(recentsViewContainer).when(mContainerInterface).getCreatedContainer();
+ }
+
+ @Before
+ public void setupBaseDragLayer() {
+ when(mBaseDragLayer.hasWindowFocus()).thenReturn(true);
+ }
+
+ @Before
+ public void setupDeviceState() {
+ when(mDeviceState.canStartTrackpadGesture()).thenReturn(true);
+ when(mDeviceState.canStartSystemGesture()).thenReturn(true);
+ when(mDeviceState.isFullyGesturalNavMode()).thenReturn(true);
+ when(mDeviceState.getNavBarPosition()).thenReturn(mock(NavBarPosition.class));
+ when(mDeviceState.getRotationTouchHelper()).thenReturn(mock(RotationTouchHelper.class));
+ }
+
+ @After
+ public void cleanUp() {
+ mInputMonitorCompat.dispose();
+ mInputEventReceiver.dispose();
+ }
+
+ @Test
+ public void testNewBaseConsumer_onKeyguard_returnsDeviceLockedInputConsumer() {
+ when(mDeviceState.isKeyguardShowingOccluded()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ DeviceLockedInputConsumer.class,
+ InputConsumer.TYPE_DEVICE_LOCKED);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onLiveTileModeWithNoContainer_returnsDefaultInputConsumer() {
+ when(mContainerInterface.isInLiveTileMode()).thenReturn(true);
+ when(mContainerInterface.getCreatedContainer()).thenReturn(null);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onLiveTileMode_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isInLiveTileMode()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_withNoRunningTask_returnsDefaultInputConsumer() {
+ when(mCurrentGestureState.getRunningTask()).thenReturn(null);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_prevGestureAnimatingToLauncher_returnsOverviewInputConsumer() {
+ when(mPreviousGestureState.isRunningAnimationToLauncher()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_predictiveBackToHomeInProgress_returnsOverviewInputConsumer() {
+ when(mDeviceState.isPredictiveBackToHomeInProgress()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_resumedThroughShellTransition_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_shellNoWindowFocus_returnsOverviewWithoutFocusInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+ when(mBaseDragLayer.hasWindowFocus()).thenReturn(false);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewWithoutFocusInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW_WITHOUT_FOCUS);
+ }
+
+ @Test
+ public void testNewBaseConsumer_forceOverviewInputConsumer_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+ when(mRunningTask.isRootChooseActivity()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_launcherChildActivityResumed_returnsDefaultInputConsumer() {
+ when(mRunningTask.isHomeTask()).thenReturn(true);
+ when(mOverviewComponentObserver.isHomeAndOverviewSame()).thenReturn(true);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onGestureBlockedTask_returnsDefaultInputConsumer() {
+ when(mDeviceState.isGestureBlockedTask(any())).thenReturn(true);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_containsOtherActivityInputConsumer() {
+ // OtherActivityInputConsumer needs to be initialized on the main thread because of
+ // MotionPauseDetector.mForcePauseTimeout
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY);
+ }
+
+ @Test
+ public void testNewConsumer_containsOtherActivityInputConsumer() {
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS);
+ }
+
+ @Test
+ public void testNewConsumer_eventCanTriggerAssistantAction_containsAssistantInputConsumer() {
+ when(mDeviceState.canTriggerAssistantAction(any())).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ASSISTANT);
+ }
+
+ @Test
+ public void testNewConsumer_taskbarIsPresent_containsTaskbarUnstashInputConsumer() {
+ DeviceProfile deviceProfile = new DeviceProfile();
+ deviceProfile.isTaskbarPresent = true;
+ when(mTaskbarActivityContext.getDeviceProfile()).thenReturn(deviceProfile);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_TASKBAR_STASH
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_CURSOR_HOVER);
+ }
+
+ @Test
+ public void testNewConsumer_whileSystemUiDialogShowing_returnsSysUiOverlayInputConsumer() {
+ when(mDeviceState.isSystemUiDialogShowing()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ SysUiOverlayInputConsumer.class,
+ InputConsumer.TYPE_SYSUI_OVERLAY);
+ }
+
+ @Test
+ public void testNewConsumer_onTrackpadGesture_returnsTrackpadStatusBarInputConsumer() {
+ when(mCurrentGestureState.isTrackpadGesture()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ TrackpadStatusBarInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_STATUS_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_whileScreenPinningActive_returnsScreenPinnedInputConsumer() {
+ when(mDeviceState.isScreenPinningActive()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ ScreenPinnedInputConsumer.class,
+ InputConsumer.TYPE_SCREEN_PINNED);
+ }
+
+ @Test
+ public void testNewConsumer_canTriggerOneHandedAction_returnsOneHandedModeInputConsumer() {
+ when(mDeviceState.canTriggerOneHandedAction(any())).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ OneHandedModeInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ONE_HANDED);
+ }
+
+ @Test
+ public void testNewConsumer_accessibilityMenuAvailable_returnsAccessibilityInputConsumer() {
+ when(mDeviceState.isAccessibilityMenuAvailable()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ AccessibilityInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ACCESSIBILITY);
+ }
+
+ @Test
+ public void testNewConsumer_onStashedBubbleBar_returnsBubbleBarInputConsumer() {
+ BubbleControllers bubbleControllers = createBubbleControllers(/* isStashed= */ true);
+
+ when(mTaskbarActivityContext.isBubbleBarEnabled()).thenReturn(true);
+ when(mTaskbarActivityContext.getBubbleControllers()).thenReturn(bubbleControllers);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ BubbleBarInputConsumer.class,
+ InputConsumer.TYPE_BUBBLE_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_onVisibleBubbleBar_returnsBubbleBarInputConsumer() {
+ BubbleControllers bubbleControllers = createBubbleControllers(/* isStashed= */ false);
+
+ when(mTaskbarActivityContext.isBubbleBarEnabled()).thenReturn(true);
+ when(mTaskbarActivityContext.getBubbleControllers()).thenReturn(bubbleControllers);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ BubbleBarInputConsumer.class,
+ InputConsumer.TYPE_BUBBLE_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_withSwipeUpProxyProvider_returnsProgressDelegateInputConsumer() {
+ mSwipeUpProxyProvider = (state) -> new AnimatedFloat();
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ ProgressDelegateInputConsumer.class,
+ InputConsumer.TYPE_PROGRESS_DELEGATE);
+ }
+
+ @Test
+ public void testNewConsumer_onLockedState_returnsDeviceLockedInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ DeviceLockedInputConsumer.class,
+ InputConsumer.TYPE_DEVICE_LOCKED);
+ }
+
+ @Test
+ public void testNewConsumer_cannotStartSysGestureOnLockedState_returnsDefaultInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+ when(mDeviceState.canStartSystemGesture()).thenReturn(false);
+
+ assertEqualsDefaultInputConsumer(this::createInputConsumer);
+ }
+
+ @Test
+ public void testNewConsumer_cannotStartTrackGestureOnLockedState_returnsDefaultInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+ when(mCurrentGestureState.isTrackpadGesture()).thenReturn(true);
+ when(mDeviceState.canStartTrackpadGesture()).thenReturn(false);
+
+ assertEqualsDefaultInputConsumer(this::createInputConsumer);
+ }
+
+ private InputConsumer createInputConsumer() {
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ InputConsumer inputConsumer = newConsumer(
+ mContext,
+ mContext,
+ mResetGestureInputConsumer,
+ mOverviewComponentObserver,
+ mDeviceState,
+ mPreviousGestureState,
+ mCurrentGestureState,
+ mTaskAnimationManager,
+ mInputMonitorCompat,
+ mSwipeUpHandlerFactory,
+ otherActivityInputConsumer -> {},
+ mInputEventReceiver,
+ mTaskbarManager,
+ mSwipeUpProxyProvider,
+ mOverviewCommandHelper,
+ event);
+
+ event.recycle();
+
+ return inputConsumer;
+ }
+
+ private InputConsumer createBaseInputConsumer() {
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ InputConsumer inputConsumer = newBaseConsumer(
+ mContext,
+ mResetGestureInputConsumer,
+ mOverviewComponentObserver,
+ mDeviceState,
+ mPreviousGestureState,
+ mCurrentGestureState,
+ mTaskAnimationManager,
+ mInputMonitorCompat,
+ mSwipeUpHandlerFactory,
+ otherActivityInputConsumer -> {},
+ mInputEventReceiver,
+ event,
+ ActiveGestureLog.CompoundString.NO_OP);
+
+ event.recycle();
+
+ return inputConsumer;
+ }
+
+ private void assertEqualsDefaultInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider) {
+ assertCorrectInputConsumer(
+ inputConsumerProvider,
+ ResetGestureInputConsumer.class,
+ InputConsumer.TYPE_RESET_GESTURE);
+
+ mResetGestureInputConsumer = null;
+
+ runOnMainSync(() -> assertThat(inputConsumerProvider.get()).isEqualTo(InputConsumer.NO_OP));
+ }
+
+ private static void assertCorrectInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider,
+ @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
+ int expectedType) {
+ assertCorrectInputConsumer(
+ inputConsumerProvider,
+ expectedOutputConsumer,
+ expectedOutputConsumer,
+ expectedType);
+ }
+
+ private static void assertCorrectInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider,
+ @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
+ @NonNull Class<? extends InputConsumer> expectedActiveConsumer,
+ int expectedType) {
+ runOnMainSync(() -> {
+ InputConsumer inputConsumer = inputConsumerProvider.get();
+
+ assertThat(inputConsumer).isInstanceOf(expectedOutputConsumer);
+ assertThat(inputConsumer.getActiveConsumerInHierarchy())
+ .isInstanceOf(expectedActiveConsumer);
+ assertThat(inputConsumer.getType()).isEqualTo(expectedType);
+ });
+ }
+
+ private static void runOnMainSync(@NonNull Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
+
+ private static BubbleControllers createBubbleControllers(boolean isStashed) {
+ BubbleBarController bubbleBarController = mock(BubbleBarController.class);
+ BubbleBarViewController bubbleBarViewController = mock(BubbleBarViewController.class);
+ BubbleStashController bubbleStashController = mock(BubbleStashController.class);
+ BubbleStashedHandleViewController bubbleStashedHandleViewController =
+ mock(BubbleStashedHandleViewController.class);
+ BubbleDragController bubbleDragController = mock(BubbleDragController.class);
+ BubbleDismissController bubbleDismissController = mock(BubbleDismissController.class);
+ BubbleBarPinController bubbleBarPinController = mock(BubbleBarPinController.class);
+ BubblePinController bubblePinController = mock(BubblePinController.class);
+ BubbleBarSwipeController bubbleBarSwipeController = mock(BubbleBarSwipeController.class);
+ BubbleCreator bubbleCreator = mock(BubbleCreator.class);
+ BubbleControllers bubbleControllers = new BubbleControllers(
+ bubbleBarController,
+ bubbleBarViewController,
+ bubbleStashController,
+ Optional.of(bubbleStashedHandleViewController),
+ bubbleDragController,
+ bubbleDismissController,
+ bubbleBarPinController,
+ bubblePinController,
+ Optional.of(bubbleBarSwipeController),
+ bubbleCreator);
+
+ when(bubbleBarViewController.hasBubbles()).thenReturn(true);
+ when(bubbleStashController.isStashed()).thenReturn(isStashed);
+ when(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(true);
+ when(bubbleBarViewController.isBubbleBarVisible()).thenReturn(!isStashed);
+ when(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(true);
+
+ return bubbleControllers;
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index a8f39af..2fb08dd 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -16,6 +16,8 @@
package com.android.quickstep;
+import android.util.Log;
+
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,6 +31,8 @@
@RunWith(AndroidJUnit4.class)
public class TaplStartLauncherViaGestureTests extends AbstractQuickStepTest {
+ public static final String TAG = "TaplStartLauncherViaGestureTests";
+
static final int STRESS_REPEAT_COUNT = 10;
private enum TestCase {
@@ -69,7 +73,9 @@
}
private void runTest(TestCase testCase) {
+ long testStartTime = System.currentTimeMillis();
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
+ long loopStartTime = System.currentTimeMillis();
// Destroy Launcher activity.
closeLauncherActivity();
@@ -84,7 +90,10 @@
default:
throw new IllegalStateException("Cannot run test case: " + testCase);
}
+ Log.d(TAG, "Loop " + (i + 1) + " runtime="
+ + (System.currentTimeMillis() - loopStartTime) + "ms");
}
+ Log.d(TAG, "Test runtime=" + (System.currentTimeMillis() - testStartTime) + "ms");
switch (testCase) {
case TO_OVERVIEW:
closeLauncherActivity();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
index 43ebb17..3c4f1d9 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
@@ -49,6 +49,7 @@
DISMISS(0),
LAUNCH_LAST_APP(0),
LAUNCH_SELECTED_APP(1),
+ DISMISS_WHEN_GOING_HOME(1),
LAUNCH_OVERVIEW(KeyboardQuickSwitchController.MAX_TASKS - 1);
private final int mNumAdditionalRunningTasks;
@@ -156,6 +157,11 @@
mLauncher.goHome().showQuickSwitchView().launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
}
+ @Test
+ public void testDismissedWhenGoingHome() {
+ runTest(TestSurface.LAUNCHED_APP, TestCase.DISMISS_WHEN_GOING_HOME);
+ }
+
private void runTest(@NonNull TestSurface testSurface, @NonNull TestCase testCase) {
for (int i = 0; i < testCase.mNumAdditionalRunningTasks; i++) {
startTestActivity(3 + i);
@@ -197,6 +203,9 @@
}
kqs.launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
break;
+ case DISMISS_WHEN_GOING_HOME:
+ kqs.dismissByGoingHome();
+ break;
case LAUNCH_OVERVIEW:
kqs.moveFocusBackward();
if (!testSurface.mInitialFocusAtZero) {
diff --git a/res/drawable/all_apps_tabs_background_selected.xml b/res/drawable/all_apps_tabs_background_selected.xml
index 47f95dd..6560632 100644
--- a/res/drawable/all_apps_tabs_background_selected.xml
+++ b/res/drawable/all_apps_tabs_background_selected.xml
@@ -15,10 +15,10 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:bottom="@dimen/all_apps_tabs_focus_width"
- android:end="@dimen/all_apps_tabs_focus_width"
- android:start="@dimen/all_apps_tabs_focus_width"
- android:top="@dimen/all_apps_tabs_focus_width">
+ android:bottom="@dimen/all_apps_tabs_focus_vertical_inset"
+ android:end="@dimen/all_apps_tabs_focus_horizontal_inset"
+ android:start="@dimen/all_apps_tabs_focus_horizontal_inset"
+ android:top="@dimen/all_apps_tabs_focus_vertical_inset">
<shape android:shape="rectangle">
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
<solid android:color="?attr/materialColorPrimary" />
diff --git a/res/drawable/all_apps_tabs_background_unselected.xml b/res/drawable/all_apps_tabs_background_unselected.xml
index ab592a8..ce7b334 100644
--- a/res/drawable/all_apps_tabs_background_unselected.xml
+++ b/res/drawable/all_apps_tabs_background_unselected.xml
@@ -15,10 +15,10 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:bottom="@dimen/all_apps_tabs_focus_width"
- android:end="@dimen/all_apps_tabs_focus_width"
- android:start="@dimen/all_apps_tabs_focus_width"
- android:top="@dimen/all_apps_tabs_focus_width">
+ android:bottom="@dimen/all_apps_tabs_focus_vertical_inset"
+ android:end="@dimen/all_apps_tabs_focus_horizontal_inset"
+ android:start="@dimen/all_apps_tabs_focus_horizontal_inset"
+ android:top="@dimen/all_apps_tabs_focus_vertical_inset">
<shape android:shape="rectangle">
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
<solid android:color="?attr/materialColorSurfaceBright" />
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index d113a38..2bb2eb3 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -71,7 +71,8 @@
android:id="@+id/widget_preview_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_marginVertical="16dp"
+ android:layout_margin="16dp"
+ android:background="@drawable/widgets_surface_background"
android:layout_weight="1">
<include
diff --git a/res/layout/all_apps_personal_work_tabs.xml b/res/layout/all_apps_personal_work_tabs.xml
index ecc5a14..b6a8ed8 100644
--- a/res/layout/all_apps_personal_work_tabs.xml
+++ b/res/layout/all_apps_personal_work_tabs.xml
@@ -21,8 +21,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_header_pill_height"
android:layout_gravity="center_horizontal"
- android:paddingTop="@dimen/all_apps_tabs_vertical_padding_focus"
- android:paddingBottom="@dimen/all_apps_tabs_vertical_padding_focus"
android:layout_marginTop="@dimen/all_apps_tabs_margin_top"
android:orientation="horizontal"
style="@style/TextHeadline"
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 622f0d6..7c57726 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -81,6 +81,7 @@
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/widgets_surface_background"
+ android:clipToOutline="true"
android:orientation="vertical"
android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:visibility="gone">
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index 5427732..1ce1c55 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -64,6 +64,7 @@
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/widgets_surface_background"
+ android:clipToOutline="true"
android:orientation="vertical"
android:visibility="gone">
<include layout="@layout/widget_recommendations" />
diff --git a/res/layout/widgets_list_expand_button.xml b/res/layout/widgets_list_expand_button.xml
index 17c19ac..ff2d777 100644
--- a/res/layout/widgets_list_expand_button.xml
+++ b/res/layout/widgets_list_expand_button.xml
@@ -15,6 +15,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget_list_expand_button"
style="@style/Button.Rounded.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index 5dc1b47..cf090ad 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -133,6 +133,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/widgets_surface_background"
+ android:clipToOutline="true"
android:orientation="vertical"
android:visibility="gone">
<include layout="@layout/widget_recommendations" />
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 46f2d8a..e2f0e09 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -17,6 +17,7 @@
android:id="@+id/work_mode_toggle"
android:layout_height="@dimen/work_fab_height"
android:layout_width="wrap_content"
+ android:elevation="@dimen/work_fab_elevation"
android:minHeight="@dimen/work_fab_height"
android:gravity="center_vertical"
android:background="@drawable/work_mode_fab_background"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 5181bb7..0886f50 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruikinstellings vir %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nuwe venster"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Stoor apppaar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hierdie apppaar word nie op hierdie toestel gesteun nie"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Neem notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Voeg by"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Voeg <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Wys almal"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Wys alle legstukke"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Wys tans alle legstukke"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om legstukinstellings te verander"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Verander legstukinstellings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Deursoek programme"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gedeaktiveer deur jou administrateur"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Laat toe dat tuisskerm gedraai word"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Wanneer foon gedraai word"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Landskapmodus"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Stel foon op landskapmodus"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Kennisgewingkolle"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Aan"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Af"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Het dit"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Onderbreek werkprogramme"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Hervat"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Skedule van werkapps"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaat ruimte"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index a217bb6..576fefc 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"የ%1$s የአጠቃቀም ቅንብሮች"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"አዲስ መስኮት"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"የመተግበሪያ ጥምረትን ያስቀምጡ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ይህ የመተግበሪያ ጥምረት በዚህ መሣሪያ ላይ አይደገፍም"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"የማስታወሻ አያያዝ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"አክል"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"ምግብር <xliff:g id="WIDGET_NAME">%1$s</xliff:g>ን አክል"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ሁሉንም አሳይ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ሁሉንም ምግብሮች አሳይ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ሁሉንም ምግብሮች በማሳየት ላይ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"የምግብር ቅንብሮችን ለመለወጥ መታ ያድርጉ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"የምግብር ቅንብሮችን ይለውጡ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"መተግበሪያዎችን ፈልግ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"በእርስዎ አስተዳዳሪ የተሰናከለ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"የመነሻ ማያ ገፅ ማሽከርከርን ይፍቀዱ"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ስልኩ ሲዞር"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"የመሬት አቀማመጥ ሁኔታ"</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">"አብራ"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ጠፍቷል"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ገባኝ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"የሥራ መተግበሪያዎችን ባሉበት አቁም"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ካቆመበት ቀጥል"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"የሥራ መተግበሪያዎች መርሐግብር"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"አጣራ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"አልተሳካም፦ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"የግል ቦታ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index c08254a..b902aca 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"إعدادات استخدام \"%1$s\""</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"نافذة جديدة"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"حفظ استخدام التطبيقين معًا"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"لا يمكن استخدام هذين التطبيقَين في الوقت نفسه على هذا الجهاز"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"تدوين الملاحظات"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"إضافة"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"إضافة التطبيق المصغّر \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"عرض الكل"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"عرض كل التطبيقات المصغّرة"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"جارٍ عرض كل التطبيقات المصغّرة"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"انقر لتغيير إعدادات الأداة"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغيير إعدادات الأداة"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"بحث في التطبيقات"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"أوقف المشرف هذه الميزة"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"السماح بتدوير الشاشة الرئيسية"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"عند تدوير الهاتف"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"الوضع الأفقي"</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">"الإعداد مفعّل"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"غير مفعّل"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"حسنًا"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"إيقاف تطبيقات العمل مؤقتًا"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"إلغاء الإيقاف المؤقت"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"الجدول الزمني لتطبيقات العمل"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"فلتر"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
<string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index ccfb10e..128c846 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sৰ বাবে ব্যৱহাৰৰ ছেটিং"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"নতুন ৱিণ্ড’"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"এপৰ পেয়াৰ ছেভ কৰক"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইচটোত এই এপ্ পেয়াৰ কৰাৰ সুবিধাটো সমৰ্থিত নহয়"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"টোকা গ্ৰহণ কৰা"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"যোগ দিয়ক"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট যোগ দিয়ক"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"আটাইবোৰ দেখুৱাওক"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"আটাইবোৰ ৱিজেট দেখুৱাওক"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"আটাইবোৰ ৱিজেট দেখুৱাই থকা হৈছে"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ৱিজেটৰ ছেটিং সলনি কৰিবলৈ টিপক"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ৱিজেটৰ ছেটিং সলনি কৰক"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"এপ্সমূহ সন্ধান কৰক"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"আপোনাৰ প্ৰশাসকে অক্ষম কৰি ৰাখিছে"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"গৃহ স্ক্ৰীন ঘূৰোৱাৰ অনুমতি দিয়ক"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ফ\'নটো যেতিয়া ঘূৰোৱা হয়"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"লেণ্ডস্কেইপ ম’ড"</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">"অন কৰা আছে"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"অফ আছে"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"বুজি পালোঁ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"কৰ্মস্থানৰ এপ্ পজ কৰক"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"আনপজ কৰক"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"কাম সম্পৰ্কীয় এপৰ সময়সূচী"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টাৰ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"বিফল: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"প্ৰাইভেট স্পে\'চ"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index c85f271..96447b4 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s üzrə istifadə ayarları"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Yeni Pəncərə"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Tətbiq cütünü saxlayın"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu tətbiq cütü bu cihazda dəstəklənmir"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qeydgötürmə"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Əlavə edin"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidcet əlavə edin"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hamısını göstər"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Bütün vidcetləri göstərin"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Bütün vidcetlər göstərilir"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidcet ayarlarını dəyişmək üçün toxunun"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidcet ayarlarını dəyişin"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tətbiqləri axtarın"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Admininiz tərəfindən deaktiv edilib"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Əsas ekran çevrilsin"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon çevrilən zaman"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Landşaft rejimi"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefonu landşaft rejiminə ayarlayın"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Bildiriş nöqtələri"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Aktiv"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Deaktiv"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Anladım"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"İş tətbiqlərini durdurun"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Davam etdirin"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"İş tətbiqləri cədvəli"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Məxfi sahə"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index e8b55b7..5408aaf 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Podešavanja potrošnje za %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Novi prozor"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ovaj par aplikacija nije podržan na ovom uređaju"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pravljenje beležaka"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajte vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Prikažite sve vidžete"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Prikazuju se svi vidžeti"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promenite podešavanja vidžeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator je onemogućio"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Dozvoli rotaciju početnog ekrana"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon rotira"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Vodoravni režim"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Podesite telefon na vodoravni režim"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Tačke za obaveštenja"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Uključeno"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Isključeno"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Važi"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pauziraj poslovne aplikacije"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ponovo aktiviraj"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Raspored za poslovne aplikacije"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 6d714bc..cf5e7f8 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s: налады выкарыстання"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Новае акно"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Захаваць спалучэнне праграм"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Дадзенае спалучэнне праграм не падтрымліваецца на гэтай прыладзе"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Стварэнне нататак"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Дадаць"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Дадаць віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Паказаць усе"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Паказаць усе віджэты"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Паказаны ўсе віджэты"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Націсніце, каб змяніць налады віджэта"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Змяніць налады віджэта"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук праграм"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Адключаная адміністратарам"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Дазволіць паварот галоўнага экрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Альбомная арыентацыя"</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">"Уключана"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Выкл."</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Зразумела"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Прыпыніць працоўныя праграмы"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Актываваць"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Расклад працоўных праграм"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Прыватная прастора"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 191ef03..fd4c983 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки за използването на %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Нов прозорец"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Запазване на двойката приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Тази двойка приложения не се поддържа на устройството"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Водене на бележки"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Добавяне"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавяне на приспособлението „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Вижте всички"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Показване на всички приспособления"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Показват се всички приспособления"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Докоснете, за да промените настройките на приспособлението"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промяна на настройките на приспособлението"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Търсене в приложенията"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Деактивирано от администратора ви"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Разрешаване на завъртането на началния екран"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"При завъртане на телефона"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Хоризонтален режим"</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">"Вкл."</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Изкл."</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Разбрах"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Поставяне на пауза на служебните приложения"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Отмяна на паузата"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"График за служебните приложения"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтър"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Частно пространство"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 43834af..56461a3 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-এর জন্য ব্যবহারের সেটিংস"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"নতুন উইন্ডো"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"অ্যাপ পেয়ার সেভ করুন"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইসে এই অ্যাপ পেয়ারটি কাজ করে না"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"নোট নেওয়া"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"যোগ করুন"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট যোগ করুন"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"সব দেখুন"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"সব উইজেট দেখুন"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"সব উইজেট দেখানো হচ্ছে"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"উইজেট সেটিংস পরিবর্তন করতে ট্যাপ করুন"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"উইজেট সেটিংস পরিবর্তন করুন"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"অ্যাপ খুঁজুন"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"আপনার প্রশাসক দ্বারা অক্ষম করা হয়েছে"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"হোম স্ক্রিন রোটেট করার অনুমতি দিন"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"যখন ফোনটি ঘোরানো হয়"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ভূদৃশ্য মোড"</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">"চালু করা আছে"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"বন্ধ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"বুঝেছি"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"অফিসের অ্যাপ পজ করুন"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"আনপজ করুন"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"অফিসের অ্যাপের শিডিউল"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টার"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পেস"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 0beeafe..803c6c0 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke korištenja za: %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Novi prozor"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Par aplikacija nije podržan na uređaju"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilješki"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodajte"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodavanje vidžeta <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Prikaz svih vidžeta"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Prikazivanje svih vidžeta"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da promijenite postavke vidžeta"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promjena postavki vidžeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogućio vaš administrator"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Dozvoli rotiranje početnog ekrana"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon zarotira"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Vodoravni način"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Postavite telefon u vodoravni način"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Tačke za obavještenja"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Uključeno"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Isključeno"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Razumijem"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pauziraj poslovne aplikacije"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ponovo pokreni"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Raspored poslovnih aplikacija"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 94a7b41..0414bb2 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuració d\'ús de %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Finestra nova"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Desa la parella d\'aplicacions"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aquesta parella d\'aplicacions no s\'admet en aquest dispositiu"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Presa de notes"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Afegeix"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Afegeix el widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostra-ho tot"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostra tots els widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"S\'estan mostrant tots els widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca per canviar la configuració del widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Canvia la configuració del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desactivada per l\'administrador"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permet la rotació de la pantalla d\'inici"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"En girar el telèfon"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Mode horitzontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Posa el telèfon en mode horitzontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Punts de notificació"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activats"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivats"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Entesos"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Posa en pausa les aplicacions de treball"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Reactiva"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Programació de les aplicacions de treball"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espai privat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 93017bf..aa50a42 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavení využití pro aplikaci %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nové okno"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uložit dvojici aplikací"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikací není na tomto zařízení podporován"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Psaní poznámek"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Přidat"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Přidat widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Zobrazit vše"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Zobrazit všechny widgety"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Zobrazují se všechny widgety"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím změníte nastavení widgetu"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Změnit nastavení widgetu"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hledat v aplikacích"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Zakázáno administrátorem"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Povolit otáčení plochy"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Při otočení telefonu"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Režim na šířku"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Nastavit telefon do režimu na šířku"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Puntíky s oznámením"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Zapnuto"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Vypnuto"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pozastavit pracovní aplikace"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Zrušit pozastavení"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Plán pracovních aplikací"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Soukromý prostor"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index c22d0dc..0410763 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Indstillinger for brug af %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nyt vindue"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gem appsammenknytning"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne appsammenknytning understøttes ikke på enheden"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tilføj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tilføj <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Vis alle"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Vis alle widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Viser alle widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryk for at ændre widgetindstillinger"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Skift widgetindstillinger"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Deaktiveret af din administrator"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Tillad rotation af startskærmen"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Når telefonen roteres"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Liggende format"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Indstil telefonen til liggende format"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Notifikationsprikker"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Til"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Fra"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Sæt arbejdsapps på pause"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Genoptag"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Tidsplan for arbejdsapps"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 21ada28..cb63ff0 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nutzungseinstellungen für %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Neues Fenster"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"App-Paar speichern"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notizen"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Hinzufügen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ hinzufügen"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Alle anzeigen"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Alle Widgets anzeigen"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Es werden alle Widgets angezeigt"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tippen, um die Widget-Einstellungen zu ändern"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget-Einstellungen ändern"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps finden"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Von deinem Administrator deaktiviert"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Drehen des Startbildschirms zulassen"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Beim Drehen des Smartphones"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Querformat"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Smartphone auf Querformat einstellen"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"App-Benachrichtigungspunkte"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"An"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Aus"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Geschäftliche Apps pausieren"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nicht mehr pausieren"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Zeitplan für geschäftliche Apps"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Vertrauliches Profil"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1e18977..79d9f19 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ρυθμίσεις χρήσης για %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Νέο παράθυρο"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Αποθήκευση ζεύγους εφαρμογών"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Αυτό το ζεύγος εφαρμογών δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Δημιουργία σημειώσεων"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Προσθήκη"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Προσθήκη του γραφικού στοιχείου <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Εμφάνιση όλων"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Εμφάνιση συνόλου γραφικών στοιχείων"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Εμφάνιση όλων των γραφικών στοιχείων"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Πατήστε για αλλαγή των ρυθμίσεων του γραφικού στοιχείου"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Αλλαγή ρυθμίσεων γραφικού στοιχείου"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Αναζήτηση εφαρμογών"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Απενεργοποιήθηκε από τον διαχειριστή σας"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Να επιτρέπεται η περιστροφή της αρχικής οθόνης"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Όταν το τηλέφωνο περιστρέφεται"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Οριζόντιος προσανατολισμός"</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">"Ενεργοποίηση"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Απενεργοποίηση"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Το κατάλαβα"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Παύση εφαρμογών εργασιών"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Αναίρεση παύσης"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Πρόγραμμα εφαρμογών εργασιών"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Φίλτρο"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ιδιωτικός χώρος"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index a2a4145..a58ace8 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"New window"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Show all widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Showing all widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <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="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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pause work apps"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Unpause"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Work apps schedule"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index c600680..e2d072b 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -32,6 +32,7 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"New Window"</string>
+ <string name="manage_windows_option_taskbar" msgid="2294109489960654212">"Manage Windows"</string>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index a2a4145..a58ace8 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"New window"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Show all widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Showing all widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <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="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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pause work apps"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Unpause"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Work apps schedule"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index a2a4145..a58ace8 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"New window"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Show all widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Showing all widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <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="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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pause work apps"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Unpause"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Work apps schedule"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 44147c2..b0b06b0 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración del uso de %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Ventana nueva"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"No se admite esta vinculación de apps en este dispositivo"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Agregar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Agregar widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todos"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostrar todos los widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Mostrando todos los widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Presiona para cambiar la configuración del widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar la configuración del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"El administrador inhabilitó esta función"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permitir la rotación de la pantalla principal"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modo horizontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Establecer el teléfono en modo horizontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Puntos de notificación"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activados"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivados"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Entendido"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Detener apps de trabajo"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Reanudar"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Programa de las apps de trabajo"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 40e04d5..0062b2f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ajustes de uso para %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Ventana nueva"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar apps emparejadas"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"El dispositivo no admite esta aplicación emparejada"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Añadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Añadir widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todo"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostrar todos los widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Mostrando todos los widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar los ajustes del widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar ajustes del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicaciones"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitado por el administrador"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permitir rotación de la pantalla de inicio"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modo de vista horizontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Pon el teléfono en modo de vista horizontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Burbujas de notificación"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activado"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivadas"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Entendido"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pausar aplicaciones de trabajo"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Reanudar"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Horario de aplicaciones de trabajo"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index de62de1..5eccca9 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Kasutuse seaded: %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Uus aken"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvesta rakendusepaar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"See rakendusepaar ei ole selles seadmes toetatud"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Märkmete tegemine"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisa"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisa vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Kuva kõik"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Kuva kõik vidinad"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Kõik vidinad on kuvatud"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Puudutage vidina seadete muutmiseks"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidina seadete muutmine"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Otsige rakendusi"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Keelas administraator"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Luba avakuva pööramine"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kui telefoni pööratakse"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Horisontaalrežiim"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Sea telefon horisontaalrežiimi"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Märguandetäpid"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Sees"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Väljas"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Selge"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Peata töörakendused"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Lõpeta peatamine"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Töörakenduste ajakava"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaatne ruum"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 27510b3..8d0499c 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s aplikazioaren erabilera-ezarpenak"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Leiho berria"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gorde aplikazio parea"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aplikazio pare hori ez da gailu honekin bateragarria"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Gehitu"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Gehitu <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Erakutsi guztiak"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Erakutsi widget guztiak"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Widget guztiak erakusten"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Sakatu hau widgeten ezarpenak aldatzeko"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Aldatu widgeten ezarpenak"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Bilatu aplikazioetan"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratzaileak desgaitu du"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Eman orri nagusia biratzeko baimena"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Telefonoa biratzean"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Ikuspegi horizontala"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Ezarri telefonoa ikuspegi horizontalean"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Jakinarazpen-biribiltxoak"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Aktibatuta"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desaktibatuta"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Ados"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pausatu laneko aplikazioak"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Aktibatu berriro"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Laneko aplikazioen programazioa"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Iragazi"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Eremu pribatua"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 8a21dc7..18a2038 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"اطلاعات برنامه %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"تنظیمات مصرف برای %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"پنجره جدید"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ذخیره جفت برنامه"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمیشود"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشتبرداری"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"نمایش همه"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"نمایش همه ابزارهها"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"درحال نمایش دادن همه ابزارهها"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزاره، تکضرب بزنید"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزاره"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامهها"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"توسط سرپرست سیستم غیرفعال شده است"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"مجاز کردن چرخش صفحه اصلی"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"وقتی تلفن چرخانده میشود"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"حالت افقی"</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">"روشن"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"خاموش"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"متوجهام"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"توقف موقت برنامههای کاری"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ازسرگیری"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"برنامه زمانی برنامههای کاری"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"فیلتر"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"فضای خصوصی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index c778a61..f04fa62 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Käyttöasetus tälle: %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Uusi ikkuna"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Tallenna sovelluspari"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Sovellusparia ei tueta tällä laitteella"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Muistiinpanojen tekeminen"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisää"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisää widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Näytä kaikki"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Näytä kaikki widgetit"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Näytetään kaikki widgetit"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Napauta, niin voit muuttaa widgetin asetuksia"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Muuta widgetin asetuksia"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hae sovelluksia"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Järjestelmänvalvoja on poistanut toiminnon käytöstä."</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Salli aloitusnäytön kiertäminen"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kun puhelinta kierretään"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Vaakasuunta"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Aseta puhelin vaakasuuntaan"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Pistemerkit"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Päällä"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Ei päällä"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Keskeytä työsovellusten käyttö"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Jatka"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Työsovellusten aikataulu"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Suodatin"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Yksityinen tila"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 1f5e264..6f26dae 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nouvelle fenêtre"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applis n\'est pas prise en charge sur cet appareil"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de note"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tout afficher"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Afficher tous les widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Tous les widgets affichés"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Touchez pour modifier les paramètres du widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applis"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Cette fonction est désactivée par votre administrateur"</string>
<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>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <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="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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Mettre en pause les applis professionnelles"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Réactiver"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Horaire des applis professionnelles"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index a5b9a32..bd1f23c 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nouvelle fenêtre"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Enregistrer une paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de notes"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez un widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tout afficher"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Afficher tous les widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Afficher tous les widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Appuyez pour modifier les paramètres du widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Désactivé par votre administrateur"</string>
<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>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Mode Paysage"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Placez 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ées"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Désactivées"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Mettre en pause les applis professionnelles"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Réactiver"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Planifier l\'activation des applis pros"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index ca2861a..9eae629 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración de uso para %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Ventá nova"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"O dispositivo non admite este emparellamento de aplicacións"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Engadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engadir o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todo"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostrar todos os widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Mostrando todos os widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar a configuración do widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar configuración do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicacións"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Función desactivada polo administrador"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permitir xirar a pantalla de inicio"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Ao xirar o teléfono"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modo horizontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Pon o teléfono no modo horizontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Puntos de notificacións"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Opción activada"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivados"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Entendido"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pór en pausa aplicacións do traballo"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Volver activar"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Horario das aplicacións do traballo"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espazo privado"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 59e3134..84f4ce6 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sના વપરાશ સંબંધિત સેટિંગ"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"નવી વિન્ડો"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ઍપની જોડી સાચવો"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"આ ડિવાઇસ પર, આ ઍપની જોડીને સપોર્ટ આપવામાં આવતો નથી"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"નોંધ લેવી"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ઉમેરો"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેરો"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"બધા બતાવો"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"બધા વિજેટ બતાવો"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"બધા વિજેટ બતાવી રહ્યાં છીએ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"વિજેટના સેટિંગ બદલવા માટે ટૅપ કરો"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"વિજેટના સેટિંગ બદલો"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ઍપ શોધો"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"જ્યારે ફોન ફેરવવામાં આવે ત્યારે"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"લૅન્ડસ્કેપ મોડ"</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">"ચાલુ છે"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"બંધ છે"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"સમજાઈ ગયું"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ઑફિસની ઍપ થોભાવો"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ફરી ચાલુ કરો"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ઑફિસ માટેની ઍપનું શેડ્યૂલ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ફિલ્ટર કરો"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"નિષ્ફળ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ખાનગી સ્પેસ"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index c26cafb..110e3af 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s के लिए खर्च की सेटिंग"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"नई विंडो"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ऐप पेयर सेव करें"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन, इस डिवाइस पर काम नहीं कर सकते"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"नोट बनाने से जुड़े विजेट"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"जोड़ें"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोड़ें"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सभी दिखाएं"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"सभी विजेट दिखाएं"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"सभी विजेट दिखाए जा रहे हैं"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट की सेटिंग में बदलाव करने के लिए टैप करें"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेट की सेटिंग में बदलाव करें"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ऐप्लिकेशन खोजें"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपके एडमिन ने बंद किया हुआ है"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन घुमाने की अनुमति दें"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"फ़ोन घुुमाए जाने पर"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"लैंडस्केप मोड"</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">"चालू है"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"चालू"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ठीक है"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"वर्क ऐप्लिकेशन रोकें"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"चालू करें"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"वर्क ऐप्लिकेशन के लिए शेड्यूल"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"फ़िल्टर"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"पूरा नहीं हुआ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"प्राइवेट स्पेस"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 4a29979..06a8d06 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke upotrebe za %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Novi prozor"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Spremi par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Taj par aplikacija nije podržan na ovom uređaju"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilježaka"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Prikaži sve widgete"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Prikazuju se svi widgeti"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promijenili postavke widgeta"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promijenite postavke widgeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretraži aplikacije"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogućio administrator"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Dopusti zakretanje početnog zaslona"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon zakrene"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Pejzažni način"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Postavljanje telefona u pejzažni način"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Točke obavijesti"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Uključeno"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Isključeno"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Shvaćam"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pauziraj poslovne aplikacije"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ponovno pokreni"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Raspored za poslovne aplikacije"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index aa1167d..6228678 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"A(z) %1$s használati beállításai"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Új ablak"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Alkalmazáspár mentése"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ezt az alkalmazáspárt nem támogatja az eszköz"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Jegyzetelés"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Hozzáadás"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadása"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Az összes megjelenítése"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Minden modul mutatása"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Összes modul megjelenítése…"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ide koppintva módosíthatja a modulbeállításokat"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"A modulbeállítások módosítása"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Alkalmazások keresése"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"A rendszergazda letiltotta"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"A kezdőképernyő elforgatásának engedélyezése"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"A telefon elforgatásakor"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Fekvő tájolás"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Állítsa a telefont fekvő tájolásúra"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Értesítési pöttyök"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Be"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Ki"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Értem"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Munkahelyi alkalmazások szüneteltetése"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Folytatás"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Munkahelyi alkalmazások ütemezése"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Szűrő"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 692984e..010d259 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Օգտագործման կարգավորումներ (%1$s)"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Նոր պատուհան"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվ. զույգը"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Նշումների ստեղծում"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ավելացնել"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ավելացնել <xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթը"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Բոլորը"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Ցույց տալ բոլոր վիջեթները"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Բոլոր վիջեթները ցուցադրված են"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Հպեք՝ վիջեթի կարգավորումները փոփոխելու համար"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Փոխել վիջեթի կարգավորումները"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Որոնել հավելվածներ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Անջատվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Թույլ տալ հիմնական էկրանի պտտումը"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Հեռախոսը պտտելու դեպքում"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Հորիզոնական"</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">"Միացված է"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Անջատված է"</string>
@@ -198,11 +195,10 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Եղավ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Դադարեցնել աշխատանքային հավելվածները"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Վերսկսել"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Աշխատանքային հավելվածների ժամանակացույց"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Զտեք"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Անձնական տարածք"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Մասնավոր տարածք"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Հպեք կարգավորելու կամ բացելու համար"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Մասնավոր"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 1870055..027a111 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setelan penggunaan untuk %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Jendela Baru"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Simpan pasangan aplikasi"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Pasangan aplikasi ini tidak didukung di perangkat ini"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pembuatan catatan"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambahkan"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tampilkan semua"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Tampilkan semua widget"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Menampilkan semua widget"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketuk untuk mengubah setelan widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ubah setelan widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dinonaktifkan oleh admin"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Izinkan layar utama diputar"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Saat ponsel diputar"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Mode lanskap"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Setel ponsel ke mode lanskap"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Titik notifikasi"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Aktif"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Nonaktif"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Oke"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Jeda aplikasi kerja"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Aktifkan lagi"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Jadwal aplikasi kerja"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 393589a..c2f8f5a 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Notkunarstillingar fyrir %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nýr gluggi"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Vista forritapar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Þetta forritapar er ekki stutt í þessu tæki"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Glósugerð"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Bæta við"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Bæta græjunni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> við"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Sýna allt"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Sýna allar græjur"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Sýnir allar græjur"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ýttu til að breyta græjustillingum"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Breyta græjustillingum"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Leita í forritum"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gert óvirkt af kerfisstjóra"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Leyfa snúning á heimaskjá"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Þegar símanum er snúið"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Langsnið"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Stilla síma á langsnið"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Tilkynningapunktar"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Kveikt"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Slökkt"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Ég skil"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Setja vinnuforrit í bið"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ljúka hléi"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Áætlun vinnuforrita"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Sía"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Leynirými"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 2a14445..34d2f57 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Impostazioni di utilizzo per %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nuova finestra"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salva coppia di app"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Questa coppia di app non è supportata su questo dispositivo"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aggiunta di note"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Aggiungi"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Aggiungi widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostra tutto"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostra tutti i widget"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Visualizzazione di tutti i widget"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tocca per modificare le impostazioni del widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifica le impostazioni del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca nelle app"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disattivata dall\'amministratore"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Consenti rotazione della schermata Home"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Con il telefono ruotato"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modalità Orizzontale"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Imposta lo smartphone in modalità Orizzontale"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Indicatori di notifica"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"On"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Off"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Metti in pausa le app di lavoro"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Riattiva"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Programmazione app di lavoro"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spazio privato"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 724742a..4eb3e96 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"הגדרות שימוש ב-%1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"חלון חדש"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"שמירת צמד אפליקציות"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"הוספת הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"הצגת הכול"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"הצגת כל הווידג\'טים"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"כל הווידג\'טים מוצגים"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"אפשר לשנות את הגדרות הווידג\'ט בהקשה"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"שינוי הגדרות הווידג\'ט"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"חיפוש אפליקציות"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"הושבת על ידי מנהל המערכת שלך"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"סיבוב מסך הבית"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"כאשר מסובבים את הטלפון"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"פריסה לרוחב"</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">"מופעל"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"כבוי"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"הבנתי"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"השהיית האפליקציות לעבודה"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ביטול ההשהיה"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"לוח זמנים להשהיית אפליקציות לעבודה"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 29dbf26..e11a22c 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s の使用設定"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"新しいウィンドウ"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"アプリのペア設定を保存"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"このデバイスは、このアプリのペア設定に対応していません"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"メモ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"追加"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ウィジェットを追加"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"すべて表示"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"すべてのウィジェットを表示"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"すべてのウィジェットを表示しています"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"タップしてウィジェットの設定を変更する"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ウィジェットの設定を変更します"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"アプリを検索"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"管理者により無効にされています"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ホーム画面の回転を許可"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"スマートフォンの向きに合わせます"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"横表示"</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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"仕事用アプリを一時停止"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"停止解除"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"仕事用アプリのスケジュール"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"フィルタ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失敗: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"プライベート スペース"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 876ab11..c702c62 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"გამოყენების პარამეტრები %1$s-ისთვის"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ახალი ფანჯარა"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"აპთა წყვილის შენახვა"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ამ მოწყობილობაზე აღნიშნული აპთა წყვილი არ არის მხარდაჭერილი"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ჩანიშვნა"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"დამატება"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტის დამატება"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ყველას ჩვენება"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ყველა ვიჯეტის ჩვენება"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ნაჩვენებია ყველა ვიჯეტი"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"შეეხეთ ვიჯეტის პარამეტრების შესაცვლელად"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ვიჯეტის პარამეტრების შეცვლა"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"აპების ძიება"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"გათიშულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"მთავარი ეკრანის შეტრიალების დაშვება"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ტელეფონის შეტრიალებისას"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"პეიზაჟის რეჟიმი"</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">"ჩართულია"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"გამორთულია"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"გასაგებია"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"სამსახურის აპების დაპაუზება"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"პაუზის გაუქმება"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"სამსახურის აპების განრიგი"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ფილტრი"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ვერ მოხერხდა: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"პირადი სივრცე"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index bc1c380..605a602 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s пайдалану параметрлері"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Жаңа терезе"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Қолданбаларды жұптау әрекетін сақтау"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бұл құрылғы қолданбаларды жұптау функциясын қолдамайды."</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ескертпе жазу"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Қосу"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Виджет (<xliff:g id="WIDGET_NAME">%1$s</xliff:g>) қосу"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Барлығын көру"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Барлық виджетті көрсету"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Барлық виджет көрсетіліп тұр."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджет параметрлерін өзгерту үшін түртіңіз."</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Виджет параметрлерін өзгерту"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Қолданбаларды іздеу"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Әкімші өшірді"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Негізгі экранды бұруға рұқсат ету"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон бұрылғанда"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Альбом режимі"</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">"Қосулы"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Өшірулі"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Түсінікті"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Жұмыс қолданбаларын кідірту"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Қайта қосу"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Жұмыс қолданбаларының кестесі"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Сүзгі"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Құпия кеңістік"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 813b5a2..f6d0f37 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធីសម្រាប់ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ការកំណត់ការប្រើប្រាស់សម្រាប់ %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"វិនដូថ្មី"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"រក្សាទុកគូកម្មវិធី"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"មិនអាចប្រើគូកម្មវិធីនេះនៅលើឧបករណ៍នេះបានទេ"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ការកត់ត្រា"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"បញ្ចូល"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"បញ្ចូលធាតុក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"បង្ហាញទាំងអស់"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"បង្ហាញធាតុក្រាហ្វិកទាំងអស់"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"កំពុងបង្ហាញធាតុក្រាហ្វិកទាំងអស់"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ចុចដើម្បីប្ដូរការកំណត់ធាតុក្រាហ្វិក"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ប្ដូរការកំណត់ធាតុក្រាហ្វិក"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ស្វែងរកកម្មវិធី"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"អនុញ្ញាតការបងិ្វលអេក្រង់ដើម"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"នៅពេលដែលបង្វិលទូរសព្ទ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ផ្ដេក"</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">"បើក"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"បិទ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"យល់ហើយ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ផ្អាកកម្មវិធីការងារ"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ឈប់ផ្អាក"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"កាលវិភាគកម្មវិធីការងារ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"តម្រង"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"បានបរាជ័យ៖ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"បន្ទប់ឯកជន"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index b4bc3a1..bc9f293 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ಗೆ ಸಂಬಂಧಿಸಿದ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ಹೊಸ ವಿಂಡೋ"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ಟಿಪ್ಪಣಿ ತೆಗೆದುಕೊಳ್ಳುವುದು"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ಸೇರಿಸಿ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಸೇರಿಸಿ"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ಎಲ್ಲಾ ತೋರಿಸಿ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ಎಲ್ಲಾ ವಿಜೆಟ್ಗಳನ್ನು ತೋರಿಸಿ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ಎಲ್ಲಾ ವಿಜೆಟ್ಗಳನ್ನು ತೋರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ಆ್ಯಪ್ಗಳನ್ನು ಹುಡುಕಿ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ಫೋನ್ ತಿರುಗಿಸಿದಾಗ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್ ಮೋಡ್"</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">"ಆನ್ ಆಗಿದೆ"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ಆಫ್ ಆಗಿದೆ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ಅರ್ಥವಾಯಿತು"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಿ"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ವಿರಾಮವನ್ನು ರದ್ದುಗೊಳಿಸಿ"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳ ವೇಳಾಪಟ್ಟಿ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ಫಿಲ್ಟರ್"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ವಿಫಲವಾಗಿದೆ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 4baba23..7748a32 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s의 사용량 설정"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"새 창"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"앱 페어링 저장"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"이 앱 페어링은 이 기기에서 지원되지 않습니다"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"메모"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"추가"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯 추가"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"모두 표시"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"모든 위젯 표시"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"모든 위젯 표시"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"탭하여 위젯 설정 변경"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"위젯 설정 변경"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"앱 검색"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"관리자가 사용 중지함"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"홈 화면 회전 허용"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"휴대전화 회전 시"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"가로 모드"</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">"사용"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"사용 안함"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"확인"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"직장 앱 일시중지"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"일시중지 해제"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"직장 앱 일정"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"필터"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"실패: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"비공개 스페이스"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 83b0fa8..d3cf7e4 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s колдонмосун пайдалануу параметрлери"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Жаңы терезе"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Колдонмолорду сактап коюу"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бул эки колдонмону бул түзмөктө бир маалда пайдаланууга болбойт"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Эскертме жазуу"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Кошуу"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетин кошуу"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Баарын көрсөтүү"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Виджеттин баарын көрсөтүү"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Бардык виджеттерди көрсөтүү"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджеттин параметрлерин өзгөртүү үчүн таптап коюңуз"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Виджеттин параметрлерин өзгөртүү"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Колдонмолорду издөө"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администраторуңуз өчүрүп койгон"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Башкы экранды бурууга уруксат берүү"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон бурулганда"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Туурасынан"</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">"Күйүк"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Өчүк"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Түшүндүм"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Жумуш колдонмолорун тындыруу"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Улантуу"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Жумуш колдонмолорунун графиги"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Чыпкалоо"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Жеке мейкиндик"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 767c574..10611c1 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ການຕັ້ງຄ່າການນຳໃຊ້ສຳລັບ %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ໜ້າຈໍໃໝ່"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ການຈັບຄູ່ແອັບນີ້ບໍ່ຮອງຮັບຢູ່ອຸປະກອນນີ້"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ການຈົດບັນທຶກ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ເພີ່ມ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ສະແດງທັງໝົດ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ສະແດງວິດເຈັດທັງໝົດ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ກໍາລັງສະແດງວິດເຈັດທັງໝົດ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ແຕະເພື່ອປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ຊອກຫາແອັບ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ຖືກປິດການນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ອະນຸຍາດໃຫ້ໝຸນໜ້າຈໍຢູ່ໂຮມສະກຣີນໄດ້"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ເມື່ອໝຸນໂທລະສັບ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ໂໝດແນວນອນ"</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">"ເປີດ"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ປິດ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ຢຸດແອັບບ່ອນເຮັດວຽກຊົ່ວຄາວ"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ຍົກເລີກການຢຸດຊົ່ວຄາວ"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ກຳນົດເວລາຂອງແອັບບ່ອນເຮັດວຽກ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ກັ່ນຕອງ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ບໍ່ສຳເລັດ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ພື້ນທີ່ສ່ວນຕົວ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 08b603d..c6c379a 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"„%1$s“ naudojimo nustatymai"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Naujas langas"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Išsaugoti programų porą"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ši programų pora šiame įrenginyje nepalaikoma"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Užrašų kūrimas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridėti"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridėti valdiklį: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Rodyti viską"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Rodyti visus valdiklius"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Rodomi visi valdikliai"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Palieskite, kad pakeistumėte valdiklio nustatymus"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Pakeisti valdiklio nustatymus"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Paieškos programos"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Išjungė administratorius"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Leisti pasukti pagrindinį ekraną"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kai telefonas pasukamas"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Gulsčiojo ekrano režimas"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Nustatykite telefoną į gulsčiojo ekrano režimą"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Pranešimų taškai"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Įjungta"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Išjungta"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Supratau"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pristabdyti darbo programas"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Atšaukti pristabdymą"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Darbo programų tvarkaraštis"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruoti"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privati erdvė"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e02abe0..0dc7445 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Lietojuma iestatījumi: %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Jauns logs"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Saglabāt lietotņu pāri"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Šis lietotņu pāris netiek atbalstīts šajā ierīcē"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Piezīmju pierakstīšana"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pievienot"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pievienot logrīku <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Rādīt visus"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Rādīt visus logrīkus"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Tiek rādīti visi logrīki"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Pieskarieties, lai mainītu logrīka iestatījumus."</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mainīt logrīka iestatījumus"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Meklēt lietotnes"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Atspējojis administrators"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Atļaut sākuma ekrāna pagriešanu"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Pagriežot tālruni"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Ainavas režīms"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Iestatīt tālrunī ainavas režīmu"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Paziņojumu punkti"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Ieslēgti"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Izslēgts"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Labi"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pārtraukt darba lietotņu darbību"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Atsākt"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Darba lietotņu grafiks"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrs"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privātā telpa"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index e524d82..c5518bc 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Поставки за користење за %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Нов прозорец"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Зачувај го парот апликации"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Паров апликации не е поддржан на уредов"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Фаќање белешки"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додај го виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Прикажи ги сите"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Прикажи ги сите виџети"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Се прикажуваат сите виџети"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Допрете за да ги промените поставките за виџетот"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промени ги поставките за виџетот"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пребарувајте апликации"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Оневозможено од администраторот"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Дозволи ротирање на почетниот екран"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Кога телефонот се ротира"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Хоризонтален режим"</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">"Вклучено"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Исклучено"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Сфатив"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Паузирај ги работните апликации"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Прекини ја паузата"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Распоред на работните апликации"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index e273e14..756c065 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s എന്നതിനുള്ള ഉപയോഗ ക്രമീകരണം"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"പുതിയ വിന്ഡോ"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ആപ്പ് ജോടി സംരക്ഷിക്കുക"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ഈ ഉപകരണത്തിൽ ഈ ആപ്പ് ജോടിക്ക് പിന്തുണയില്ല"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ചേർക്കുക"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ചേർക്കുക"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"എല്ലാം കാണിക്കൂ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"എല്ലാ വിജറ്റും കാണിക്കുക"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"എല്ലാ വിജറ്റുകളും കാണിക്കുന്നു"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"വിജറ്റ് ക്രമീകരണം മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"വിജറ്റ് ക്രമീകരണം മാറ്റുക"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ആപ്പുകൾ തിരയുക"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ഹോം സ്ക്രീൻ റൊട്ടേഷൻ അനുവദിക്കുക"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ഫോൺ തിരിച്ച നിലയിലായിരിക്കുമ്പോൾ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ലാൻഡ്സ്കേപ്പ് മോഡ്"</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">"ഓണാണ്"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ഓഫാണ്"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"മനസ്സിലായി"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ഔദ്യോഗിക ആപ്പുകൾ താൽക്കാലികമായി നിർത്തുക"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"താൽക്കാലികമായി നിർത്തിയത് മാറ്റുക"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ഔദ്യോഗിക ആപ്പുകൾക്കുള്ള ഷെഡ്യൂൾ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ഫിൽട്ടർ ചെയ്യുക"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"പരാജയപ്പെട്ടു: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"സ്വകാര്യ സ്പേസ്"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 7e5ed73..aad461b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-н ашиглалтын тохиргоо"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Шинэ цонх"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Апп хослуулалтыг хадгалах"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Энэ апп хослуулалтыг уг төхөөрөмж дээр дэмждэггүй"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Тэмдэглэл хөтлөх"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Нэмэх"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг нэмэх"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Бүгдийг харуул"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Бүх виджетийг харуулах"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Бүх виджетийг харуулж байна"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Жижиг хэрэгслийн тохиргоог өөрчлөхийн тулд товшино уу"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Жижиг хэрэгслийн тохиргоог өөрчлөх"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Апп хайх"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Таны админ идэвхгүй болгосон"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Үндсэн нүүрийг эргүүлэхийг зөвшөөрөх"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Утсыг эргүүлсэн үед"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Хэвтээ горим"</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">"Асаалттай"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Унтраалттай"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Ойлголоо"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Ажлын аппуудыг түр зогсоох"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Түр зогсоохоо болих"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Ажлын аппуудын хуваарь"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Шүүлтүүр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Амжилтгүй болсон: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Хувийн орон зай"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index b5d4f71..a089669 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s साठी वापरासंबंधित सेटिंग्ज"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"नवीन विंडो"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ॲपची जोडी सेव्ह करा"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"या ॲपची जोडीला या डिव्हाइसवर सपोर्ट नाही"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"टिपा घेणे"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"जोडा"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोडा"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सर्व दाखवा"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"सर्व विजेट दाखवा"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"सर्व विजेट दाखवत आहे"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट सेटिंग्ज बदलण्यासाठी टॅप करा"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेट सेटिंग्ज बदला"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन फिरवण्याची अनुमती द्या"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरवला जातो तेव्हा"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"लँडस्केप मोड"</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">"सुरू"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"बंद"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"समजले"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"कार्य ॲप्स थांबवा"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"अनपॉझ करा"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Work apps साठी शेड्यूल"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"खाजगी स्पेस"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index a48d518..79a8c43 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Tetapan penggunaan sebanyak %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Tetingkap Baharu"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Simpan gandingan apl"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Gandingan apl ini tidak disokong pada peranti ini"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tunjukkan semua"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Tunjukkan semua widget"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Menunjukkan semua widget"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketik untuk menukar tetapan widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Tukar tetapan widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cari apl"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dilumpuhkan oleh pentadbir anda"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Benarkan putaran skrin utama"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Apabila telefon diputar"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Mod landskap"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Tetapkan telefon kepada mod landskap"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Titik pemberitahuan"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Hidup"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Mati"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Jeda apl kerja"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nyahjeda"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Jadual apl kerja"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Tapis"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang persendirian"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index f892a1b..340d7a8 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s အတွက် အသုံးပြုမှုဆက်တင်များ"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ဝင်းဒိုးအသစ်"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ဤအက်ပ်တွဲချိတ်ခြင်းကို ဤစက်တွင် ပံ့ပိုးမထားပါ"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"မှတ်စုလိုက်ခြင်း"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ထည့်ရန်"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ထည့်ရန်"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"အားလုံးပြပါ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ဝိဂျက်အားလုံး ပြပါ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ဝိဂျက်အားလုံးကို ပြထားသည်"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ဝိဂျက် ဆက်တင်များကို ပြောင်းရန် တို့ပါ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ဝိဂျက် ဆက်တင်များကို ပြောင်းပါ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ရှာဖွေမှု အက်ပ်များ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ပင်မစာမျက်နှာလှည့်ခြင်းကို ခွင့်ပြုခြင်း"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ဖုန်းကိုလှည့်ထားစဉ်"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"အလျားလိုက်"</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">"ဖွင့်"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ပိတ်"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"နားလည်ပြီ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"အလုပ်သုံးအက်ပ်များကို ခဏရပ်ရန်"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ပြန်ဖွင့်ရန်"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"အလုပ်သုံးအက်ပ်များ အချိန်ဇယား"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"စစ်ထုတ်ရန်"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"မအောင်မြင်ပါ− <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"သီးသန့်ချတ်ခန်း"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index b9b69a0..004e100 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Bruksinnstillinger for %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nytt vindu"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Lagre app-paret"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatskriving"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Legg til"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Legg til <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Vis alle"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Vis alle moduler"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Viser alle moduler"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trykk for å endre modulinnstillinger"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Endre modulinnstillinger"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søk etter apper"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratoren har slått av funksjonen"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Tillat at startskjermen roterer"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Når telefonen roteres"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Liggende retning"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Plasser telefonen i liggende retning"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Varselsprikker"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"På"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Av"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Greit"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Sett jobbapper på pause"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Gjenoppta"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Tidsplan for jobbapper"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 6f93761..0940743 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s को प्रयोगसम्बन्धी सेटिङ"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"नयाँ विन्डो"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"एपको पेयर सेभ गर्नुहोस्"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"यस डिभाइसमा यो एप पेयर प्रयोग गर्न मिल्दैन"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"नोट लेख्ने कार्य"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"हाल्नुहोस्"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हाल्नुहोस्"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सबै देखाउनुहोस्"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"सबै विजेटहरू देखाउनुहोस्"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"सबै विजेटहरू देखाइँदै छन्"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेटका सेटिङ बदल्न ट्याप गर्नुहोस्"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेटका सेटिङ बदल्नुहोस्"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"एपहरू खोज्नुहोस्"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"तपाईँको प्रशासकद्वारा असक्षम गरिएको"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रिन रोटेट हुन दिइयोस्"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"फोन घुमाउँदा"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ल्यान्डस्केप मोड"</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">"सक्रिय"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"निष्क्रिय"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"बुझेँ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"कामसम्बन्धी एपहरू पज गर्नुहोस्"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"सुचारु गर्नुहोस्"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"कामसम्बन्धी एपहरूको समयतालिका"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"निजी स्पेस"</string>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 06f0eee..a891e39 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -38,16 +38,16 @@
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
<item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
+ <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
<item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
<item name="materialColorErrorContainer">@color/system_error_container_dark</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
+ <item name="materialColorInversePrimary">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorInverseSurface">@color/system_surface_light</item>
<item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
<item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index a38971f..f6d3e0f 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruiksinstellingen voor %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nieuw venster"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"App-paar opslaan"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dit app-paar wordt niet ondersteund op dit apparaat"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aantekeningen maken"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Toevoegen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toevoegen"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Alles tonen"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Alle widgets tonen"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Alle widgets worden getoond"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om de widgetinstellingen te wijzigen"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widgetinstellingen wijzigen"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps zoeken"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Uitgezet door je beheerder"</string>
<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>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <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="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>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Werk-apps pauzeren"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Hervatten"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Planning voor werk-apps"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filteren"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privéruimte"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index a20e0fc..7b48ad0 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ପାଇଁ ବ୍ୟବହାର ସେଟିଂସ"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ନୂଆ ୱିଣ୍ଡୋ"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ଏହି ଆପ ପେୟାର ଏ ଡିଭାଇସରେ ସମର୍ଥିତ ନୁହେଁ"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ନୋଟ-ଟେକିଂ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ସବୁ ଦେଖାନ୍ତୁ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ସମସ୍ତ ୱିଜେଟ ଦେଖାନ୍ତୁ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ସମସ୍ତ ୱିଜେଟ ଦେଖାଉଛି"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ଆପ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ହୋମ ସ୍କ୍ରିନ ରୋଟେସନକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ଯେତେବେଳେ ଫୋନକୁ ରୋଟେଟ କରାଯାଇଥାଏ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ଲେଣ୍ଡସ୍କେପ ମୋଡ"</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">"ଚାଲୁ"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ବନ୍ଦ କରନ୍ତୁ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ବୁଝିଗଲି"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ୱାର୍କ ଆପ୍ସ ବିରତ କରନ୍ତୁ"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ୱାର୍କ ଆପ୍ସ ସିଡୁଲ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ଫିଲ୍ଟର୍"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 65187bf..6ea5848 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ਲਈ ਵਰਤੋਂ ਸੈਟਿੰਗਾਂ"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"ਨਵੀਂ ਵਿੰਡੋ"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਦਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ਸਭ ਦਿਖਾਓ"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"ਸਭ ਵਿਜੇਟ ਦਿਖਾਓ"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"ਸਭ ਵਿਜੇਟ ਦਿਖਾਏ ਜਾ ਰਹੇ ਹਨ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ਐਪਾਂ ਖੋਜੋ"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਈ ਗਈ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ਹੋਮ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁਮਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ਜਦੋਂ ਫ਼ੋਨ ਘੁਮਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ਲੈਂਡਸਕੇਪ ਮੋਡ"</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">"ਚਾਲੂ"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ਬੰਦ"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ਸਮਝ ਲਿਆ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਰੋਕੋ"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ਰੋਕ ਹਟਾਓ"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਦੀ ਸਮਾਂ-ਸੂਚੀ"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ਫਿਲਟਰ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ਇਹ ਕਾਰਵਾਈ ਅਸਫਲ ਹੋਈ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 861be1e..bde1d2f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s – ustawienia użycia"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nowe okno"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Zapisz parę aplikacji"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta para aplikacji nie jest obsługiwana na tym urządzeniu"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatki"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Pokaż wszystko"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Pokaż wszystkie widżety"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Wyświetlam wszystkie widżety"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Kliknij, aby zmienić ustawienia widżetu"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmień ustawienia widżetu"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Wyszukaj aplikacje"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Funkcja wyłączona przez administratora"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Zezwalaj na obrót ekranu głównego"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Po obróceniu telefonu"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Tryb poziomy"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Przestaw telefon w tryb poziomy"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Kropki powiadomień"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Włączone"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Wyłączone"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Wstrzymaj aplikacje służbowe"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Cofnij wstrzymywanie"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Harmonogram aplikacji służbowych"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruj"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Przestrzeń prywatna"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 04bff1f..1fadfdd 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Definições de utilização para %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nova janela"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar par de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este par de apps não é suportado neste dispositivo"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicione o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar tudo"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostrar todos os widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"A mostrar todos os widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para alterar as definições do widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Alterar definições do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativada pelo gestor"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permitir rotação do ecrã principal"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Quando o telemóvel é rodado"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modo horizontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Defina o telemóvel para o modo horizontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Pontos de notificação"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Ativados"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desativados"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pausar apps de trabalho"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Retomar"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Horário das apps de trabalho"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 20cc9fb..e2cf070 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configurações de uso de %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nova janela"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvar par de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este Par de apps não está disponível no dispositivo"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anotações"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicionar o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar tudo"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Mostrar todos os widgets"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Mostrando todos os widgets"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para mudar as configurações do widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mudar as configurações do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativado pelo administrador"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permitir a rotação da tela inicial"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Quando o smartphone for girado"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modo paisagem"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Definir o smartphone para o modo paisagem"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Pontos de notificação"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Ativados"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desativado"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Ok"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pausar apps de trabalho"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ativar"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Programação de apps de trabalho"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 4226920..71d16cb 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setări de utilizare pentru %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Fereastră nouă"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvează perechea de aplicații"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Perechea de aplicații nu este acceptată pe acest dispozitiv"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Luare de notițe"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adaugă"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adaugă widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Afișează tot"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Afișează toate widgeturile"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Se afișează toate widgeturile"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Atinge ca să schimbi setările pentru widgeturi"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifică setările pentru widgeturi"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Caută aplicații"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dezactivată de administrator"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Permite rotirea ecranului de pornire"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Când telefonul este rotit"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modul Peisaj"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Setează telefonul în modul Peisaj"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Puncte de notificare"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activate"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Dezactivate"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Întrerupe aplicațiile pentru lucru"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Anulează întreruperea"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Programul aplicațiilor pentru lucru"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtru"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spațiu privat"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2b827ef..10af874 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки использования приложения \"%1$s\""</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Новое окно"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Сохранить приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Одновременно использовать эти два приложения на устройстве нельзя."</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Создание заметок"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Добавить"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавить виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Показать все"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Показать все виджеты"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Показаны все виджеты"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Нажмите, чтобы изменить настройки виджета"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Изменить настройки виджета"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Поиск приложений"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Функция отключена администратором"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Разрешить поворачивать главный экран"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"При повороте телефона"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Горизонтальный режим"</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">"Включены"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Отключены"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ОК"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Приостановить рабочие приложения"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Возобновить"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Расписание рабочих приложений"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фильтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
<string name="private_space_label" msgid="2359721649407947001">"Частное пространство"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 646443e..44fc1da 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s සඳහා භාවිත සැකසීම්"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"නව කවුළුව"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"යෙදුම් යුගල සුරකින්න"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"මෙම යෙදුම් යුගලය මෙම උපාංගයෙහි සහාය නොදක්වයි"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"සටහන් කර ගැනීම"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"එක් කරන්න"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව එක් කරන්න"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"සියල්ල පෙන්වන්න"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"සියලු ම විජට් පෙන්වන්න"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"සියලුම විජට් පෙන්වමින්"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"විජට් සැකසීම් වෙනස් කිරීමට තට්ටු කරන්න"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"විජට් සැකසීම් වෙනස් කරන්න"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"යෙදුම් සොයන්න"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ඔබගේ පරිපාලක විසින් අබල කරන ලදී"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"මුල් තිරය කරකැවීමට ඉඩ දෙන්න"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"දුරකථනය කරකවන විට"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"භූ දර්ශන ආකාරය"</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">"ක්රියාත්මකයි"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ක්රියාවිරහිතයි"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"තේරුණා"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"කාර්යාල යෙදුම් විරාම කරන්න"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"විරාම නොකරන්න"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"කාර්යාල යෙදුම් කාල සටහන"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"පෙරහන"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"අසාර්ථකයි: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"පෞද්ගලික ඉඩ"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index f9245cd..8eb4e38 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavenia používania pre %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nové okno"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uložiť pár aplikácií"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikácií nie je v tomto zariadení podporovaný"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridať miniaplikáciu <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Zobraziť všetko"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Zobraziť všetky miniaplikácie"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Zobrazujú sa všetky miniaplikácie"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím zmeňte nastavenia miniaplikácie"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmena nastavení miniaplikácie"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hľadať aplikácie"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Zakázané vaším správcom"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Povoliť otáčanie plochy"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Pri otočení telefónu"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Režim na šírku"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Nastavte v telefóne režim na šírku"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Bodky upozornení"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Zapnuté"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Vypnuté"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Dobre"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pozastaviť pracovné aplikácie"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Zrušiť pozastavenie"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Plán pre pracovné aplikácie"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrujte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Súkromný priestor"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index e8d8702..9c2221b 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavitve uporabe za »%1$s«"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Novo okno"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Shrani par aplikacij"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta par aplikacij ni podprt v tej napravi"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ustvarjanje zapiskov"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajanje pripomočka »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Pokaži vse"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Prikaz vseh pripomočkov"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Prikazani so vsi pripomočki"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dotaknite se, če želite spremeniti nastavitve pripomočka."</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Spreminjanje nastavitev pripomočka"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Iskanje programov"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogočil skrbnik."</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Dovoli sukanje začetnega zaslona"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Ko se telefon zasuka"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Ležeči način"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefon preklopite v ležeči način"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Obvestilne pike"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Vklopljeno"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Izklopljeno"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"V redu"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Začasno zaustavi delovne aplikacije"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Znova aktiviraj"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Razpored delovnih aplikacij"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1e5420a..ced2c8c 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Cilësimet e përdorimit për \"%1$s\""</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Dritare e re"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Ruaj çiftin e aplikacioneve"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ky çift aplikacionesh nuk mbështetet në këtë pajisje"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Shfaq të gjitha"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Shfaq të gjitha miniaplikacionet"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Po shfaqen të gjitha miniaplikacionet"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trokit për të ndryshuar cilësimet e miniaplikacionit"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ndrysho cilësimet e miniaplikacionit"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Kërko për aplikacione"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Çaktivizuar nga administratori"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Lejo rrotullimin e ekranit bazë"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kur telefoni rrotullohet"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Modaliteti horizontal"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Vendose telefonin në modalitetin horizontal"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Pikat e njoftimeve"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Aktiv"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Joaktiv"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"E kuptova"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Vendos në pauzë aplikacionet e punës"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Hiq nga pauza"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Orari për aplikacionet e punës"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Hapësira private"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index c5b7bd0..b4cc0e5 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Подешавања потрошње за %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Нови прозор"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Сачувај пар апликација"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Овај пар апликација није подржан на овом уређају"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Прављење бележака"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додајте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Прикажи све"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Прикажите све виџете"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Приказују се сви виџети"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промените подешавања виџета"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Претражите апликације"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администратор је онемогућио"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Дозволи ротацију почетног екрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Када се телефон ротира"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Водоравни режим"</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">"Укључено"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Искључено"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Важи"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Паузирај пословне апликације"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Поново активирај"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Распоред за пословне апликације"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватни простор"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 9ebf366..52b8108 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Användningsinställningar för %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Nytt fönster"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Spara app-par"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lägg till"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lägg till widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Visa alla"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Visa alla widgetar"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Visar alla widgetar"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryck för att ändra inställningarna för widgeten"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ändra inställningarna för widgeten"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sök efter appar"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inaktiverat av administratören"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Tillåt rotering av startskärmen"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"När telefonen vrids"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Liggande"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Ställ in telefonen på liggande läge"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Aviseringsprickar"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"På"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Av"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pausa jobbappar"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Återuppta"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Schema för jobbappar"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a7725f3..5acef91 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mipangilio ya matumizi ya %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Dirisha Jipya"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Hifadhi jozi ya programu"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Jozi hii ya programu haitumiki kwenye kifaa hiki"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Kuandika madokezo"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Weka"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Weka wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Onyesha zote"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Onyesha wijeti zote"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Inaonyesha wijeti zote"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Gusa ili ubadilishe mipangilio ya wijeti"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Badilisha mipangilio ya wijeti"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tafuta programu"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Imezimwa na msimamizi wako"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Ruhusu kipengele cha kuzungusha skrini ya kwanza"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Simu inapozungushwa"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Mkao wa mlalo"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Weka simu katika mkao wa mlalo"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Vitone vya arifa"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Imewashwa"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Imezimwa"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Nimeelewa"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Simamisha programu za kazini"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Acha kusimamisha"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Ratiba ya programu za kazini"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 295367d..ea84963 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sக்கான உபயோக அமைப்புகள்"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"புதிய சாளரம்"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"இந்தச் சாதனத்தில் இந்த ஆப்ஸ் ஜோடி ஆதரிக்கப்படவில்லை"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"குறிப்பெடுத்தல்"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"சேர்"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்டைச் சேர்க்கும்"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"எல்லாம் காட்டு"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"அனைத்து விட்ஜெட்களையும் காட்டும்"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"அனைத்து விட்ஜெட்களையும் காட்டுகிறது"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"விட்ஜெட் அமைப்புகளை மாற்றத் தட்டவும்"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"விட்ஜெட் அமைப்புகளை மாற்றும்"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ஆப்ஸில் தேடுக"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"உங்கள் நிர்வாகி முடக்கியுள்ளார்"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"முகப்புத் திரை சுழற்சியை அனுமதித்தல்"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"மொபைலைச் சுழற்றும் போது"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"லேண்ட்ஸ்கேப் பயன்முறை"</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">"ஆன்"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ஆஃப்"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"சரி"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"பணி ஆப்ஸை இடைநிறுத்து"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"மீண்டும் இயக்கு"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"பணி ஆப்ஸுக்கான திட்ட அட்டவணை"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"வடிப்பான்"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"தோல்வி: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"தனிப்பட்ட சேமிப்பிடம்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 5859665..f445d77 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sకు సంబంధించిన వినియోగ సెట్టింగ్లు"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"కొత్త విండో"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"యాప్ పెయిర్ను సేవ్ చేయండి"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ఈ పరికరంలో ఈ యాప్ పెయిర్ సపోర్ట్ చేయదు"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"నోట్-టేకింగ్"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"జోడించండి"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్ను జోడించండి"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"అన్నీ చూడండి"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"అన్ని విడ్జెట్లను చూపండి"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"అన్ని విడ్జెట్లు చూపబడుతున్నాయి"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"విడ్జెట్ సెట్టింగ్లను మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"విడ్జెట్ సెట్టింగ్లను మార్చండి"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"యాప్ల కోసం సెర్చ్ చేయండి"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"మీ నిర్వాహకులు నిలిపివేసారు"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"మొదటి స్క్రీన్ రొటేషన్ను అనుమతించండి"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"ఫోన్ను తిప్పినప్పుడు"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"ల్యాండ్స్కేప్ మోడ్"</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">"ఆన్"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ఆఫ్"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"అర్థమైంది"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"వర్క్ యాప్లను పాజ్ చేయండి"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"పాజ్ నుండి తీసివేయండి"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"వర్క్ యాప్ల షెడ్యూల్"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ఫిల్టర్ చేయి"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"విఫలమైంది: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ప్రైవేట్ స్పేస్"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index fd2ba21..6acf390 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"การตั้งค่าการใช้งานสำหรับ %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"หน้าต่างใหม่"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"บันทึกคู่แอป"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ไม่รองรับคู่แอปนี้ในอุปกรณ์เครื่องนี้"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"การจดบันทึก"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"เพิ่ม"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"แสดงทั้งหมด"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"แสดงวิดเจ็ตทั้งหมด"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"กำลังแสดงวิดเจ็ตทั้งหมด"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"แตะเพื่อเปลี่ยนการตั้งค่าวิดเจ็ต"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"เปลี่ยนการตั้งค่าวิดเจ็ต"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ค้นหาแอป"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"ปิดใช้โดยผู้ดูแลระบบ"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"อนุญาตให้หมุนหน้าจอหลัก"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"เมื่อหมุนโทรศัพท์"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"โหมดแนวนอน"</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">"เปิด"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"ปิด"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"รับทราบ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"หยุดแอปงานชั่วคราว"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ยกเลิกการหยุดชั่วคราว"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"กำหนดเวลาของแอปงาน"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"ตัวกรอง"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ไม่สำเร็จ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"พื้นที่ส่วนตัว"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 69f88e1..0cef73a 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mga setting ng paggamit para sa %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Bagong Window"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"I-save ang app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hindi sinusuportahan sa device na ito ang pares ng app na ito"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pagtatala"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Idagdag"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Idagdag ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Ipakita lahat"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Ipakita ang lahat ng widget"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Ipinapakita ang lahat ng widget"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"I-tap para baguhin ang mga setting ng widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Baguhin ang mga setting ng widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Na-disable ng iyong admin"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Payagan ang pag-rotate ng home screen"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Kailan maro-rotate ang telepono"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Landscape mode"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Itakda ang telepono sa landscape mode"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Mga notification dot"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Naka-on"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Naka-off"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"I-pause ang mga app para sa trabaho"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"I-unpause"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Iskedyul ng mga app para sa trabaho"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Pribadong space"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index e61b670..8dbcc49 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ile ilgili kullanım ayarları"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Yeni Pencere"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uygulama çiftini kaydedin"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu uygulama çifti bu cihazda desteklenmiyor"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Not alma"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ekle"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ekle"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tümünü göster"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Tüm widget\'ları göster"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Tüm widget\'lar gösteriliyor"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Widget ayarlarını değiştirmek için dokunun"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget ayarlarını değiştir"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Uygulamalarda ara"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Yöneticiniz tarafından devre dışı bırakıldı"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Ana ekranı döndürmeye izin ver"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon döndürüldüğünde"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Yatay mod"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefonu yatay moda ayarlayın"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Bildirim noktaları"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Açık"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Kapalı"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Anladım"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"İş uygulamalarını duraklat"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Devam ettir"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"İş uygulamaları programı"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Gizli alan"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index fd293e3..069277d 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Параметри використання (%1$s)"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Нове вікно"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Зберегти пару додатків"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ці два додатки не можна одночасно використовувати на цьому пристрої"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Створення нотаток"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Додати"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додати віджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Показати всі"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Показати всі віджети"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Показано всі віджети"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Натисніть, щоб змінити налаштування віджета"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Змінити налаштування віджета"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук додатків"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Вимкнув адміністратор"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Дозволити обертання головного екрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Коли телефон обертається"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Альбомна орієнтація"</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">"Увімкнено"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Вимкнено"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Зрозуміло"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Призупинити робочі додатки"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Відновити"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Розклад призупинення робочих додатків"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 911a2d5..3cbfd1b 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s کے لیے ایپ کی معلومات"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s کیلئے استعمال کی ترتیبات"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"نئی ونڈو"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ایپس کے جوڑے کو محفوظ کریں"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ایپس کا یہ جوڑا اس آلے پر تعاون یافتہ نہیں ہے"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"نوٹ لکھنا"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"شامل کریں"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ شامل کریں"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"سبھی دکھائیں"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"سبھی ویجیٹس دکھائیں"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"سبھی ویجیٹس دکھائے جا رہے ہیں"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ویجیٹ ترتیبات تبدیل کرنے کے لیے تھپتھپائیں"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ویجیٹ ترتیبات تبدیل کریں"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ایپس تلاش کریں"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"آپ کے منتظم کی طرف سے غیر فعال کر دیا گیا"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"ہوم اسکرین گھمانے کی اجازت دیں"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"جب فون گھمایا جاتا ہے"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"لینڈ اسکیپ وضع"</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">"آن ہے"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"آف ہے"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"سمجھ آ گئی"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"ورک ایپس موقوف کریں"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"چلائیں"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"ورک ایپس کا شیڈول"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"فلٹر"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ناکام ہو گيا: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"نجی اسپیس"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index aacb35f..2b77321 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s uchun sarf sozlamalari"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Yangi oyna"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Ilova juftini saqlash"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu ilova jufti ushbu qurilmada ishlamaydi"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qayd olish"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Chiqarish"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjetini chiqarish"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hammasi"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Barcha vidjetlar"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Barcha vidjetlar chiqarilgan"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidjet sozlamalarini oʻzgartirish uchun bosing"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidjet sozlamalarini oʻzgartirish"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Ilovalarni qidirish"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator tomonidan o‘chirilgan"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Bosh ekranni burishga ruxsat"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon burilganda"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Yotiq rejim"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Telefonni yotiq rejimga oʻtkazish"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Bildirishnoma belgilari"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Yoniq"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Oʻchiq"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Ishga oid ilovalarni pauza qilish"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Pauzadan chiqarish"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Ishga oid ilovalar jadvali"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Saralash"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index cea93da..ae49356 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Chế độ cài đặt mức sử dụng %1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Cửa sổ mới"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Lưu cặp ứng dụng"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cặp ứng dụng này không hoạt động được trên thiết bị này"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ghi chú"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Thêm"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hiện tất cả"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Hiện tất cả tiện ích"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Đang hiện tất cả tiện ích"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Nhấn để thay đổi chế độ cài đặt tiện ích"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Thay đổi chế độ cài đặt tiện ích"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tìm kiếm ứng dụng"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Bị tắt bởi quản trị viên của bạn"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Cho phép xoay màn hình chính"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Khi xoay điện thoại"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Chế độ ngang"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Đặt điện thoại ở chế độ ngang"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Dấu chấm thông báo"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Đang bật"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Tắt"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Tôi hiểu"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Tạm dừng các ứng dụng công việc"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Bỏ tạm dừng"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Lịch biểu cho ứng dụng công việc"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Bộ lọc"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Không gian riêng tư"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 9efd6c3..69d92f8 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s的使用设置"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"新窗口"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"保存应用组合"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"在该设备上无法使用此应用对"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"记事"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"添加"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"添加“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"全部显示"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"显示所有微件"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"正在显示所有微件"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"点按即可更改微件设置"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"更改微件设置"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜索应用"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"已被您的管理员停用"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"允许旋转主屏幕"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"手机旋转时"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"横屏模式"</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">"已开启"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"已关闭"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"知道了"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"暂停工作应用"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"取消暂停"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"工作应用时间表"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"过滤器"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私密空间"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index c944240..3589167 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"新視窗"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"此裝置不支援此應用程式配對"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"加<xliff:g id="WIDGET_NAME">%1$s</xliff:g>小工具"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"顯示全部"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"顯示所有小工具"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"顯示所有小工具"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕按即可變更小工具設定"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"變更小工具設定"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"已由你的管理員停用"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"允許旋轉主畫面"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"隨手機旋轉"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"水平模式"</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">"開啟"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"關閉"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"知道了"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"暫停工作應用程式"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"取消暫停"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"工作應用程式時間表"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"操作失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 476c0e5..3f16360 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"新視窗"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"這部裝置不支援這組應用程式配對"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"新增「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"全部顯示"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"顯示所有小工具"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"現已顯示所有小工具"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕觸即可變更小工具設定"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"變更小工具設定"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"已由你的管理員停用"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"允許旋轉主畫面"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"當手機旋轉時"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"橫向模式"</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">"開啟"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"關閉"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"我知道了"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"暫停工作應用程式"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"取消暫停"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"工作應用程式時間表"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 623454b..63fd982 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -32,6 +32,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Amasethingi okusetshenziswa ka-%1$s"</string>
<string name="new_window_option_taskbar" msgid="6448780542727767211">"Iwindi Elisha"</string>
+ <!-- no translation found for manage_windows_option_taskbar (2294109489960654212) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Londoloza i-app ebhangqiwe"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Lokhu kubhanqwa kwe-app akusekelwa kule divayisi"</string>
@@ -69,12 +71,9 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ukuthatha amanothi"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Engeza"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engeza iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for widgets_list_expand_button_label (7912016136574932622) -->
- <skip />
- <!-- no translation found for widgets_list_expand_button_content_description (4600513860973450888) -->
- <skip />
- <!-- no translation found for widgets_list_expanded (7374857868788557730) -->
- <skip />
+ <string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Bonisa konke"</string>
+ <string name="widgets_list_expand_button_content_description" msgid="4600513860973450888">"Bonisa wonke amawijethi"</string>
+ <string name="widgets_list_expanded" msgid="7374857868788557730">"Ibonisa wonke amawijethi"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Thepha ukuze ushintshe amasethingi ewijethi"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Shintsha amasethingi ewijethi"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sesha izinhlelo zokusebenza"</string>
@@ -130,10 +129,8 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Kukhutshazwe umlawuli wakho"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Vumela ukuzungezisa kwesikrini sasekhaya"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Uma ifoni iphendukiswa"</string>
- <!-- no translation found for landscape_mode_title (5138814555934843926) -->
- <skip />
- <!-- no translation found for landscape_mode_desc (7372569859592816793) -->
- <skip />
+ <string name="landscape_mode_title" msgid="5138814555934843926">"Imodi yokuvundla"</string>
+ <string name="landscape_mode_desc" msgid="7372569859592816793">"Setha ifoni kumodi yokuvundla"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Amacashazi esaziso"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Vuliwe"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Valiwe"</string>
@@ -198,8 +195,7 @@
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Ngiyezwa"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Misa ama-app omsebenzi"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Susa ukumisa"</string>
- <!-- no translation found for work_scheduler_button_content_description (917340740986764967) -->
- <skip />
+ <string name="work_scheduler_button_content_description" msgid="917340740986764967">"Ishejuli yama-app omsebenzi"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Hlunga"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Isikhala esiyimfihlo"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 77d789f..535d61f 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -58,16 +58,16 @@
<attr name="materialColorSecondaryFixedDim" format="color" />
<attr name="materialColorOnErrorContainer" format="color" />
<attr name="materialColorOnSecondaryFixed" format="color" />
- <attr name="materialColorOnSurfaceInverse" format="color" />
+ <attr name="materialColorInverseOnSurface" format="color" />
<attr name="materialColorTertiaryFixedDim" format="color" />
<attr name="materialColorOnTertiaryFixed" format="color" />
<attr name="materialColorPrimaryFixedDim" format="color" />
<attr name="materialColorSecondaryContainer" format="color" />
<attr name="materialColorErrorContainer" format="color" />
<attr name="materialColorOnPrimaryFixed" format="color" />
- <attr name="materialColorPrimaryInverse" format="color" />
+ <attr name="materialColorInversePrimary" format="color" />
<attr name="materialColorSecondaryFixed" format="color" />
- <attr name="materialColorSurfaceInverse" format="color" />
+ <attr name="materialColorInverseSurface" format="color" />
<attr name="materialColorSurfaceVariant" format="color" />
<attr name="materialColorTertiaryContainer" format="color" />
<attr name="materialColorTertiaryFixed" format="color" />
@@ -210,10 +210,10 @@
<attr name="layout_sticky" format="boolean" />
</declare-styleable>
- <declare-styleable name="NumRows">
+ <declare-styleable name="GridDimension">
<attr name="minDeviceWidthPx" format="float"/>
<attr name="minDeviceHeightPx" format="float"/>
- <attr name="numRowsNew" format="integer"/>
+ <attr name="numGridDimension" format="integer"/>
<attr name="dbFile" />
<attr name="defaultLayoutId"/>
<attr name="demoModeLayoutId"/>
@@ -312,9 +312,10 @@
<attr name="rowCountSpecsId" format="reference" />
<!-- defaults to allAppsCellSpecsId, if not specified -->
<attr name="allAppsCellSpecsTwoPanelId" format="reference" />
-
<!-- defaults to false, if not specified -->
<attr name="isFixedLandscape" format="boolean" />
+ <!-- defaults to false, if not specified -->
+ <attr name="isOldGrid" format="boolean" />
<!-- By default all categories are enabled -->
<attr name="deviceCategory" format="integer">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c69778a..0d4e79b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -125,9 +125,8 @@
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
<dimen name="all_apps_tabs_button_horizontal_padding">4dp</dimen>
- <dimen name="all_apps_tabs_vertical_padding">6dp</dimen>
- <dimen name="all_apps_tabs_vertical_padding_focus">1dp</dimen>
- <dimen name="all_apps_tabs_focus_width">5dp</dimen>
+ <dimen name="all_apps_tabs_focus_horizontal_inset">5dp</dimen>
+ <dimen name="all_apps_tabs_focus_vertical_inset">6dp</dimen>
<dimen name="all_apps_tabs_focus_border">3dp</dimen>
<dimen name="all_apps_tabs_focus_padding">2dp</dimen>
<dimen name="all_apps_tabs_margin_top">8dp</dimen>
@@ -155,6 +154,7 @@
<!-- Floating action button inside work tab to toggle work profile -->
<dimen name="work_fab_height">56dp</dimen>
<dimen name="work_fab_radius">16dp</dimen>
+ <dimen name="work_fab_elevation">6dp</dimen>
<dimen name="work_fab_icon_size">24dp</dimen>
<dimen name="work_fab_icon_vertical_margin">16dp</dimen>
<dimen name="work_fab_icon_start_margin_expanded">4dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 123e2b8..f7069a6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -47,6 +47,8 @@
<!-- Title for an option to open a new window for a given app -->
<string name="new_window_option_taskbar">New Window</string>
+ <!-- Title for an option to manage open windows for a given app -->
+ <string name="manage_windows_option_taskbar">Manage Windows</string>
<!-- App pairs -->
<string name="save_app_pair">Save app pair</string>
@@ -456,7 +458,7 @@
<string name="widget_resized">Widget resized to width <xliff:g id="number" example="2">%1$s</xliff:g> height <xliff:g id="number" example="1">%2$s</xliff:g></string>
<!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] -->
- <string name="action_deep_shortcut">Shortcuts</string>
+ <string name="action_deep_shortcut">Shortcut Menu</string>
<!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
<string name="action_dismiss_notification">Dismiss</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6d3579b..1c70d6c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -41,16 +41,16 @@
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
<item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
+ <item name="materialColorInverseOnSurface">@color/system_on_surface_dark</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
<item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
<item name="materialColorErrorContainer">@color/system_error_container_light</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
+ <item name="materialColorInversePrimary">@color/system_primary_dark</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
+ <item name="materialColorInverseSurface">@color/system_surface_dark</item>
<item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
<item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 34cf56b..817cc40 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -20,6 +20,7 @@
import static android.graphics.fonts.FontStyle.FONT_WEIGHT_NORMAL;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
+import static com.android.launcher3.Flags.enableContrastTiles;
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
@@ -39,6 +40,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.icu.text.MessageFormat;
@@ -125,6 +127,8 @@
private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
+ private static final int APP_PILL_TITLE_PADDING = 8;
+
private float mScaleForReorderBounce = 1f;
private IntArray mBreakPointsIntArray;
@@ -722,6 +726,34 @@
}
}
+ /** Draws a background behind the App Title label when required. **/
+ public void drawAppContrastTile(Canvas canvas) {
+ RectF appTitleBounds;
+ Paint.FontMetrics fm = getPaint().getFontMetrics();
+ Rect tmpRect = new Rect();
+ getDrawingRect(tmpRect);
+ CharSequence text = getText();
+
+ float titleLength = (getPaint().measureText(text, 0, text.length())
+ + APP_PILL_TITLE_PADDING * 2);
+ titleLength = Math.min(titleLength, tmpRect.width());
+ appTitleBounds = new RectF((tmpRect.width() - titleLength) / 2.f - getCompoundPaddingLeft(),
+ 0, (tmpRect.width() + titleLength) / 2.f + getCompoundPaddingRight(),
+ (int) Math.ceil(fm.bottom - fm.top));
+
+
+ if (mIcon != null) {
+ Rect iconBounds = new Rect();
+ getIconBounds(iconBounds);
+ int textStart = iconBounds.bottom + getCompoundDrawablePadding();
+ appTitleBounds.offset(0, textStart);
+ }
+
+ canvas.drawRoundRect(appTitleBounds, appTitleBounds.height() / 2,
+ appTitleBounds.height() / 2,
+ PillColorProvider.getInstance(getContext()).getAppTitlePillPaint());
+ }
+
/** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
if (mRunningAppState == RunningAppState.NOT_RUNNING || mDisplay != DISPLAY_TASKBAR) {
@@ -826,6 +858,11 @@
setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
getPaddingBottom());
}
+ if (shouldDrawAppContrastTile()) {
+ setPadding(getPaddingLeft() + APP_PILL_TITLE_PADDING, getPaddingTop(),
+ getPaddingRight() + APP_PILL_TITLE_PADDING,
+ getPaddingBottom());
+ }
// Only apply two line for all_apps and device search only if necessary.
if (shouldUseTwoLine() && (mLastOriginalText != null)) {
int allowedVerticalSpace = height - getPaddingTop() - getPaddingBottom()
@@ -909,7 +946,9 @@
@Override
public void setTextColor(ColorStateList colors) {
- mTextColor = colors.getDefaultColor();
+ mTextColor = shouldDrawAppContrastTile() ? PillColorProvider.getInstance(
+ getContext()).getAppTitleTextPaint().getColor()
+ : colors.getDefaultColor();
mTextColorStateList = colors;
if (Float.compare(mTextAlpha, 1) == 0) {
super.setTextColor(colors);
@@ -926,6 +965,15 @@
&& info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION);
}
+ /**
+ * Whether or not an App title contrast tile should be drawn for this element.
+ **/
+ public boolean shouldDrawAppContrastTile() {
+ return mDisplay == DISPLAY_WORKSPACE && shouldTextBeVisible()
+ && PillColorProvider.getInstance(getContext()).isMatchaEnabled()
+ && enableContrastTiles();
+ }
+
public void setTextVisibility(boolean visible) {
setTextAlpha(visible ? 1 : 0);
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 3d715e5..867bf98 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -41,8 +41,11 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.MSDLPlayerWrapper;
import com.android.launcher3.views.ActivityContext;
+import com.google.android.msdl.data.model.MSDLToken;
+
/**
* Implements a DropTarget.
*/
@@ -62,6 +65,7 @@
protected final ActivityContext mActivityContext;
protected final DropTargetHandler mDropTargetHandler;
protected DropTargetBar mDropTargetBar;
+ private final MSDLPlayerWrapper mMSDLPlayerWrapper;
/** Whether this drop target is active for the current drag */
protected boolean mActive;
@@ -94,6 +98,7 @@
super(context, attrs, defStyle);
mActivityContext = ActivityContext.lookupContext(context);
mDropTargetHandler = mActivityContext.getDropTargetHandler();
+ mMSDLPlayerWrapper = MSDLPlayerWrapper.INSTANCE.get(context);
Resources resources = getResources();
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
@@ -142,6 +147,10 @@
@Override
public final void onDragEnter(DragObject d) {
+ // Perform Haptic feedback
+ if (Flags.msdlFeedback()) {
+ mMSDLPlayerWrapper.playToken(MSDLToken.SWIPE_THRESHOLD_INDICATOR);
+ }
if (!mAccessibleDrag && !mTextVisible) {
// Show tooltip
hideTooltip();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 78535a1..09225e7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1833,7 +1833,8 @@
workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace;
}
int paddingTop = workspaceTopPadding + (mIsScalableGrid ? 0 : edgeMarginPx);
- int paddingSide = desiredWorkspaceHorizontalMarginPx;
+ // On isFixedLandscapeMode on phones we already have padding because of the camera hole
+ int paddingSide = inv.isFixedLandscapeMode ? 0 : desiredWorkspaceHorizontalMarginPx;
padding.set(paddingSide, paddingTop, paddingSide, paddingBottom);
}
@@ -1941,10 +1942,8 @@
startSpacing += getAdditionalQsbSpace();
if (inv.isFixedLandscapeMode) {
- endSpacing += workspacePadding.right + cellLayoutPaddingPx.right
- + mInsets.right;
- startSpacing += workspacePadding.left + cellLayoutPaddingPx.left
- + mInsets.left;
+ endSpacing += mInsets.right;
+ startSpacing += mInsets.left;
}
hotseatBarPadding.top = hotseatBarTopPadding;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6468f74..b2ccba4 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -187,22 +187,20 @@
public void adjustForBubbleBar(boolean isBubbleBarVisible) {
DeviceProfile dp = mActivity.getDeviceProfile();
float adjustedBorderSpace = dp.getHotseatAdjustedBorderSpaceForBubbleBar(getContext());
- boolean adjustmentRequired = Float.compare(adjustedBorderSpace, 0f) != 0;
-
+ boolean shouldAdjustHotseat = isBubbleBarVisible
+ && Float.compare(adjustedBorderSpace, 0f) != 0;
ShortcutAndWidgetContainer icons = getShortcutsAndWidgets();
// update the translation provider for future layout passes of hotseat icons.
- if (adjustmentRequired && isBubbleBarVisible) {
+ if (shouldAdjustHotseat) {
icons.setTranslationProvider(
cellX -> dp.getHotseatAdjustedTranslation(getContext(), cellX));
} else {
icons.setTranslationProvider(null);
}
- if (!adjustmentRequired) return;
-
AnimatorSet animatorSet = new AnimatorSet();
for (int i = 0; i < icons.getChildCount(); i++) {
View child = icons.getChildAt(i);
- float tx = isBubbleBarVisible ? dp.getHotseatAdjustedTranslation(getContext(), i) : 0;
+ float tx = shouldAdjustHotseat ? dp.getHotseatAdjustedTranslation(getContext(), i) : 0;
if (child instanceof Reorderable) {
MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate();
animatorSet.play(
@@ -213,8 +211,8 @@
}
if (mQsb instanceof HorizontalInsettableView horizontalInsettableQsb) {
final float currentInsetFraction = horizontalInsettableQsb.getHorizontalInsets();
- final float targetInsetFraction =
- isBubbleBarVisible ? (float) dp.iconSizePx / dp.hotseatQsbWidth : 0;
+ final float targetInsetFraction = shouldAdjustHotseat
+ ? (float) dp.iconSizePx / dp.hotseatQsbWidth : 0;
ValueAnimator qsbAnimator =
ValueAnimator.ofFloat(currentInsetFraction, targetInsetFraction);
qsbAnimator.addUpdateListener(animation -> {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 04e4b57..e1d84be 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -651,14 +651,14 @@
}
/**
- * Parses through the xml to find NumRows specs. Then calls findBestRowCount to get the correct
- * row count for this GridOption.
+ * Parses through the xml to find GridDimension specs. Then calls findBestRowCount to get the
+ * correct row count for this GridOption.
*
* @return the result of {@link #findBestRowCount(List, Info)}.
*/
- public static NumRows getRowCount(ResourceHelper resourceHelper, Context context,
+ public static GridDimension getRowCount(ResourceHelper resourceHelper, Context context,
Info displayInfo) {
- ArrayList<NumRows> rowCounts = new ArrayList<>();
+ ArrayList<GridDimension> rowCounts = new ArrayList<>();
try (XmlResourceParser parser = resourceHelper.getXml()) {
final int depth = parser.getDepth();
@@ -666,8 +666,8 @@
while (((type = parser.next()) != XmlPullParser.END_TAG
|| parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if ((type == XmlPullParser.START_TAG)
- && "NumRows".equals(parser.getName())) {
- rowCounts.add(new NumRows(context, Xml.asAttributeSet(parser)));
+ && "GridDimension".equals(parser.getName())) {
+ rowCounts.add(new GridDimension(context, Xml.asAttributeSet(parser)));
}
}
} catch (IOException | XmlPullParserException e) {
@@ -678,10 +678,10 @@
}
/**
- * @return the biggest row count that fits the display dimensions spec using NumRows to
+ * @return the biggest row count that fits the display dimensions spec using GridDimension to
* determine that. If no best row count is found, return -1.
*/
- public static NumRows findBestRowCount(List<NumRows> list, Info displayInfo) {
+ public static GridDimension findBestRowCount(List<GridDimension> list, Info displayInfo) {
int minWidthPx = Integer.MAX_VALUE;
int minHeightPx = Integer.MAX_VALUE;
for (WindowBounds bounds : displayInfo.supportedBounds) {
@@ -700,10 +700,10 @@
}
}
- NumRows selectedRow = null;
- for (NumRows item: list) {
+ GridDimension selectedRow = null;
+ for (GridDimension item: list) {
if (minWidthPx >= item.mMinDeviceWidthPx && minHeightPx >= item.mMinDeviceHeightPx) {
- if (selectedRow == null || selectedRow.mNumRowsNew < item.mNumRowsNew) {
+ if (selectedRow == null || selectedRow.mNumGridDimension < item.mNumGridDimension) {
selectedRow = item;
}
}
@@ -1031,6 +1031,7 @@
private final int mAllAppsCellSpecsTwoPanelId;
private final int mRowCountSpecsId;
private final boolean mIsFixedLandscape;
+ private final boolean mIsOldGrid;
public GridOption(Context context, AttributeSet attrs, Info displayInfo) {
TypedArray a = context.obtainStyledAttributes(
@@ -1044,8 +1045,8 @@
mIsDualGrid = a.getBoolean(R.styleable.GridDisplayOption_isDualGrid, false);
if (mRowCountSpecsId != INVALID_RESOURCE_HANDLE) {
ResourceHelper resourceHelper = new ResourceHelper(context, mRowCountSpecsId);
- NumRows numR = getRowCount(resourceHelper, context, displayInfo);
- numRows = numR.mNumRowsNew;
+ GridDimension numR = getRowCount(resourceHelper, context, displayInfo);
+ numRows = numR.mNumGridDimension;
dbFile = numR.mDbFile;
defaultLayoutId = numR.mDefaultLayoutId;
demoModeLayoutId = numR.mDemoModeLayoutId;
@@ -1175,6 +1176,7 @@
}
mIsFixedLandscape = a.getBoolean(R.styleable.GridDisplayOption_isFixedLandscape, false);
+ mIsOldGrid = a.getBoolean(R.styleable.GridDisplayOption_isOldGrid, false);
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
DONT_INLINE_QSB);
@@ -1206,25 +1208,35 @@
}
}
- public boolean isNewGridOption() {
- return mRowCountSpecsId != INVALID_RESOURCE_HANDLE;
- }
-
+ /**
+ * Returns true if the grid option should be used given the flags that are toggled on/off.
+ */
public boolean filterByFlag(int deviceType, boolean isFixedLandscape) {
if (deviceType == TYPE_TABLET) {
return Flags.oneGridRotationHandling() == mIsDualGrid;
}
- if (isFixedLandscape) {
- return Flags.oneGridSpecs() && mIsFixedLandscape;
+ // Here we return true if fixed landscape mode should be on.
+ if (mIsFixedLandscape || isFixedLandscape) {
+ return mIsFixedLandscape && isFixedLandscape && Flags.oneGridSpecs();
}
- return ((Flags.oneGridSpecs() == isNewGridOption()) && !mIsFixedLandscape);
+ // Here we return true if we want to show the new grids.
+ if (mRowCountSpecsId != INVALID_RESOURCE_HANDLE) {
+ return Flags.oneGridSpecs();
+ }
+
+ // Here we return true if we want to show the old grids.
+ if (mIsOldGrid) {
+ return !Flags.oneGridSpecs();
+ }
+
+ return true;
}
}
- public static final class NumRows {
- final int mNumRowsNew;
+ public static final class GridDimension {
+ final int mNumGridDimension;
final float mMinDeviceWidthPx;
final float mMinDeviceHeightPx;
final String mDbFile;
@@ -1232,17 +1244,17 @@
final int mDemoModeLayoutId;
- NumRows(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumRows);
+ GridDimension(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridDimension);
- mNumRowsNew = (int) a.getFloat(R.styleable.NumRows_numRowsNew, 0);
- mMinDeviceWidthPx = a.getFloat(R.styleable.NumRows_minDeviceWidthPx, 0);
- mMinDeviceHeightPx = a.getFloat(R.styleable.NumRows_minDeviceHeightPx, 0);
- mDbFile = a.getString(R.styleable.NumRows_dbFile);
+ mNumGridDimension = (int) a.getFloat(R.styleable.GridDimension_numGridDimension, 0);
+ mMinDeviceWidthPx = a.getFloat(R.styleable.GridDimension_minDeviceWidthPx, 0);
+ mMinDeviceHeightPx = a.getFloat(R.styleable.GridDimension_minDeviceHeightPx, 0);
+ mDbFile = a.getString(R.styleable.GridDimension_dbFile);
mDefaultLayoutId = a.getResourceId(
- R.styleable.NumRows_defaultLayoutId, 0);
+ R.styleable.GridDimension_defaultLayoutId, 0);
mDemoModeLayoutId = a.getResourceId(
- R.styleable.NumRows_demoModeLayoutId, mDefaultLayoutId);
+ R.styleable.GridDimension_demoModeLayoutId, mDefaultLayoutId);
a.recycle();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6145077..8981024 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -233,6 +233,7 @@
import com.android.launcher3.util.ItemInflater;
import com.android.launcher3.util.KeyboardShortcutsDelegate;
import com.android.launcher3.util.LockedUserState;
+import com.android.launcher3.util.MSDLPlayerWrapper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.PluginManagerWrapper;
@@ -537,6 +538,7 @@
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
mWidgetPickerDataProvider = new WidgetPickerDataProvider();
+ PillColorProvider.getInstance(mWorkspace.getContext()).registerObserver();
boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
if (internalStateHandled) {
@@ -781,6 +783,11 @@
if (!com.android.launcher3.Flags.oneGridSpecs()) {
return;
}
+ // When the flag oneGridSpecs is on we want to disable ALLOW_ROTATION which is replaced
+ // by FIXED_LANDSCAPE_MODE, ALLOW_ROTATION will only be used on Tablets afterwards.
+ if (getDeviceProfile().isPhone || getDeviceProfile().isTwoPanels) {
+ LauncherPrefs.get(this).put(LauncherPrefs.ALLOW_ROTATION, false);
+ }
getRotationHelper().setFixedLandscape(
Objects.requireNonNull(mDeviceProfile.inv).isFixedLandscapeMode
);
@@ -1813,6 +1820,7 @@
// changes while launcher is still loading.
getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener);
mOverlayManager.onActivityDestroyed();
+ PillColorProvider.getInstance(mWorkspace.getContext()).unregisterObserver();
}
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
@@ -2738,6 +2746,7 @@
mModel.dumpState(prefix, fd, writer, args);
mOverlayManager.dump(prefix, writer);
ACTIVITY_TRACKER.dump(prefix, writer);
+ MSDLPlayerWrapper.INSTANCE.get(getApplicationContext()).dump(prefix, writer);
}
/**
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index df75470..a5b8168 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -24,7 +24,7 @@
public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db";
public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db";
public static final String LAUNCHER_2_BY_2_DB = "launcher_2_by_2.db";
- public static final String LAUNCHER_7_BY_3_DB = "launcher_7_by_3.db";
+ public static final String LAUNCHER_8_BY_3_DB = "launcher_8_by_3.db";
public static final String BACKUP_DB = "backup.db";
public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
public static final String MANAGED_USER_PREFERENCES_KEY =
@@ -45,7 +45,7 @@
LAUNCHER_4_BY_4_DB,
LAUNCHER_3_BY_3_DB,
LAUNCHER_2_BY_2_DB,
- LAUNCHER_7_BY_3_DB));
+ LAUNCHER_8_BY_3_DB));
public static final List<String> OTHER_FILES = Collections.unmodifiableList(Arrays.asList(
BACKUP_DB,
diff --git a/src/com/android/launcher3/PillColorPorovider.kt b/src/com/android/launcher3/PillColorPorovider.kt
new file mode 100644
index 0000000..347c5d6
--- /dev/null
+++ b/src/com/android/launcher3/PillColorPorovider.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3
+
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.Paint
+import android.net.Uri
+import android.provider.Settings
+import com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR
+
+class PillColorProvider private constructor(c: Context) {
+ private val context = c.applicationContext
+
+ private val matchaUri by lazy { Settings.Secure.getUriFor(MATCHA_SETTING) }
+ var appTitlePillPaint = Paint()
+ private set
+
+ var appTitleTextPaint = Paint()
+ private set
+
+ private var isMatchaEnabledInternal = 0
+
+ var isMatchaEnabled = isMatchaEnabledInternal != 0
+
+ private val pillColorObserver =
+ object : ContentObserver(ORDERED_BG_EXECUTOR.handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == matchaUri) {
+ isMatchaEnabledInternal =
+ Settings.Secure.getInt(context.contentResolver, MATCHA_SETTING, 0)
+ isMatchaEnabled = isMatchaEnabledInternal != 0
+ }
+ }
+ }
+
+ fun registerObserver() {
+ context.contentResolver.registerContentObserver(matchaUri, false, pillColorObserver)
+ setup()
+ }
+
+ fun unregisterObserver() {
+ context.contentResolver.unregisterContentObserver(pillColorObserver)
+ }
+
+ fun setup() {
+ appTitlePillPaint.color =
+ context.resources.getColor(
+ R.color.material_color_surface_container_lowest,
+ context.theme,
+ )
+ appTitleTextPaint.color =
+ context.resources.getColor(R.color.material_color_on_surface, context.theme)
+ isMatchaEnabledInternal = Settings.Secure.getInt(context.contentResolver, MATCHA_SETTING, 0)
+ isMatchaEnabled = isMatchaEnabledInternal != 0
+ }
+
+ companion object {
+ private var INSTANCE: PillColorProvider? = null
+ private const val MATCHA_SETTING = "matcha_enable"
+
+ // TODO: Replace with a Dagger injection that is a singleton.
+ @JvmStatic
+ fun getInstance(context: Context): PillColorProvider {
+ if (INSTANCE == null) {
+ INSTANCE = PillColorProvider(context)
+ }
+ return INSTANCE!!
+ }
+ }
+}
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index b3cb948..f4d3146 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -303,10 +303,11 @@
.setData(Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
.putExtra(Intent.EXTRA_USER, info.user);
context.startActivity(i);
- FileLog.d(TAG, "start uninstall activity " + cn.getPackageName());
+ FileLog.d(TAG, "start uninstall activity from drop target " + cn.getPackageName());
return cn;
} catch (URISyntaxException e) {
- Log.e(TAG, "Failed to parse intent to start uninstall activity for item=" + info);
+ Log.e(TAG, "Failed to parse intent to start drop target uninstall activity for"
+ + " item=" + info);
return null;
}
}
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 6168e41..ea5eb8f 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -73,8 +73,9 @@
|| alreadyAddedPromiseIcon) {
FileLog.d(LOG,
String.format(Locale.ENGLISH,
- "Removing PromiseIcon for package: %s, install reason: %d,"
- + " alreadyAddedPromiseIcon: %s",
+ "Removing unneeded PromiseIcon for package: %s"
+ + ", install reason: %d,"
+ + " alreadyAddedPromiseIcon: %s",
info.getAppPackageName(),
info.getInstallReason(),
alreadyAddedPromiseIcon
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0e9c861..95dbf5f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME;
import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
@@ -1222,6 +1223,10 @@
}
protected void onPageBeginTransition() {
+ // Widget resize frame doesn't receive events to close when talkback is enabled. For that
+ // case, close it here.
+ AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_WIDGET_RESIZE_FRAME);
+
super.onPageBeginTransition();
updateChildrenLayersEnabled();
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 1b58987..c938482 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
+import static com.android.window.flags.Flags.predictiveBackThreeButtonNav;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1173,8 +1174,10 @@
super.dispatchDraw(canvas);
if (mNavBarScrimHeight > 0) {
- canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
- mNavBarScrimPaint);
+ float left = (getWidth() - getWidth() / getScaleX()) / 2;
+ float top = getHeight() / 2f + (getHeight() / 2f - mNavBarScrimHeight) / getScaleY();
+ canvas.drawRect(left, top, getWidth() / getScaleX(),
+ top + mNavBarScrimHeight / getScaleY(), mNavBarScrimPaint);
}
}
@@ -1340,6 +1343,17 @@
invalidateHeader();
}
+ @Override
+ public void setScaleY(float scaleY) {
+ super.setScaleY(scaleY);
+ if (predictiveBackThreeButtonNav() && mNavBarScrimHeight > 0) {
+ // Call invalidate to prevent navbar scrim from scaling. The navbar scrim is drawn
+ // directly onto the canvas. To prevent it from being scaled with the canvas, there's a
+ // counter scale applied in dispatchDraw.
+ invalidate(20, getHeight() - mNavBarScrimHeight, getWidth(), getHeight());
+ }
+ }
+
/**
* Set {@link Animator.AnimatorListener} on {@link mAllAppsTransitionController} to observe
* animation of backing out of all apps search view to all apps view.
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 21dce14..609edd2 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -45,6 +45,7 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -220,6 +221,7 @@
* when animation is not running.
*/
public void reset() {
+ Trace.beginSection("PrivateProfileManager#reset");
// Ensure the state of the header view is what it should be before animating.
updateView();
getMainRecyclerView().setChildAttachedConsumer(null);
@@ -239,6 +241,7 @@
executeLock();
}
addPrivateSpaceDecorator(updatedState);
+ Trace.endSection();
}
/** Returns whether or not Private Space Settings Page is available. */
@@ -293,31 +296,12 @@
}
}
- @Override
public void setQuietMode(boolean enable) {
- UI_HELPER_EXECUTOR.post(() ->
- mUserCache.getUserProfiles()
- .stream()
- .filter(getUserMatcher())
- .findFirst()
- .ifPresent(userHandle -> setQuietModeSafely(enable, userHandle)));
+ setQuietMode(enable, mAllApps.mActivityContext);
mReadyToAnimate = true;
}
/**
- * Sets Quiet Mode for Private Profile.
- * If {@link SecurityException} is thrown, prompts the user to set this launcher as HOME app.
- */
- private void setQuietModeSafely(boolean enable, UserHandle userHandle) {
- try {
- mUserManager.requestQuietModeEnabled(enable, userHandle);
- } catch (SecurityException ex) {
- ApiWrapper.INSTANCE.get(mAllApps.mActivityContext)
- .assignDefaultHomeRole(mAllApps.mActivityContext);
- }
- }
-
- /**
* Expand the private space after the app list has been added and updated from
* {@link AlphabeticalAppsList#onAppsUpdated()}
*/
@@ -331,7 +315,9 @@
/** Collapses the private space before the app list has been updated. */
void executeLock() {
+ Trace.beginSection("PrivateProfileManager#executeLock");
MAIN_EXECUTOR.execute(() -> updatePrivateStateAnimator(false));
+ Trace.endSection();
}
void setAnimationRunning(boolean isAnimationRunning) {
@@ -378,6 +364,7 @@
if (mPSHeader == null) {
return;
}
+ Trace.beginSection("PrivateProfileManager#updateView");
Log.d(TAG, "bindPrivateSpaceHeaderViewElements: " + "Updating view with state: "
+ getCurrentState());
mPSHeader.setAlpha(1);
@@ -436,6 +423,7 @@
}
}
mPSHeader.invalidate();
+ Trace.endSection();
}
/** Sets the enablement of the profile when header or button is clicked. */
@@ -840,6 +828,7 @@
ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
List<BaseAllAppsAdapter.AdapterItem> adapterItems =
mainAdapterHolder.mAppsList.getAdapterItems();
+ Trace.beginSection("PrivateProfileManager#expandPrivateSpace");
if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
&& mAllApps.isPersonalTab()) {
// Animate the text and settings icon.
@@ -849,6 +838,7 @@
getPsHeaderHeight(), deviceProfile.allAppsCellHeightPx);
updatePrivateStateAnimator(true);
}
+ Trace.endSection();
}
private void exitSearchAndExpand() {
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 93b6b29..765c29c 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
@@ -26,6 +27,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -69,14 +71,26 @@
}
/** Sets quiet mode as enabled/disabled for the profile type. */
- protected void setQuietMode(boolean enabled) {
+ protected void setQuietMode(boolean enabled, Context context) {
UI_HELPER_EXECUTOR.post(() ->
mUserCache.getUserProfiles()
.stream()
.filter(getUserMatcher())
.findFirst()
.ifPresent(userHandle ->
- mUserManager.requestQuietModeEnabled(enabled, userHandle)));
+ setQuietModeSafely(enabled, userHandle, context)));
+ }
+
+ /**
+ * Sets Quiet Mode for Private Profile.
+ * If {@link SecurityException} is thrown, prompts the user to set this launcher as HOME app.
+ */
+ private void setQuietModeSafely(boolean enable, UserHandle userHandle, Context context) {
+ try {
+ mUserManager.requestQuietModeEnabled(enable, userHandle);
+ } catch (SecurityException ex) {
+ ApiWrapper.INSTANCE.get(context).assignDefaultHomeRole(context);
+ }
}
/** Sets current state for the profile type. */
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 3d0c1d0..6ebab5a 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -74,7 +74,7 @@
*/
public void setWorkProfileEnabled(boolean enabled) {
updateCurrentState(STATE_TRANSITION);
- setQuietMode(!enabled);
+ setQuietMode(!enabled, mAllApps.mActivityContext);
}
@Override
diff --git a/src/com/android/launcher3/dagger/LauncherComponentProvider.kt b/src/com/android/launcher3/dagger/LauncherComponentProvider.kt
new file mode 100644
index 0000000..5015e54
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherComponentProvider.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dagger
+
+import android.content.Context
+import android.view.LayoutInflater
+import com.android.launcher3.LauncherApplication
+
+/**
+ * Utility class to extract LauncherAppComponent from a context.
+ *
+ * If the context doesn't provide LauncherAppComponent by default, it creates a new one and
+ * associate it with that context
+ */
+object LauncherComponentProvider {
+
+ @JvmStatic
+ fun get(c: Context): LauncherAppComponent {
+ val app = c.applicationContext
+ if (app is LauncherApplication) return app.appComponent
+
+ val inflater = LayoutInflater.from(app)
+ val existingFilter = inflater.filter
+ if (existingFilter is Holder) return existingFilter.component
+
+ // Create a new component
+ return Holder(
+ DaggerLauncherAppComponent.builder().appContext(app).build()
+ as LauncherAppComponent,
+ existingFilter,
+ )
+ .apply { inflater.filter = this }
+ .component
+ }
+
+ private data class Holder(
+ val component: LauncherAppComponent,
+ private val filter: LayoutInflater.Filter?,
+ ) : LayoutInflater.Filter {
+
+ override fun onLoadClass(clazz: Class<*>?) = filter?.onLoadClass(clazz) ?: true
+ }
+}
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index 29fc613..4aa3673 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -119,6 +119,9 @@
initialDragViewScale,
dragViewScaleOnDrop,
scalePx);
+ // During a drag, we don't want to expose the descendendants of drag view to a11y users,
+ // since those decendents are not a valid position in the workspace.
+ dragView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
dragView.setItemInfo(dragInfo);
mDragObject.dragComplete = false;
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 8368256..ed4f492 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -56,6 +56,7 @@
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.ToLongFunction;
import java.util.stream.Collectors;
@@ -79,8 +80,8 @@
private final Context mContext;
private final ToLongFunction<UserHandle> mUserSerialProvider;
private final Runnable mOnEmptyDbCreateCallback;
+ private final AtomicInteger mMaxItemId = new AtomicInteger(-1);
- private int mMaxItemId = -1;
public boolean mHotseatRestoreTableExists;
/**
@@ -97,21 +98,19 @@
protected void initIds() {
// In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
// the DB here
- if (mMaxItemId == -1) {
- mMaxItemId = initializeMaxItemId(getWritableDatabase());
- }
+ mMaxItemId.compareAndSet(-1, initializeMaxItemId(getWritableDatabase()));
}
@Override
public void onCreate(SQLiteDatabase db) {
if (LOGD) Log.d(TAG, "creating new launcher database");
- mMaxItemId = 1;
+ mMaxItemId.set(1);
addTableToDb(db, getDefaultUserSerial(), false /* optional */);
// Fresh and clean launcher DB.
- mMaxItemId = initializeMaxItemId(db);
+ mMaxItemId.set(initializeMaxItemId(db));
mOnEmptyDbCreateCallback.run();
}
@@ -451,11 +450,10 @@
// after that point
@Override
public int generateNewItemId() {
- if (mMaxItemId < 0) {
+ if (mMaxItemId.get() < 0) {
throw new RuntimeException("Error: max item id was not initialized");
}
- mMaxItemId += 1;
- return mMaxItemId;
+ return mMaxItemId.incrementAndGet();
}
/**
@@ -484,7 +482,7 @@
public void checkId(ContentValues values) {
int id = values.getAsInteger(Favorites._ID);
- mMaxItemId = Math.max(id, mMaxItemId);
+ mMaxItemId.accumulateAndGet(id, Math::max);
}
private int initializeMaxItemId(SQLiteDatabase db) {
@@ -508,7 +506,7 @@
int count = loader.loadLayout(db);
// Ensure that the max ids are initialized
- mMaxItemId = initializeMaxItemId(db);
+ mMaxItemId.set(initializeMaxItemId(db));
return count;
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationDBController.java b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
index 617cac7..bfa00bd 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationDBController.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
@@ -17,12 +17,14 @@
package com.android.launcher3.model;
import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.Flags.oneGridSpecs;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
+import static com.android.launcher3.provider.LauncherDbUtils.shiftTableByXCells;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -130,6 +132,20 @@
// Only use this strategy when comparing the previous grid to the new grid and the
// columns are the same and the destination has more rows
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
+
+ if (oneGridSpecs()) {
+ DbReader destReader = new DbReader(
+ target.getWritableDatabase(), TABLE_NAME, context);
+ boolean shouldShiftCells = shouldShiftCells(destReader, srcDeviceState.getRows());
+ if (shouldShiftCells) {
+ shiftTableByXCells(
+ target.getWritableDatabase(),
+ (destDeviceState.getRows() - srcDeviceState.getRows()),
+ TABLE_NAME);
+ }
+ }
+
+ // Save current configuration, so that the migration does not run again.
destDeviceState.writeToPrefs(context);
return true;
}
@@ -427,17 +443,22 @@
}
}
- static void copyCurrentGridToNewGrid(
- @NonNull Context context,
- @NonNull DeviceGridState destDeviceState,
- @NonNull DatabaseHelper target,
- @NonNull SQLiteDatabase source) {
- // Only use this strategy when comparing the previous grid to the new grid and the
- // columns are the same and the destination has more rows
- copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
- destDeviceState.writeToPrefs(context);
+ private static boolean shouldShiftCells(final DbReader destReader, final int srcGridRowCount) {
+ List<DbEntry> workspaceItems = destReader.loadAllWorkspaceEntries();
+ int firstPageItemsRowPosSum = workspaceItems.stream()
+ .filter(entry -> entry.screenId == 0)
+ .mapToInt(entry -> entry.cellY).sum();
+ int firstPageWorkspaceItemsCount = (int) workspaceItems.stream()
+ .filter(entry -> entry.screenId == 0).count();
+ if (firstPageWorkspaceItemsCount == 0) {
+ return false;
+ }
+ float srcGridMidPoint = srcGridRowCount / 2f;
+ float firstPageItemPosAvg = (float) firstPageItemsRowPosSum / firstPageWorkspaceItemsCount;
+ return (firstPageItemPosAvg >= srcGridMidPoint);
}
+
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public static class DbReader {
diff --git a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
index c856d4b..3f52d8a 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
+++ b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
@@ -21,15 +21,20 @@
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.launcher3.Flags
+import com.android.launcher3.Flags.oneGridSpecs
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.get
import com.android.launcher3.LauncherPrefs.Companion.getPrefs
import com.android.launcher3.LauncherSettings
+import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
+import com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.model.GridSizeMigrationDBController.DbReader
-import com.android.launcher3.provider.LauncherDbUtils
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction
+import com.android.launcher3.provider.LauncherDbUtils.copyTable
+import com.android.launcher3.provider.LauncherDbUtils.dropTable
+import com.android.launcher3.provider.LauncherDbUtils.shiftTableByXCells
import com.android.launcher3.util.CellAndSpan
import com.android.launcher3.util.GridOccupancy
import com.android.launcher3.util.IntArray
@@ -59,27 +64,30 @@
// amount of rows we simply copy over the source grid to the destination grid, rather
// than undergoing the general grid migration.
if (shouldMigrateToStrictlyTallerGrid(isDestNewDb, srcDeviceState, destDeviceState)) {
- GridSizeMigrationDBController.copyCurrentGridToNewGrid(
- context,
- destDeviceState,
- target,
- source,
- )
+ copyTable(source, TABLE_NAME, target.writableDatabase, TABLE_NAME, context)
+ if (oneGridSpecs()) {
+ val destReader = DbReader(target.writableDatabase, TABLE_NAME, context)
+ val shouldShiftCells = shouldShiftCells(destReader, srcDeviceState.rows)
+ if (shouldShiftCells) {
+ shiftTableByXCells(
+ target.writableDatabase,
+ (destDeviceState.rows - srcDeviceState.rows),
+ TABLE_NAME,
+ )
+ }
+ }
+ // Save current configuration, so that the migration does not run again.
+ destDeviceState.writeToPrefs(context)
return
}
- LauncherDbUtils.copyTable(
- source,
- LauncherSettings.Favorites.TABLE_NAME,
- target.writableDatabase,
- LauncherSettings.Favorites.TMP_TABLE,
- context,
- )
+
+ copyTable(source, TABLE_NAME, target.writableDatabase, TMP_TABLE, context)
val migrationStartTime = System.currentTimeMillis()
try {
SQLiteTransaction(target.writableDatabase).use { t ->
- val srcReader = DbReader(t.db, LauncherSettings.Favorites.TMP_TABLE, context)
- val destReader = DbReader(t.db, LauncherSettings.Favorites.TABLE_NAME, context)
+ val srcReader = DbReader(t.db, TMP_TABLE, context)
+ val destReader = DbReader(t.db, TABLE_NAME, context)
val targetSize = Point(destDeviceState.columns, destDeviceState.rows)
@@ -95,7 +103,7 @@
// Migrate workspace.
migrateWorkspace(srcReader, destReader, target, targetSize, idsInUse)
- LauncherDbUtils.dropTable(t.db, LauncherSettings.Favorites.TMP_TABLE)
+ dropTable(t.db, TMP_TABLE)
t.commit()
}
} catch (e: Exception) {
@@ -112,6 +120,19 @@
}
}
+ private fun shouldShiftCells(destReader: DbReader, srcGridRowCount: Int): Boolean {
+ val workspaceItems = destReader.loadAllWorkspaceEntries()
+ val firstPageItemsRowPosSum =
+ workspaceItems.sumOf { entry -> if (entry.screenId == 0) entry.cellY else 0 }
+ val firstPageWorkspaceItemsCount = workspaceItems.count { entry -> entry.screenId == 0 }
+ if (firstPageWorkspaceItemsCount == 0) {
+ return false
+ }
+ val srcGridMidPoint = srcGridRowCount / 2f
+ val firstPageItemPosAvg = firstPageItemsRowPosSum / firstPageWorkspaceItemsCount.toFloat()
+ return (firstPageItemPosAvg >= srcGridMidPoint)
+ }
+
/** Handles hotseat migration. */
@VisibleForTesting
fun migrateHotseat(
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a830c96..83eace8 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -246,7 +246,7 @@
TraceHelper.INSTANCE.beginSection(TAG);
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
mIsRestoreFromBackup =
- (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
+ LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
LauncherRestoreEventLogger restoreEventLogger = null;
if (enableLauncherBrMetricsFixed()) {
restoreEventLogger = LauncherRestoreEventLogger.Companion
@@ -266,21 +266,21 @@
sanitizeFolders(mItemsDeleted);
sanitizeAppPairs();
sanitizeWidgetsShortcutsAndPackages();
- logASplit("sanitizeData");
+ logASplit("sanitizeData finished");
}
verifyNotStopped();
mLauncherBinder.bindWorkspace(true /* incrementBindId */, /* isBindSync= */ false);
- logASplit("bindWorkspace");
+ logASplit("bindWorkspace finished");
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
- logASplit("sendFirstScreenBroadcast");
+ logASplit("sendFirstScreenBroadcast finished");
// Take a break
waitForIdle();
- logASplit("step 1 complete");
+ logASplit("step 1 loading workspace complete");
verifyNotStopped();
// second step
@@ -291,11 +291,11 @@
} finally {
Trace.endSection();
}
- logASplit("loadAllApps");
+ logASplit("loadAllApps finished");
verifyNotStopped();
mLauncherBinder.bindAllApps();
- logASplit("bindAllApps");
+ logASplit("bindAllApps finished");
verifyNotStopped();
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
@@ -303,28 +303,28 @@
updateHandler.updateIcons(allActivityList,
LauncherActivityCachingLogic.INSTANCE,
mApp.getModel()::onPackageIconsUpdated);
- logASplit("update icon cache");
+ logASplit("update AllApps icon cache finished");
verifyNotStopped();
- logASplit("save shortcuts in icon cache");
+ logASplit("saving all shortcuts in icon cache");
updateHandler.updateIcons(allShortcuts, CacheableShortcutCachingLogic.INSTANCE,
mApp.getModel()::onPackageIconsUpdated);
// Take a break
waitForIdle();
- logASplit("step 2 complete");
+ logASplit("step 2 loading AllApps complete");
verifyNotStopped();
// third step
List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
- logASplit("loadDeepShortcuts");
+ logASplit("loadDeepShortcuts finished");
verifyNotStopped();
mLauncherBinder.bindDeepShortcuts();
- logASplit("bindDeepShortcuts");
+ logASplit("bindDeepShortcuts finished");
verifyNotStopped();
- logASplit("save deep shortcuts in icon cache");
+ logASplit("saving deep shortcuts in icon cache");
updateHandler.updateIcons(
convertShortcutsToCacheableShortcuts(allDeepShortcuts, allActivityList),
CacheableShortcutCachingLogic.INSTANCE,
@@ -332,7 +332,7 @@
// Take a break
waitForIdle();
- logASplit("step 3 complete");
+ logASplit("step 3 loading all shortcuts complete");
verifyNotStopped();
// fourth step
@@ -345,11 +345,11 @@
widgetsModel.updateWidgetFilters(mWidgetsFilterDataProvider);
}
List<CachedObject> allWidgetsList = widgetsModel.update(mApp, /*packageUser=*/null);
- logASplit("load widgets");
+ logASplit("load widgets finished");
verifyNotStopped();
mLauncherBinder.bindWidgets();
- logASplit("bindWidgets");
+ logASplit("bindWidgets finished");
verifyNotStopped();
LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
@@ -357,7 +357,7 @@
mLauncherBinder.bindSmartspaceWidget();
// Turn off pref.
prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(false));
- logASplit("bindSmartspaceWidget");
+ logASplit("bindSmartspaceWidget finished");
verifyNotStopped();
} else if (!enableSmartspaceAsAWidget() && WIDGET_ON_FIRST_SCREEN
&& !prefs.get(LauncherPrefs.SHOULD_SHOW_SMARTSPACE)) {
@@ -365,10 +365,10 @@
prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(true));
}
+ logASplit("saving all widgets in icon cache");
updateHandler.updateIcons(allWidgetsList,
CachedObjectCachingLogic.INSTANCE,
mApp.getModel()::onWidgetLabelsUpdated);
- logASplit("save widgets in icon cache");
// fifth step
loadFolderNames();
@@ -414,7 +414,7 @@
} finally {
Trace.endSection();
}
- logASplit("loadWorkspace");
+ logASplit("loadWorkspace finished");
mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
&& (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(
@@ -440,7 +440,7 @@
} else {
dbController.tryMigrateDB(restoreEventLogger);
}
- Log.d(TAG, "loadWorkspace: loading default favorites");
+ Log.d(TAG, "loadWorkspace: loading default favorites if necessary");
dbController.loadDefaultFavoritesIfNecessary();
synchronized (mBgDataModel) {
@@ -453,7 +453,7 @@
mInstallingPkgsCached = installingPkgs;
}
installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
- FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
+ FileLog.d(TAG, "loadWorkspace: Packages with active install/update sessions: "
+ installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
@@ -478,8 +478,12 @@
widgetInflater, mPmHelper, iconRequestInfos, unlockedUsers,
allDeepShortcuts);
- while (!mStopped && c.moveToNext()) {
- itemProcessor.processItem();
+ if (mStopped) {
+ Log.w(TAG, "loadWorkspaceImpl: Loader stopped, skipping item processing");
+ } else {
+ while (!mStopped && c.moveToNext()) {
+ itemProcessor.processItem();
+ }
}
tryLoadWorkspaceIconsInBulk(iconRequestInfos);
} finally {
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index 856c294..b9c928c 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -33,7 +33,6 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.Flags;
-import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.PackageUserKey;
import java.lang.ref.WeakReference;
@@ -79,7 +78,7 @@
}
SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
if (sessionInfo != null) {
- FileLog.d(TAG, "onCreated: Install session created for"
+ Log.d(TAG, "onCreated: Install session created for"
+ " appPackageName=" + sessionInfo.getAppPackageName()
+ ", sessionId=" + sessionInfo.getSessionId()
+ ", appIcon=" + sessionInfo.getAppIcon()
@@ -111,7 +110,7 @@
activeSessions.remove(sessionId);
if (key != null && key.mPackageName != null) {
- FileLog.d(TAG, "onFinished: active install session finished for"
+ Log.d(TAG, "onFinished: active install session finished for"
+ " appPackageName=" + key.mPackageName
+ ", sessionId=" + sessionId
+ ", success=" + success);
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.kt b/src/com/android/launcher3/provider/LauncherDbUtils.kt
index 3c68e46..6f1d0dd 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.kt
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.kt
@@ -131,6 +131,11 @@
}
}
+ @JvmStatic
+ fun shiftTableByXCells(db: SQLiteDatabase, x: Int, toTable: String) {
+ db.run { execSQL("UPDATE $toTable SET cellY = cellY + $x") }
+ }
+
/**
* Migrates the legacy shortcuts to deep shortcuts pinned under Launcher. Removes any invalid
* shortcut or any shortcut which requires some permission to launch
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 82229f8..e4c50f0 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -18,18 +18,23 @@
import android.content.Context
import android.util.Log
+import android.view.InflateException
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.VisibleForTesting.Companion.PROTECTED
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.android.launcher3.BubbleTextView
import com.android.launcher3.BuildConfig
import com.android.launcher3.allapps.BaseAllAppsAdapter
+import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.util.CancellableTask
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.ActivityContext.ActivityContextDelegate
+import java.lang.IllegalStateException
const val PREINFLATE_ICONS_ROW_COUNT = 4
const val EXTRA_ICONS_COUNT = 2
@@ -39,10 +44,11 @@
* [RecyclerView]. The view inflation will happen on background thread and inflated [ViewHolder]s
* will be added to [RecycledViewPool] on main thread.
*/
-class AllAppsRecyclerViewPool<T> : RecycledViewPool() {
+class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : ActivityContext {
var hasWorkProfile = false
- private var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
+ @VisibleForTesting(otherwise = PROTECTED)
+ var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
companion object {
private const val TAG = "AllAppsRecyclerViewPool"
@@ -53,7 +59,7 @@
/**
* Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
*/
- fun <T> preInflateAllAppsViewHolders(context: T) where T : Context, T : ActivityContext {
+ fun preInflateAllAppsViewHolders(context: T) {
val appsView = context.appsView ?: return
val activeRv: RecyclerView = appsView.activeRecyclerView ?: return
val preInflateCount = getPreinflateCount(context)
@@ -97,36 +103,65 @@
override fun getLayoutManager(): RecyclerView.LayoutManager? = null
}
+ preInflateAllAppsViewHolders(
+ adapter,
+ BaseAllAppsAdapter.VIEW_TYPE_ICON,
+ activeRv,
+ preInflateCount,
+ ) {
+ getPreinflateCount(context)
+ }
+ }
+
+ @VisibleForTesting(otherwise = PROTECTED)
+ fun preInflateAllAppsViewHolders(
+ adapter: RecyclerView.Adapter<*>,
+ viewType: Int,
+ activeRv: RecyclerView,
+ preInflationCount: Int,
+ preInflationCountProvider: () -> Int,
+ ) {
+ if (preInflationCount <= 0) {
+ return
+ }
mCancellableTask?.cancel()
var task: CancellableTask<List<ViewHolder>>? = null
task =
CancellableTask(
{
val list: ArrayList<ViewHolder> = ArrayList()
- for (i in 0 until preInflateCount) {
+ for (i in 0 until preInflationCount) {
if (task?.canceled == true) {
break
}
// If activeRv's layout manager has been reset to null on main thread, skip
// the preinflation as we cannot generate correct LayoutParams
if (activeRv.layoutManager == null) {
+ list.clear()
break
}
- list.add(
- adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
- )
+ try {
+ list.add(adapter.createViewHolder(activeRv, viewType))
+ } catch (e: InflateException) {
+ list.clear()
+ // It's still possible for UI thread to set activeRv's layout manager to
+ // null and we should break the loop and cancel the preinflation.
+ break
+ }
}
list
},
MAIN_EXECUTOR,
{ viewHolders ->
- for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
+ // Run preInflationCountProvider again as the needed VH might have changed
+ val newPreInflationCount = preInflationCountProvider.invoke()
+ for (i in 0 until minOf(viewHolders.size, newPreInflationCount)) {
putRecycledView(viewHolders[i])
}
},
)
mCancellableTask = task
- VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
+ VIEW_PREINFLATION_EXECUTOR.execute(mCancellableTask)
}
/**
@@ -143,10 +178,11 @@
* app icons plus [EXTRA_ICONS_COUNT] is the magic minimal count of app icons to preinflate to
* suffice fast scrolling.
*
- * Note that we need to preinfate extra app icons in size of one all apps pages, so that opening
- * all apps don't need to inflate app icons.
+ * Note that if [FeatureFlags.ALL_APPS_GONE_VISIBILITY] is enabled, we need to preinfate extra
+ * app icons in size of one all apps pages, so that opening all apps don't need to inflate app
+ * icons.
*/
- fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
+ fun getPreinflateCount(context: T): Int {
var targetPreinflateCount =
PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
EXTRA_ICONS_COUNT
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 5851f62..5068b48 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE;
import static com.android.launcher3.BuildConfig.IS_STUDIO_BUILD;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import android.app.Activity;
@@ -52,6 +53,7 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.Flags;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherFiles;
import com.android.launcher3.R;
import com.android.launcher3.states.RotationHelper;
@@ -310,7 +312,10 @@
}
return mDeveloperOptionsEnabled;
case FIXED_LANDSCAPE_MODE:
- if (!Flags.oneGridSpecs()) {
+ if (!Flags.oneGridSpecs()
+ // adding this condition until fixing b/378972567
+ || InvariantDeviceProfile.INSTANCE.get(getContext()).deviceType
+ == TYPE_MULTI_DISPLAY) {
return false;
}
// When the setting changes rotate the screen accordingly to showcase the result
diff --git a/src/com/android/launcher3/util/ContextTracker.java b/src/com/android/launcher3/util/ContextTracker.java
index c729b4b..3201bd1 100644
--- a/src/com/android/launcher3/util/ContextTracker.java
+++ b/src/com/android/launcher3/util/ContextTracker.java
@@ -35,7 +35,7 @@
private static final String TAG = "ContextTracker";
private WeakReference<CONTEXT> mCurrentContext = new WeakReference<>(null);
- private CopyOnWriteArrayList<SchedulerCallback<CONTEXT>> mCallbacks =
+ private final CopyOnWriteArrayList<SchedulerCallback<CONTEXT>> mCallbacks =
new CopyOnWriteArrayList<>();
@Nullable
@@ -81,7 +81,7 @@
public boolean handleCreate(CONTEXT context) {
mCurrentContext = new WeakReference<>(context);
- return handleCreate(context, /* alreadyOnHome= */ false);
+ return handleCreate(context, isHomeStarted(context));
}
public boolean handleNewIntent(CONTEXT context) {
diff --git a/src/com/android/launcher3/util/DaggerSingletonObject.java b/src/com/android/launcher3/util/DaggerSingletonObject.java
index febe6af..a245761 100644
--- a/src/com/android/launcher3/util/DaggerSingletonObject.java
+++ b/src/com/android/launcher3/util/DaggerSingletonObject.java
@@ -18,8 +18,8 @@
import android.content.Context;
-import com.android.launcher3.LauncherApplication;
import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherComponentProvider;
import java.util.function.Function;
@@ -37,8 +37,6 @@
}
public T get(Context context) {
- LauncherAppComponent component =
- ((LauncherApplication) context.getApplicationContext()).getAppComponent();
- return mFunction.apply(component);
+ return mFunction.apply(LauncherComponentProvider.get(context));
}
}
diff --git a/src/com/android/launcher3/util/MSDLPlayerWrapper.java b/src/com/android/launcher3/util/MSDLPlayerWrapper.java
index 1e53ac1..eccccc7 100644
--- a/src/com/android/launcher3/util/MSDLPlayerWrapper.java
+++ b/src/com/android/launcher3/util/MSDLPlayerWrapper.java
@@ -28,6 +28,10 @@
import com.google.android.msdl.data.model.MSDLToken;
import com.google.android.msdl.domain.InteractionProperties;
import com.google.android.msdl.domain.MSDLPlayer;
+import com.google.android.msdl.logging.MSDLEvent;
+
+import java.io.PrintWriter;
+import java.util.List;
import javax.inject.Inject;
@@ -58,4 +62,17 @@
public void playToken(MSDLToken token) {
mMSDLPlayer.playToken(token, null);
}
+
+ public List<MSDLEvent> getHistory() {
+ return mMSDLPlayer.getHistory();
+ }
+
+ /** Print the latest history of MSDL tokens played */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "MSDLPlayerWrapper history of latest events:");
+ List<MSDLEvent> events = getHistory();
+ for (MSDLEvent event: events) {
+ writer.println(prefix + "\t" + event);
+ }
+ }
}
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index f457e4e..44a7c6f 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -73,7 +73,27 @@
*/
public static final int STAGE_TYPE_SIDE = 1;
- @IntDef({STAGE_TYPE_UNDEFINED, STAGE_TYPE_MAIN, STAGE_TYPE_SIDE})
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ public static final int STAGE_TYPE_A = 2;
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ public static final int STAGE_TYPE_B = 3;
+ /**
+ * Position independent stage identifier for a given Stage
+ */
+ public static final int STAGE_TYPE_C = 4;
+
+ @IntDef({
+ STAGE_TYPE_UNDEFINED,
+ STAGE_TYPE_MAIN,
+ STAGE_TYPE_SIDE,
+ STAGE_TYPE_A,
+ STAGE_TYPE_B,
+ STAGE_TYPE_C
+ })
public @interface StageType {}
///////////////////////////////////
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index ef66ffe..392d9a7 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -102,6 +102,9 @@
@Override
public void onDraw(Canvas canvas) {
+ if (shouldDrawAppContrastTile()) {
+ drawAppContrastTile(canvas);
+ }
// If text is transparent or shadow alpha is 0, don't draw any shadow
if (skipDoubleShadow()) {
super.onDraw(canvas);
diff --git a/src/com/android/launcher3/views/StickyHeaderLayout.java b/src/com/android/launcher3/views/StickyHeaderLayout.java
index 090251f..4142e1f 100644
--- a/src/com/android/launcher3/views/StickyHeaderLayout.java
+++ b/src/com/android/launcher3/views/StickyHeaderLayout.java
@@ -120,7 +120,19 @@
}
private float getCurrentScroll() {
- return mScrollOffset + (mCurrentEmptySpaceView == null ? 0 : mCurrentEmptySpaceView.getY());
+ float scroll;
+ if (mCurrentRecyclerView.getVisibility() != VISIBLE) {
+ // When no list is displayed, assume no scroll.
+ scroll = 0f;
+ } else if (mCurrentEmptySpaceView != null) {
+ // Otherwise use empty space view as reference to position.
+ scroll = mCurrentEmptySpaceView.getY();
+ } else {
+ // If there is no empty space view, but the list is visible, we are scrolled away
+ // completely, so assume all non-sticky children should also be scrolled away.
+ scroll = -mHeaderHeight;
+ }
+ return mScrollOffset + scroll;
}
@Override
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 1c0d94c..fda5175 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
+import static com.android.window.flags.Flags.predictiveBackThreeButtonNav;
import android.content.Context;
import android.graphics.Canvas;
@@ -128,6 +129,17 @@
}
@Override
+ public void setScaleY(float scaleY) {
+ super.setScaleY(scaleY);
+ if (predictiveBackThreeButtonNav() && mNavBarScrimHeight > 0) {
+ // Call invalidate to prevent navbar scrim from scaling. The navbar scrim is drawn
+ // directly onto the canvas. To prevent it from being scaled with the canvas, there's a
+ // counter scale applied in dispatchDraw.
+ invalidate();
+ }
+ }
+
+ @Override
public final void onClick(View v) {
WidgetCell wc;
if (v instanceof WidgetCell view) {
@@ -318,8 +330,10 @@
super.dispatchDraw(canvas);
if (mNavBarScrimHeight > 0) {
- canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
- mNavBarScrimPaint);
+ float left = (getWidth() - getWidth() / getScaleX()) / 2;
+ float top = getHeight() / 2f + (getHeight() / 2f - mNavBarScrimHeight) / getScaleY();
+ canvas.drawRect(left, top, getWidth() / getScaleX(),
+ top + mNavBarScrimHeight / getScaleY(), mNavBarScrimPaint);
}
}
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
index e190dc3..2c07fd9 100644
--- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -16,7 +16,7 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Flags.enforceSystemRadiusForAppWidgets;
+import static com.android.launcher3.Flags.useSystemRadiusForAppWidgets;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
@@ -99,7 +99,7 @@
public static float computeEnforcedRadius(@NonNull Context context) {
Resources res = context.getResources();
float systemRadius = res.getDimension(android.R.dimen.system_app_widget_background_radius);
- if (enforceSystemRadiusForAppWidgets()) {
+ if (useSystemRadiusForAppWidgets()) {
return systemRadius;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 2f64ab1..150806a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -295,8 +295,11 @@
}
private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
- recyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
if (mCurrentWidgetsRecyclerView != recyclerView) {
+ // Bind scrollbar if changing the recycler view. If widgets list updates, since
+ // scrollbar is already attached to the recycler view, it will automatically adjust as
+ // needed with recycler view's onScrollListener.
+ recyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
// Only reset the scroll position & expanded apps if the currently shown recycler view
// has been updated.
reset();
@@ -605,9 +608,12 @@
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
mAdapters.get(getCurrentAdapterHolderType()).mWidgetsRecyclerView.setVisibility(
VISIBLE);
- // Visibility of recommended widgets, recycler views and headers are handled in methods
- // below.
- post(this::onRecommendedWidgetsBound);
+ if (mRecommendedWidgetsCount > 0) {
+ // Display recommendations immediately, if present, so that other parts of sticky
+ // header (e.g. personal / work tabs) don't flash in interim.
+ mWidgetRecommendationsContainer.setVisibility(VISIBLE);
+ }
+ // Visibility of recycler views and headers are handled in methods below.
onWidgetsBound();
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 3c67538..74a9a5c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -103,7 +103,7 @@
.equals(mWidgetsContentVisiblePackageUserKey);
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@Nullable private RecyclerView mRecyclerView;
- @Nullable private PackageUserKey mPendingClickHeader;
+ @Nullable private PackageUserKey mHeaderPositionToMaintain;
@Px private int mMaxHorizontalSpan;
private boolean mShowOnlyDefaultList = true;
@@ -215,7 +215,7 @@
// Get the current top of the header with the matching key before adjusting the visible
// entries.
OptionalInt previousPositionForPackageUserKey =
- getPositionForPackageUserKey(mPendingClickHeader);
+ getPositionForPackageUserKey(mHeaderPositionToMaintain);
OptionalInt topForPackageUserKey =
getOffsetForPosition(previousPositionForPackageUserKey);
@@ -247,13 +247,15 @@
mVisibleEntries.addAll(newVisibleEntries);
diffResult.dispatchUpdatesTo(this);
- if (mPendingClickHeader != null) {
+ if (mHeaderPositionToMaintain != null && mRecyclerView != null) {
// Get the position for the clicked header after adjusting the visible entries. The
// position may have changed if another header had previously been expanded.
OptionalInt positionForPackageUserKey =
- getPositionForPackageUserKey(mPendingClickHeader);
- scrollToPositionAndMaintainOffset(positionForPackageUserKey, topForPackageUserKey);
- mPendingClickHeader = null;
+ getPositionForPackageUserKey(mHeaderPositionToMaintain);
+ // Post scroll updates to be applied after diff updates.
+ mRecyclerView.post(() -> scrollToPositionAndMaintainOffset(positionForPackageUserKey,
+ topForPackageUserKey));
+ mHeaderPositionToMaintain = null;
}
}
@@ -384,7 +386,7 @@
// Store the header that was clicked so that its position will be maintained the next time
// we update the entries.
- mPendingClickHeader = packageUserKey;
+ mHeaderPositionToMaintain = packageUserKey;
updateVisibleEntries();
@@ -470,6 +472,16 @@
*/
public void useExpandedList() {
mShowOnlyDefaultList = false;
+ if (mWidgetsContentVisiblePackageUserKey != null) {
+ // Maintain selected header for the next update that expands the list.
+ mHeaderPositionToMaintain = mWidgetsContentVisiblePackageUserKey;
+ } else if (mVisibleEntries.size() > 2) {
+ // Maintain last visible header shown above expand button since there was no selected
+ // header.
+ mHeaderPositionToMaintain = PackageUserKey.fromPackageItemInfo(
+ mVisibleEntries.get(mVisibleEntries.size() - 2).mPkgItem);
+ }
+
}
/** Comparator for sorting WidgetListRowEntry based on package title. */
diff --git a/tests/Android.bp b/tests/Android.bp
index 35a2275..e4fecc5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -63,7 +63,6 @@
"src/com/android/launcher3/dragging/TaplDragTest.java",
"src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java",
"src/com/android/launcher3/ui/TaplTestsLauncher3Test.java",
- "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
"src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
],
}
@@ -173,6 +172,7 @@
"multivalentTests/src/**/*.java",
"multivalentTests/src/**/*.kt",
"src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+ "src/com/android/launcher3/ui/BaseLauncherTaplTest.java",
"tapl/com/android/launcher3/tapl/*.java",
"tapl/com/android/launcher3/tapl/*.kt",
],
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 1ddd453..68e493d 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -183,6 +183,7 @@
</activity>
<activity-alias android:name="Activity2"
android:label="TestActivity2"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -192,6 +193,7 @@
</activity-alias>
<activity-alias android:name="Activity3"
android:label="TestActivity3"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -201,6 +203,7 @@
</activity-alias>
<activity-alias android:name="Activity4"
android:label="TestActivity4"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -210,6 +213,7 @@
</activity-alias>
<activity-alias android:name="Activity5"
android:label="TestActivity5"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -219,6 +223,7 @@
</activity-alias>
<activity-alias android:name="Activity6"
android:label="TestActivity6"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -228,6 +233,7 @@
</activity-alias>
<activity-alias android:name="Activity7"
android:label="TestActivity7"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -237,6 +243,7 @@
</activity-alias>
<activity-alias android:name="Activity8"
android:label="TestActivity8"
+ android:icon="@drawable/test_icon"
android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
@@ -246,6 +253,7 @@
</activity-alias>
<activity-alias android:name="Activity9" android:exported="true"
android:label="TestActivity9"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -254,6 +262,7 @@
</activity-alias>
<activity-alias android:name="Activity10" android:exported="true"
android:label="TestActivity10"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -262,6 +271,7 @@
</activity-alias>
<activity-alias android:name="Activity11" android:exported="true"
android:label="TestActivity11"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -270,6 +280,7 @@
</activity-alias>
<activity-alias android:name="Activity12" android:exported="true"
android:label="TestActivity12"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -278,6 +289,7 @@
</activity-alias>
<activity-alias android:name="Activity13" android:exported="true"
android:label="TestActivity13"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -286,6 +298,7 @@
</activity-alias>
<activity-alias android:name="Activity14" android:exported="true"
android:label="TestActivity14"
+ android:icon="@drawable/test_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -363,7 +376,7 @@
</activity>
<activity android:name="com.android.launcher3.testcomponent.ImeTestActivity"
android:label="ImeTestActivity"
- android:icon="@drawable/test_theme_icon"
+ android:icon="@drawable/test_icon"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tests/assets/ReorderWidgets/push_reorder_case b/tests/assets/ReorderWidgets/push_reorder_case
index 1eacfae..73b67d0 100644
--- a/tests/assets/ReorderWidgets/push_reorder_case
+++ b/tests/assets/ReorderWidgets/push_reorder_case
@@ -39,6 +39,6 @@
board: 6x5
xxxxxx
bbbb--
---m---
---aaa-
---ddd-
\ No newline at end of file
+--maaa
+--ddd-
+------
\ No newline at end of file
diff --git a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index f8794f8..c4519eb 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -168,7 +168,6 @@
isLandscape: Boolean = false,
isGestureMode: Boolean = true,
isFolded: Boolean = false,
- isFixedLandscape: Boolean = false,
) {
val (unfoldedNaturalX, unfoldedNaturalY) = deviceSpecUnfolded.naturalSize
val unfoldedWindowsBounds =
@@ -195,7 +194,6 @@
rotation = if (isLandscape) Surface.ROTATION_90 else Surface.ROTATION_0,
isGestureMode = isGestureMode,
densityDpi = deviceSpecFolded.densityDpi,
- isFixedLandscape = isFixedLandscape,
)
} else {
initializeCommonVars(
@@ -204,7 +202,6 @@
rotation = if (isLandscape) Surface.ROTATION_0 else Surface.ROTATION_90,
isGestureMode = isGestureMode,
densityDpi = deviceSpecUnfolded.densityDpi,
- isFixedLandscape = isFixedLandscape,
)
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/DeleteDropTargetTest.kt b/tests/multivalentTests/src/com/android/launcher3/DeleteDropTargetTest.kt
index 46e66e4..42374a5 100644
--- a/tests/multivalentTests/src/com/android/launcher3/DeleteDropTargetTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/DeleteDropTargetTest.kt
@@ -1,20 +1,29 @@
package com.android.launcher3
import android.content.Context
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.Utilities.*
+import com.android.launcher3.dragndrop.DragView
import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.MSDLPlayerWrapper
+import com.google.android.msdl.data.model.MSDLToken
import com.google.common.truth.Truth.assertThat
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
@SmallTest
@RunWith(AndroidJUnit4::class)
class DeleteDropTargetTest {
+ @get:Rule val mSetFlagsRule = SetFlagsRule()
+
private var mContext: Context = ActivityContextWrapper(getApplicationContext())
// Use a non-abstract class implementation
@@ -37,4 +46,17 @@
// A lot of space for text so the text should not be clipped
assertThat(buttonDropTarget.isTextClippedVertically(1000)).isFalse()
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun onDragEnter_performsMSDLSwipeThresholdFeedback() {
+ val target = DropTarget.DragObject(mContext)
+ target.dragView = mock<DragView<*>>()
+ buttonDropTarget.onDragEnter(target)
+ val wrapper = MSDLPlayerWrapper.INSTANCE.get(mContext)
+
+ val history = wrapper.history
+ assertThat(history.size).isEqualTo(1)
+ assertThat(history[0].tokenName).isEqualTo(MSDLToken.SWIPE_THRESHOLD_INDICATOR.name)
+ }
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/dagger/LauncherComponentProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/dagger/LauncherComponentProviderTest.kt
new file mode 100644
index 0000000..9255877
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/dagger/LauncherComponentProviderTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dagger
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.view.ContextThemeWrapper
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.R
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
+import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertSame
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LauncherComponentProviderTest {
+
+ val app: Context = ApplicationProvider.getApplicationContext()
+
+ @Test
+ fun `returns same component as Launcher application`() {
+ val c = SandboxModelContext()
+ assertSame(c.appComponent, LauncherComponentProvider.get(c))
+ assertNotSame(LauncherComponentProvider.get(c), LauncherComponentProvider.get(app))
+ }
+
+ @Test
+ fun `returns same component for isolated context`() {
+ val c = IsolatedContext()
+
+ // Same component is returned for multiple calls, irrespective of the wrappers
+ assertNotNull(LauncherComponentProvider.get(c))
+ assertSame(
+ LauncherComponentProvider.get(c),
+ LauncherComponentProvider.get(ContextThemeWrapper(c, R.style.LauncherTheme)),
+ )
+
+ // Different than main application
+ assertNotSame(LauncherComponentProvider.get(c), LauncherComponentProvider.get(app))
+ }
+
+ @Test
+ fun `different components for different isolated context`() {
+ val c1 = IsolatedContext()
+ val c2 = IsolatedContext()
+
+ assertNotNull(LauncherComponentProvider.get(c1))
+ assertNotNull(LauncherComponentProvider.get(c2))
+ assertNotSame(LauncherComponentProvider.get(c1), LauncherComponentProvider.get(c2))
+ }
+
+ inner class IsolatedContext : ContextWrapper(app.createPackageContext(TEST_PACKAGE, 0)) {
+
+ override fun getApplicationContext(): Context = this
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
index ce00b28..9b4bd71 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
@@ -71,6 +71,7 @@
import com.google.common.truth.Truth;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -99,6 +100,11 @@
new LauncherIconProvider(mContext));
}
+ @After
+ public void tearDown() {
+ mIconCache.close();
+ }
+
@Test
public void getShortcutInfoBadge_nullComponent_overrideAllowed() throws Exception {
String overridePackage = "com.android.settings";
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
index c9ea421..09752b8 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/DatabaseHelperTest.kt
@@ -1,5 +1,6 @@
package com.android.launcher3.model
+import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -11,8 +12,10 @@
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
import java.util.function.ToLongFunction
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -24,6 +27,19 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class DatabaseHelperTest {
+ val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
+ // v30 - 21 columns
+ lateinit var db: SQLiteDatabase
+
+ @Before
+ fun setUp() {
+ db = FactitiousDbController(context, INSERTION_SQL).inMemoryDb
+ }
+
+ @After
+ fun tearDown() {
+ db.close()
+ }
/**
* b/304687723 occurred when a return was accidentally added to a case statement in
@@ -33,13 +49,11 @@
*/
@Test
fun onUpgrade_to_version_32_from_30() {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
val userSerialProvider =
ToLongFunction<UserHandle> {
UserCache.INSTANCE.get(context).getSerialNumberForUser(it)
}
val dbHelper = DatabaseHelper(context, null, userSerialProvider) {}
- val db = FactitiousDbController(context, INSERTION_SQL).inMemoryDb
dbHelper.onUpgrade(db, 30, 32)
@@ -54,9 +68,6 @@
*/
@Test
fun after_migrating_from_db_v30_to_v32_copy_table() {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
- val db = FactitiousDbController(context, INSERTION_SQL).inMemoryDb // v30 - 21 columns
-
addTableToDb(db, 1, true, TMP_TABLE)
LauncherDbUtils.copyTable(db, TABLE_NAME, db, TMP_TABLE, context)
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 7cd5da4..e8f778f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -18,6 +18,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherAppState
+import com.android.launcher3.icons.BitmapInfo
import com.android.launcher3.icons.waitForUpdateHandlerToFinish
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.Executors
@@ -160,6 +161,9 @@
assertWithMessage("Index $index was not highRes")
.that(items[index].bitmap.isNullOrLowRes)
.isFalse()
+ assertWithMessage("Index $index was the default icon")
+ .that(isDefaultIcon(items[index].bitmap))
+ .isFalse()
}
}
@@ -168,9 +172,17 @@
assertWithMessage("Index $index was not lowRes")
.that(items[index].bitmap.isNullOrLowRes)
.isTrue()
+ assertWithMessage("Index $index was the default icon")
+ .that(isDefaultIcon(items[index].bitmap))
+ .isFalse()
}
}
+ private fun isDefaultIcon(bitmap: BitmapInfo) =
+ LauncherAppState.getInstance(modelHelper.sandboxContext)
+ .iconCache
+ .isDefaultIcon(bitmap, modelHelper.sandboxContext.user)
+
/** Recreate DeviceProfiles after changing InvariantDeviceProfile */
private fun recreateSupportedDeviceProfiles() {
LauncherAppState.getIDP(modelHelper.sandboxContext).supportedProfiles =
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
index 7933331..eee6191 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
@@ -82,6 +82,7 @@
@After
fun tearDown() {
+ db.close()
modelHelper.destroy()
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index b4945d7..63359ec 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -109,6 +109,7 @@
@After
public void tearDown() {
+ mCursor.close();
mModelHelper.destroy();
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index d0c168a..c30b730 100644
--- a/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -92,6 +92,7 @@
private Cursor mMockCursor;
private LauncherPrefs mPrefs;
private LauncherRestoreEventLogger mMockRestoreEventLogger;
+ private SQLiteDatabase mDb;
@Before
public void setup() {
@@ -107,57 +108,60 @@
@After
public void teardown() {
+ if (mDb != null) {
+ mDb.close();
+ }
mModelHelper.destroy();
LauncherPrefs.get(mContext).removeSync(RESTORE_DEVICE);
}
@Test
public void testGetProfileId() throws Exception {
- SQLiteDatabase db = new MyModelDbController(23).getDb();
- assertEquals(23, new RestoreDbTask().getDefaultProfileId(db));
+ mDb = new MyModelDbController(23).getDb();
+ assertEquals(23, new RestoreDbTask().getDefaultProfileId(mDb));
}
@Test
public void testMigrateProfileId() throws Exception {
- SQLiteDatabase db = new MyModelDbController(42).getDb();
+ mDb = new MyModelDbController(42).getDb();
// Add some mock data
for (int i = 0; i < 5; i++) {
ContentValues values = new ContentValues();
values.put(Favorites._ID, i);
values.put(Favorites.TITLE, "item " + i);
- db.insert(Favorites.TABLE_NAME, null, values);
+ mDb.insert(Favorites.TABLE_NAME, null, values);
}
// Verify item add
- assertEquals(5, getCount(db, "select * from favorites where profileId = 42"));
+ assertEquals(5, getCount(mDb, "select * from favorites where profileId = 42"));
- new RestoreDbTask().migrateProfileId(db, 42, 33);
+ new RestoreDbTask().migrateProfileId(mDb, 42, 33);
// verify data migrated
- assertEquals(0, getCount(db, "select * from favorites where profileId = 42"));
- assertEquals(5, getCount(db, "select * from favorites where profileId = 33"));
+ assertEquals(0, getCount(mDb, "select * from favorites where profileId = 42"));
+ assertEquals(5, getCount(mDb, "select * from favorites where profileId = 33"));
}
@Test
public void testChangeDefaultColumn() throws Exception {
- SQLiteDatabase db = new MyModelDbController(42).getDb();
+ mDb = new MyModelDbController(42).getDb();
// Add some mock data
for (int i = 0; i < 5; i++) {
ContentValues values = new ContentValues();
values.put(Favorites._ID, i);
values.put(Favorites.TITLE, "item " + i);
- db.insert(Favorites.TABLE_NAME, null, values);
+ mDb.insert(Favorites.TABLE_NAME, null, values);
}
// Verify default column is 42
- assertEquals(5, getCount(db, "select * from favorites where profileId = 42"));
+ assertEquals(5, getCount(mDb, "select * from favorites where profileId = 42"));
- new RestoreDbTask().changeDefaultColumn(db, 33);
+ new RestoreDbTask().changeDefaultColumn(mDb, 33);
// Verify default value changed
ContentValues values = new ContentValues();
values.put(Favorites._ID, 100);
values.put(Favorites.TITLE, "item 100");
- db.insert(Favorites.TABLE_NAME, null, values);
- assertEquals(1, getCount(db, "select * from favorites where profileId = 33"));
+ mDb.insert(Favorites.TABLE_NAME, null, values);
+ assertEquals(1, getCount(mDb, "select * from favorites where profileId = 33"));
}
@Test
@@ -170,7 +174,7 @@
long workProfileId_old = myProfileId + 3;
MyModelDbController controller = new MyModelDbController(myProfileId);
- SQLiteDatabase db = controller.getDb();
+ 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));
@@ -178,16 +182,16 @@
addIconsBulk(controller, 10, 1, myProfileId_old);
addIconsBulk(controller, 6, 2, workProfileId_old);
- assertEquals(10, getItemCountForProfile(db, myProfileId_old));
- assertEquals(6, getItemCountForProfile(db, workProfileId_old));
+ assertEquals(10, getItemCountForProfile(mDb, myProfileId_old));
+ assertEquals(6, getItemCountForProfile(mDb, workProfileId_old));
mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
// All the data has been migrated to the new user ids
- assertEquals(0, getItemCountForProfile(db, myProfileId_old));
- assertEquals(0, getItemCountForProfile(db, workProfileId_old));
- assertEquals(10, getItemCountForProfile(db, myProfileId));
- assertEquals(6, getItemCountForProfile(db, workProfileId));
+ assertEquals(0, getItemCountForProfile(mDb, myProfileId_old));
+ assertEquals(0, getItemCountForProfile(mDb, workProfileId_old));
+ assertEquals(10, getItemCountForProfile(mDb, myProfileId));
+ assertEquals(6, getItemCountForProfile(mDb, workProfileId));
}
@Test
@@ -199,7 +203,7 @@
long workProfileId_old = myProfileId + 3;
MyModelDbController controller = new MyModelDbController(myProfileId);
- SQLiteDatabase db = controller.getDb();
+ mDb = controller.getDb();
BackupManager bm = spy(new BackupManager(mContext));
doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old));
// Work profile is not migrated
@@ -207,16 +211,16 @@
addIconsBulk(controller, 10, 1, myProfileId_old);
addIconsBulk(controller, 6, 2, workProfileId_old);
- assertEquals(10, getItemCountForProfile(db, myProfileId_old));
- assertEquals(6, getItemCountForProfile(db, workProfileId_old));
+ assertEquals(10, getItemCountForProfile(mDb, myProfileId_old));
+ assertEquals(6, getItemCountForProfile(mDb, workProfileId_old));
mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
// All the data has been migrated to the new user ids
- assertEquals(0, getItemCountForProfile(db, myProfileId_old));
- assertEquals(0, getItemCountForProfile(db, workProfileId_old));
- assertEquals(10, getItemCountForProfile(db, myProfileId));
- assertEquals(10, getCount(db, "select * from favorites"));
+ assertEquals(0, getItemCountForProfile(mDb, myProfileId_old));
+ assertEquals(0, getItemCountForProfile(mDb, workProfileId_old));
+ assertEquals(10, getItemCountForProfile(mDb, myProfileId));
+ assertEquals(10, getCount(mDb, "select * from favorites"));
}
@Test
@@ -342,24 +346,24 @@
}
private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) {
- SQLiteDatabase db = new MyModelDbController(42).getDb();
+ mDb = new MyModelDbController(42).getDb();
// Add some mock data
for (int i = 0; i < screenIds.length; i++) {
ContentValues values = new ContentValues();
values.put(Favorites._ID, i);
values.put(Favorites.SCREEN, screenIds[i]);
values.put(Favorites.CONTAINER, CONTAINER_DESKTOP);
- db.insert(Favorites.TABLE_NAME, null, values);
+ mDb.insert(Favorites.TABLE_NAME, null, values);
}
// Verify items are added
assertEquals(screenIds.length,
- getCount(db, "select * from favorites where container = -100"));
+ getCount(mDb, "select * from favorites where container = -100"));
- new RestoreDbTask().removeScreenIdGaps(db);
+ new RestoreDbTask().removeScreenIdGaps(mDb);
// verify screenId gaps removed
int[] resultScreenIds = new int[screenIds.length];
- try (Cursor c = db.rawQuery(
+ try (Cursor c = mDb.rawQuery(
"select screen from favorites where container = -100 order by screen", null)) {
int i = 0;
while (c.moveToNext()) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt b/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
new file mode 100644
index 0000000..3afb0b5
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.recyclerview
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.LayoutManager
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.Executors
+import com.android.launcher3.views.ActivityContext
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AllAppsRecyclerViewPoolTest<T> where T : Context, T : ActivityContext {
+
+ private lateinit var underTest: AllAppsRecyclerViewPool<T>
+ private lateinit var adapter: RecyclerView.Adapter<*>
+
+ @Mock private lateinit var parent: RecyclerView
+ @Mock private lateinit var itemView: View
+ @Mock private lateinit var layoutManager: LayoutManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest = spy(AllAppsRecyclerViewPool())
+ adapter =
+ object : RecyclerView.Adapter<ViewHolder>() {
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ object : ViewHolder(itemView) {}
+
+ override fun getItemCount() = 0
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {}
+ }
+ underTest.setMaxRecycledViews(VIEW_TYPE, 20)
+ `when`(parent.layoutManager).thenReturn(layoutManager)
+ }
+
+ @Test
+ fun preinflate_success() {
+ underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }
+
+ awaitTasksCompleted()
+ assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(10)
+ }
+
+ @Test
+ fun preinflate_not_triggered() {
+ underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 0) { 0 }
+
+ awaitTasksCompleted()
+ assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
+ }
+
+ @Test
+ fun preinflate_cancel_before_runOnMainThread() {
+ underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }
+ assertThat(underTest.mCancellableTask!!.canceled).isFalse()
+
+ underTest.clear()
+
+ awaitTasksCompleted()
+ verify(underTest, never()).putRecycledView(any(ViewHolder::class.java))
+ assertThat(underTest.mCancellableTask!!.canceled).isTrue()
+ assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
+ }
+
+ @Test
+ fun preinflate_cancel_after_run() {
+ underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }
+ assertThat(underTest.mCancellableTask!!.canceled).isFalse()
+ awaitTasksCompleted()
+
+ underTest.clear()
+
+ verify(underTest, times(10)).putRecycledView(any(ViewHolder::class.java))
+ assertThat(underTest.mCancellableTask!!.canceled).isTrue()
+ assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
+ }
+
+ private fun awaitTasksCompleted() {
+ Executors.VIEW_PREINFLATION_EXECUTOR.submit<Any> { null }.get()
+ Executors.MAIN_EXECUTOR.submit<Any> { null }.get()
+ }
+
+ companion object {
+ private const val VIEW_TYPE: Int = 4
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
index 7484bce..ac5fda2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -26,6 +26,7 @@
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.Executors
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -38,7 +39,7 @@
@get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
private val providerName =
ComponentName(
- getInstrumentation().getContext().getPackageName(),
+ getInstrumentation().context.packageName,
"com.android.launcher3.testcomponent.AppWidgetNoConfig",
)
private val generatedPreviewLayout =
@@ -51,6 +52,7 @@
private lateinit var helper: WidgetManagerHelper
private lateinit var appWidgetProviderInfo: LauncherAppWidgetProviderInfo
private lateinit var widgetItem: WidgetItem
+ private lateinit var iconCache: IconCache
@Before
fun setup() {
@@ -88,17 +90,17 @@
createWidgetItem()
}
+ @After
+ fun tearDown() {
+ iconCache.close()
+ }
+
private fun createWidgetItem() {
Executors.MODEL_EXECUTOR.submit {
val idp = InvariantDeviceProfile()
- widgetItem =
- WidgetItem(
- appWidgetProviderInfo,
- idp,
- IconCache(context, idp, null, IconProvider(context)),
- context,
- helper,
- )
+ if (::iconCache.isInitialized) iconCache.close()
+ iconCache = IconCache(context, idp, null, IconProvider(context))
+ widgetItem = WidgetItem(appWidgetProviderInfo, idp, iconCache, context, helper)
}
.get()
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/RoundedCornerEnforcementTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/RoundedCornerEnforcementTest.kt
index c82e84c..13e23c9 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/RoundedCornerEnforcementTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/RoundedCornerEnforcementTest.kt
@@ -86,7 +86,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENFORCE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
+ @DisableFlags(Flags.FLAG_USE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
fun `Compute system radius when smaller`() {
val mockContext = mock(Context::class.java)
val mockRes = mock(Resources::class.java)
@@ -103,7 +103,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENFORCE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
+ @DisableFlags(Flags.FLAG_USE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
fun `Compute launcher radius when smaller`() {
val mockContext = mock(Context::class.java)
val mockRes = mock(Resources::class.java)
@@ -120,7 +120,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENFORCE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
+ @EnableFlags(Flags.FLAG_USE_SYSTEM_RADIUS_FOR_APP_WIDGETS)
fun `Compute system radius ignoring launcher radius`() {
val mockContext = mock(Context::class.java)
val mockRes = mock(Resources::class.java)
diff --git a/tests/res/drawable/test_icon.xml b/tests/res/drawable/test_icon.xml
new file mode 100644
index 0000000..72ebfeb
--- /dev/null
+++ b/tests/res/drawable/test_icon.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@android:color/white"/>
+ <foreground>
+ <color android:color="#FFFF0000" />
+ </foreground>
+ <monochrome>
+ <vector android:width="48dp" android:height="48dp" android:viewportWidth="48.0" android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0,24L48,24 48,48, 0,48 Z"/>
+ </vector>
+ </monochrome>
+</adaptive-icon>
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 59e1f99..e2f9feb9a 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -64,7 +64,6 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
- @ScreenRecordRule.ScreenRecord // b/353600888
public void testDragToFolder() {
// TODO: add the use case to drag an icon to an existing folder. Currently it either fails
// on tablets or phones due to difference in resolution.
@@ -97,7 +96,6 @@
* icon left.
*/
@Test
- @ScreenRecordRule.ScreenRecord // b/353600888
public void testDragOutOfFolder() {
final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
final HomeAppIcon photosIcon = createShortcutInCenterIfNotExist(PHOTOS_APP_NAME);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index a273648..8e4db5c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,75 +15,41 @@
*/
package com.android.launcher3.ui;
-import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
-
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.TestUtil.resolveSystemAppInfo;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Point;
-import android.os.Debug;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.platform.test.rule.LimitDevicesRule;
import android.system.OsConstants;
import android.util.Log;
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
-import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.tapl.HomeAllApps;
-import com.android.launcher3.tapl.HomeAppIcon;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
import com.android.launcher3.util.rule.FailureWatcher;
-import com.android.launcher3.util.rule.SamplerRule;
-import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.util.rule.TestIsolationRule;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.launcher3.util.rule.ViewCaptureRule;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@@ -93,169 +59,51 @@
/**
* Base class for all instrumentation tests providing various utility methods.
*/
-public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher> {
-
- public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 10;
+public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher>
+ extends BaseLauncherTaplTest {
private static final String TAG = "AbstractLauncherUiTest";
- private static final long BYTES_PER_MEGABYTE = 1 << 20;
-
- private static boolean sDumpWasGenerated = false;
- private static boolean sActivityLeakReported = false;
- private static boolean sSeenKeyguard = false;
- private static boolean sFirstTimeWaitingForWizard = true;
-
- private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
-
protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR;
- protected final UiDevice mDevice = getUiDevice();
- protected final LauncherInstrumentation mLauncher = createLauncherInstrumentation();
-
- @NonNull
- public static LauncherInstrumentation createLauncherInstrumentation() {
- waitForSetupWizardDismissal(); // precondition for creating LauncherInstrumentation
- return new LauncherInstrumentation(true);
- }
-
- protected Context mTargetContext;
- protected String mTargetPackage;
- private int mLauncherPid;
-
- private final ActivityManager.MemoryInfo mMemoryInfo = new ActivityManager.MemoryInfo();
- private final ActivityManager mActivityManager;
- private long mMemoryBefore;
-
- /** Detects activity leaks and throws an exception if a leak is found. */
- public static void checkDetectedLeaks(LauncherInstrumentation launcher) {
- checkDetectedLeaks(launcher, false);
- }
-
- /** Detects activity leaks and throws an exception if a leak is found. */
- public static void checkDetectedLeaks(LauncherInstrumentation launcher,
- boolean requireOneActiveActivityUnused) {
- if (TestStabilityRule.isPresubmit()) return; // b/313501215
-
- final boolean requireOneActiveActivity =
- false; // workaround for leaks when there is an unexpected Recents activity
-
- if (sActivityLeakReported) return;
-
- // Check whether activity leak detector has found leaked activities.
- Wait.atMost(() -> getActivityLeakErrorMessage(launcher, requireOneActiveActivity),
- () -> {
- launcher.forceGc();
- return MAIN_EXECUTOR.submit(
- () -> launcher.noLeakedActivities(requireOneActiveActivity)).get();
- }, launcher);
- }
-
- public static String getAppPackageName() {
- return getInstrumentation().getContext().getPackageName();
- }
-
- private static String getActivityLeakErrorMessage(LauncherInstrumentation launcher,
- boolean requireOneActiveActivity) {
- sActivityLeakReported = true;
- return "Activity leak detector has found leaked activities, requirining 1 activity: "
- + requireOneActiveActivity + "; "
- + dumpHprofData(launcher, false, requireOneActiveActivity) + ".";
- }
-
- private static String dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak,
- boolean requireOneActiveActivity) {
- if (intentionalLeak) return "intentional leak; not generating dump";
-
- String result;
- if (sDumpWasGenerated) {
- result = "dump has already been generated by another test";
- } else {
- try {
- final String fileName =
- getInstrumentation().getTargetContext().getFilesDir().getPath()
- + "/ActivityLeakHeapDump.hprof";
- if (TestHelpers.isInLauncherProcess()) {
- Debug.dumpHprofData(fileName);
- } else {
- final UiDevice device = getUiDevice();
- device.executeShellCommand(
- "am dumpheap " + device.getLauncherPackageName() + " " + fileName);
- }
- Log.d(TAG, "Saved leak dump, the leak is still present: "
- + !launcher.noLeakedActivities(requireOneActiveActivity));
- sDumpWasGenerated = true;
- result = "saved memory dump as an artifact";
- } catch (Throwable e) {
- Log.e(TAG, "dumpHprofData failed", e);
- result = "failed to save memory dump";
- }
- }
- return result + ". Full list of activities: " + launcher.getRootedActivitiesList();
- }
protected AbstractLauncherUiTest() {
- mActivityManager = InstrumentationRegistry.getContext()
- .getSystemService(ActivityManager.class);
- mLauncher.enableCheckEventsForSuccessfulGestures();
- mLauncher.setAnomalyChecker(AbstractLauncherUiTest::verifyKeyguardInvisible);
- try {
- mDevice.setOrientationNatural();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
.getString("result"));
}
- mLauncher.enableDebugTracing();
- // Avoid double-reporting of Launcher crashes.
- mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
}
- @Rule
- public ShellCommandRule mDisableHeadsUpNotification =
- ShellCommandRule.disableHeadsUpNotification();
-
- @Rule
- public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
-
- @Rule
- public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
-
- @Rule
- public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
-
- @Rule
- public LimitDevicesRule mlimitDevicesRule = new LimitDevicesRule();
-
+ /**
+ * @deprecated call {@link #performInitialization} instead
+ */
+ @Deprecated
public static void initialize(AbstractLauncherUiTest test) throws Exception {
- test.reinitializeLauncherData();
- test.mDevice.pressHome();
- test.waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
- test.waitForState("Launcher internal state didn't switch to Home",
- () -> LauncherState.NORMAL);
- test.waitForResumed("Launcher internal state is still Background");
+ test.performInitialization();
+ }
+
+ @Override
+ protected void performInitialization() {
+ reinitializeLauncherData();
+ mDevice.pressHome();
// Check that we switched to home.
- test.mLauncher.getWorkspace();
- AbstractLauncherUiTest.checkDetectedLeaks(test.mLauncher, true);
+ mLauncher.getWorkspace();
+
+ waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+ waitForState("Launcher internal state didn't switch to Home",
+ () -> LauncherState.NORMAL);
+ waitForResumed("Launcher internal state is still Background");
+
+ checkDetectedLeaks(mLauncher, true);
}
- protected void clearPackageData(String pkg) throws IOException, InterruptedException {
- assertTrue("pm clear command failed",
- mDevice.executeShellCommand("pm clear " + pkg)
- .contains("Success"));
- assertTrue("pm wait-for-handler command failed",
- mDevice.executeShellCommand("pm wait-for-handler")
- .contains("Success"));
- }
-
+ @Override
protected TestRule getRulesInsideActivityMonitor() {
final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
Launcher.ACTIVITY_TRACKER::getCreatedContext);
final RuleChain inner = RuleChain
- .outerRule(new PortraitLandscapeRunner<LAUNCHER_TYPE>(this))
+ .outerRule(new PortraitLandscapeRunner<>(this))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
// .around(viewCaptureRule) // b/315482167
.around(new TestIsolationRule(mLauncher, true));
@@ -265,175 +113,6 @@
: inner;
}
- @Rule
- public TestRule mOrderSensitiveRules = RuleChain
- .outerRule(new SamplerRule())
- .around(new TestStabilityRule())
- .around(getRulesInsideActivityMonitor());
-
- public UiDevice getDevice() {
- return mDevice;
- }
-
- @Before
- public void setUp() throws Exception {
- mLauncher.onTestStart();
-
- final String launcherPackageName = mDevice.getLauncherPackageName();
- try {
- final Context context = InstrumentationRegistry.getContext();
- final PackageManager pm = context.getPackageManager();
- final PackageInfo launcherPackage = pm.getPackageInfo(launcherPackageName, 0);
-
- if (!launcherPackage.versionName.equals("BuildFromAndroidStudio")) {
- Assert.assertEquals("Launcher version doesn't match tests version",
- pm.getPackageInfo(context.getPackageName(), 0).getLongVersionCode(),
- launcherPackage.getLongVersionCode());
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
-
- mLauncherPid = 0;
-
- mTargetContext = InstrumentationRegistry.getTargetContext();
- mTargetPackage = mTargetContext.getPackageName();
- mLauncherPid = mLauncher.getPid();
-
- UserManager userManager = mTargetContext.getSystemService(UserManager.class);
- if (userManager != null) {
- for (UserHandle userHandle : userManager.getUserProfiles()) {
- if (!userHandle.isSystem()) {
- mDevice.executeShellCommand(
- "pm remove-user --wait " + userHandle.getIdentifier());
- }
- }
- }
-
- onTestStart();
-
- initialize(this);
- }
-
- private long getAvailableMemory() {
- mActivityManager.getMemoryInfo(mMemoryInfo);
-
- return Math.divideExact(mMemoryInfo.availMem, BYTES_PER_MEGABYTE);
- }
-
- @Before
- public void saveMemoryBefore() {
- mMemoryBefore = getAvailableMemory();
- }
-
- @After
- public void logMemoryAfter() {
- long memoryAfter = getAvailableMemory();
-
- Log.d(TAG, "Available memory: before=" + mMemoryBefore
- + "MB, after=" + memoryAfter
- + "MB, delta=" + (memoryAfter - mMemoryBefore) + "MB");
- }
-
- /** Method that should be called when a test starts. */
- public static void onTestStart() {
- waitForSetupWizardDismissal();
-
- if (TestStabilityRule.isPresubmit()) {
- aggressivelyUnlockSysUi();
- } else {
- verifyKeyguardInvisible();
- }
- }
-
- private static boolean hasSystemUiObject(String resId) {
- return getUiDevice().hasObject(
- By.res(SYSTEMUI_PACKAGE, resId));
- }
-
- @NonNull
- private static UiDevice getUiDevice() {
- return UiDevice.getInstance(getInstrumentation());
- }
-
- private static void aggressivelyUnlockSysUi() {
- final UiDevice device = getUiDevice();
- for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
- Log.d(TAG, "Before attempting to unlock the phone");
- try {
- device.executeShellCommand("input keyevent 82");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- device.waitForIdle();
- }
- Assert.assertTrue("Keyguard still visible",
- TestHelpers.wait(
- Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
- Log.d(TAG, "Keyguard is not visible");
- }
-
- /** Waits for setup wizard to go away. */
- private static void waitForSetupWizardDismissal() {
- if (sFirstTimeWaitingForWizard) {
- try {
- getUiDevice().executeShellCommand(
- "am force-stop com.google.android.setupwizard");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- final boolean wizardDismissed = TestHelpers.wait(
- Until.gone(By.pkg("com.google.android.setupwizard").depth(0)),
- sFirstTimeWaitingForWizard ? 120000 : 0);
- sFirstTimeWaitingForWizard = false;
- Assert.assertTrue("Setup wizard is still visible", wizardDismissed);
- }
-
- /** Asserts that keyguard is not visible */
- public static void verifyKeyguardInvisible() {
- final boolean keyguardAlreadyVisible = sSeenKeyguard;
-
- sSeenKeyguard = sSeenKeyguard
- || !TestHelpers.wait(
- Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000);
-
- Assert.assertFalse(
- "Keyguard is visible, which is likely caused by a crash in SysUI, seeing keyguard"
- + " for the first time = "
- + !keyguardAlreadyVisible,
- sSeenKeyguard);
- }
-
- @After
- public void verifyLauncherState() {
- try {
- // Limits UI tests affecting tests running after them.
- mDevice.pressHome();
- mLauncher.waitForLauncherInitialized();
- if (mLauncherPid != 0) {
- assertEquals("Launcher crashed, pid mismatch:",
- mLauncherPid, mLauncher.getPid().intValue());
- }
- } finally {
- mLauncher.onTestFinish();
- }
- }
-
- protected void reinitializeLauncherData() {
- reinitializeLauncherData(false);
- }
-
- protected void reinitializeLauncherData(boolean clearWorkspace) {
- if (clearWorkspace) {
- mLauncher.clearLauncherData();
- } else {
- mLauncher.reinitializeLauncherData();
- }
- mLauncher.waitForLauncherInitialized();
- }
-
/**
* Runs the callback on the UI thread and returns the result.
*/
@@ -533,38 +212,6 @@
}, mLauncher, timeout);
}
- /**
- * Broadcast receiver which blocks until the result is received.
- */
- public class BlockingBroadcastReceiver extends BroadcastReceiver {
-
- private final CountDownLatch latch = new CountDownLatch(1);
- private Intent mIntent;
-
- public BlockingBroadcastReceiver(String action) {
- mTargetContext.registerReceiver(this, new IntentFilter(action),
- Context.RECEIVER_EXPORTED/*UNAUDITED*/);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- mIntent = intent;
- latch.countDown();
- }
-
- public Intent blockingGetIntent() throws InterruptedException {
- assertTrue("Timed Out", latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS));
- mTargetContext.unregisterReceiver(this);
- return mIntent;
- }
-
- public Intent blockingGetExtraIntent() throws InterruptedException {
- Intent intent = blockingGetIntent();
- return intent == null ? null : (Intent) intent.getParcelableExtra(
- Intent.EXTRA_INTENT);
- }
- }
-
public static void startAppFast(String packageName) {
startIntent(
getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage(
@@ -659,45 +306,4 @@
protected void onLauncherActivityClose(LAUNCHER_TYPE launcher) {
}
-
- protected HomeAppIcon createShortcutInCenterIfNotExist(String name) {
- Point dimension = mLauncher.getWorkspace().getIconGridDimensions();
- return createShortcutIfNotExist(name, dimension.x / 2, dimension.y / 2);
- }
-
- protected HomeAppIcon createShortcutIfNotExist(String name, Point cellPosition) {
- return createShortcutIfNotExist(name, cellPosition.x, cellPosition.y);
- }
-
- protected HomeAppIcon createShortcutIfNotExist(String name, int cellX, int cellY) {
- HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
- Log.d(ICON_MISSING, "homeAppIcon: " + homeAppIcon + " name: " + name +
- " cell: " + cellX + ", " + cellY);
- if (homeAppIcon == null) {
- HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
- allApps.freeze();
- try {
- allApps.getAppIcon(name).dragToWorkspace(cellX, cellY);
- } finally {
- allApps.unfreeze();
- }
- homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
- }
- return homeAppIcon;
- }
-
- protected void commitTransactionAndLoadHome(FavoriteItemsTransaction transaction) {
- transaction.commit();
-
- // Launch the home activity
- UiDevice.getInstance(getInstrumentation()).pressHome();
- mLauncher.waitForLauncherInitialized();
- }
-
- /** Clears all recent tasks */
- protected void clearAllRecentTasks() {
- if (!mLauncher.getRecentTasks().isEmpty()) {
- mLauncher.goHome().switchToOverview().dismissAllTasks();
- }
- }
}
diff --git a/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java b/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java
new file mode 100644
index 0000000..8449853
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.ui;
+
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Point;
+import android.os.Debug;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.rule.LimitDevicesRule;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.celllayout.FavoriteItemsTransaction;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.tapl.HomeAppIcon;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
+import com.android.launcher3.util.rule.FailureWatcher;
+import com.android.launcher3.util.rule.SamplerRule;
+import com.android.launcher3.util.rule.ScreenRecordRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.util.rule.TestIsolationRule;
+import com.android.launcher3.util.rule.TestStabilityRule;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for all TAPL tests in Launcher providing various utility methods.
+ */
+public abstract class BaseLauncherTaplTest {
+
+ public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
+ public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 10;
+
+ public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT;
+ private static final String TAG = "BaseLauncherTaplTest";
+
+ private static final long BYTES_PER_MEGABYTE = 1 << 20;
+
+ private static boolean sDumpWasGenerated = false;
+ private static boolean sActivityLeakReported = false;
+ private static boolean sSeenKeyguard = false;
+ private static boolean sFirstTimeWaitingForWizard = true;
+
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ protected final UiDevice mDevice = getUiDevice();
+ protected final LauncherInstrumentation mLauncher = createLauncherInstrumentation();
+
+ @NonNull
+ public static LauncherInstrumentation createLauncherInstrumentation() {
+ waitForSetupWizardDismissal(); // precondition for creating LauncherInstrumentation
+ return new LauncherInstrumentation(true);
+ }
+
+ protected Context mTargetContext;
+ protected String mTargetPackage;
+ private int mLauncherPid;
+
+ private final ActivityManager.MemoryInfo mMemoryInfo = new ActivityManager.MemoryInfo();
+ private final ActivityManager mActivityManager;
+ private long mMemoryBefore;
+
+ /** Detects activity leaks and throws an exception if a leak is found. */
+ public static void checkDetectedLeaks(LauncherInstrumentation launcher) {
+ checkDetectedLeaks(launcher, false);
+ }
+
+ /** Detects activity leaks and throws an exception if a leak is found. */
+ public static void checkDetectedLeaks(LauncherInstrumentation launcher,
+ boolean requireOneActiveActivityUnused) {
+ if (TestStabilityRule.isPresubmit()) return; // b/313501215
+
+ final boolean requireOneActiveActivity =
+ false; // workaround for leaks when there is an unexpected Recents activity
+
+ if (sActivityLeakReported) return;
+
+ // Check whether activity leak detector has found leaked activities.
+ Wait.atMost(() -> getActivityLeakErrorMessage(launcher, requireOneActiveActivity),
+ () -> {
+ launcher.forceGc();
+ return MAIN_EXECUTOR.submit(
+ () -> launcher.noLeakedActivities(requireOneActiveActivity)).get();
+ }, launcher, DEFAULT_UI_TIMEOUT);
+ }
+
+ public static String getAppPackageName() {
+ return getInstrumentation().getContext().getPackageName();
+ }
+
+ private static String getActivityLeakErrorMessage(LauncherInstrumentation launcher,
+ boolean requireOneActiveActivity) {
+ sActivityLeakReported = true;
+ return "Activity leak detector has found leaked activities, requirining 1 activity: "
+ + requireOneActiveActivity + "; "
+ + dumpHprofData(launcher, false, requireOneActiveActivity) + ".";
+ }
+
+ private static String dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak,
+ boolean requireOneActiveActivity) {
+ if (intentionalLeak) return "intentional leak; not generating dump";
+
+ String result;
+ if (sDumpWasGenerated) {
+ result = "dump has already been generated by another test";
+ } else {
+ try {
+ final String fileName =
+ getInstrumentation().getTargetContext().getFilesDir().getPath()
+ + "/ActivityLeakHeapDump.hprof";
+ if (TestHelpers.isInLauncherProcess()) {
+ Debug.dumpHprofData(fileName);
+ } else {
+ final UiDevice device = getUiDevice();
+ device.executeShellCommand(
+ "am dumpheap " + device.getLauncherPackageName() + " " + fileName);
+ }
+ Log.d(TAG, "Saved leak dump, the leak is still present: "
+ + !launcher.noLeakedActivities(requireOneActiveActivity));
+ sDumpWasGenerated = true;
+ result = "saved memory dump as an artifact";
+ } catch (Throwable e) {
+ Log.e(TAG, "dumpHprofData failed", e);
+ result = "failed to save memory dump";
+ }
+ }
+ return result + ". Full list of activities: " + launcher.getRootedActivitiesList();
+ }
+
+ protected BaseLauncherTaplTest() {
+ mActivityManager = InstrumentationRegistry.getContext()
+ .getSystemService(ActivityManager.class);
+ mLauncher.enableCheckEventsForSuccessfulGestures();
+ mLauncher.setAnomalyChecker(BaseLauncherTaplTest::verifyKeyguardInvisible);
+ try {
+ mDevice.setOrientationNatural();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ mLauncher.enableDebugTracing();
+ // Avoid double-reporting of Launcher crashes.
+ mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
+ }
+
+ @Rule
+ public ShellCommandRule mDisableHeadsUpNotification =
+ ShellCommandRule.disableHeadsUpNotification();
+
+ @Rule
+ public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
+
+ @Rule
+ public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
+ @Rule
+ public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
+
+ @Rule
+ public LimitDevicesRule mlimitDevicesRule = new LimitDevicesRule();
+
+ protected void performInitialization() {
+ reinitializeLauncherData();
+ mDevice.pressHome();
+ // Check that we switched to home.
+ mLauncher.getWorkspace();
+ checkDetectedLeaks(mLauncher, true);
+ }
+
+ protected void clearPackageData(String pkg) throws IOException, InterruptedException {
+ assertTrue("pm clear command failed",
+ mDevice.executeShellCommand("pm clear " + pkg)
+ .contains("Success"));
+ assertTrue("pm wait-for-handler command failed",
+ mDevice.executeShellCommand("pm wait-for-handler")
+ .contains("Success"));
+ }
+
+ protected TestRule getRulesInsideActivityMonitor() {
+ final RuleChain inner = RuleChain
+ .outerRule(new FailureWatcher(mLauncher, null))
+ .around(new TestIsolationRule(mLauncher, true));
+ return TestHelpers.isInLauncherProcess()
+ ? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
+ : inner;
+ }
+
+ @Rule
+ public TestRule mOrderSensitiveRules = RuleChain
+ .outerRule(new SamplerRule())
+ .around(new TestStabilityRule())
+ .around(getRulesInsideActivityMonitor());
+
+ public UiDevice getDevice() {
+ return mDevice;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mLauncher.onTestStart();
+
+ final String launcherPackageName = mDevice.getLauncherPackageName();
+ try {
+ final Context context = InstrumentationRegistry.getContext();
+ final PackageManager pm = context.getPackageManager();
+ final PackageInfo launcherPackage = pm.getPackageInfo(launcherPackageName, 0);
+
+ if (!launcherPackage.versionName.equals("BuildFromAndroidStudio")) {
+ Assert.assertEquals("Launcher version doesn't match tests version",
+ pm.getPackageInfo(context.getPackageName(), 0).getLongVersionCode(),
+ launcherPackage.getLongVersionCode());
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ mLauncherPid = 0;
+
+ mTargetContext = InstrumentationRegistry.getTargetContext();
+ mTargetPackage = mTargetContext.getPackageName();
+ mLauncherPid = mLauncher.getPid();
+
+ UserManager userManager = mTargetContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (UserHandle userHandle : userManager.getUserProfiles()) {
+ if (!userHandle.isSystem()) {
+ mDevice.executeShellCommand(
+ "pm remove-user --wait " + userHandle.getIdentifier());
+ }
+ }
+ }
+
+ onTestStart();
+ performInitialization();
+ }
+
+ private long getAvailableMemory() {
+ mActivityManager.getMemoryInfo(mMemoryInfo);
+
+ return Math.divideExact(mMemoryInfo.availMem, BYTES_PER_MEGABYTE);
+ }
+
+ @Before
+ public void saveMemoryBefore() {
+ mMemoryBefore = getAvailableMemory();
+ }
+
+ @After
+ public void logMemoryAfter() {
+ long memoryAfter = getAvailableMemory();
+
+ Log.d(TAG, "Available memory: before=" + mMemoryBefore
+ + "MB, after=" + memoryAfter
+ + "MB, delta=" + (memoryAfter - mMemoryBefore) + "MB");
+ }
+
+ /** Method that should be called when a test starts. */
+ public static void onTestStart() {
+ waitForSetupWizardDismissal();
+
+ if (TestStabilityRule.isPresubmit()) {
+ aggressivelyUnlockSysUi();
+ } else {
+ verifyKeyguardInvisible();
+ }
+ }
+
+ private static boolean hasSystemUiObject(String resId) {
+ return getUiDevice().hasObject(
+ By.res(SYSTEMUI_PACKAGE, resId));
+ }
+
+ @NonNull
+ private static UiDevice getUiDevice() {
+ return UiDevice.getInstance(getInstrumentation());
+ }
+
+ private static void aggressivelyUnlockSysUi() {
+ final UiDevice device = getUiDevice();
+ for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
+ Log.d(TAG, "Before attempting to unlock the phone");
+ try {
+ device.executeShellCommand("input keyevent 82");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ device.waitForIdle();
+ }
+ Assert.assertTrue("Keyguard still visible",
+ TestHelpers.wait(
+ Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
+ Log.d(TAG, "Keyguard is not visible");
+ }
+
+ /** Waits for setup wizard to go away. */
+ private static void waitForSetupWizardDismissal() {
+ if (sFirstTimeWaitingForWizard) {
+ try {
+ getUiDevice().executeShellCommand(
+ "am force-stop com.google.android.setupwizard");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ final boolean wizardDismissed = TestHelpers.wait(
+ Until.gone(By.pkg("com.google.android.setupwizard").depth(0)),
+ sFirstTimeWaitingForWizard ? 120000 : 0);
+ sFirstTimeWaitingForWizard = false;
+ Assert.assertTrue("Setup wizard is still visible", wizardDismissed);
+ }
+
+ /** Asserts that keyguard is not visible */
+ public static void verifyKeyguardInvisible() {
+ final boolean keyguardAlreadyVisible = sSeenKeyguard;
+
+ sSeenKeyguard = sSeenKeyguard
+ || !TestHelpers.wait(
+ Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000);
+
+ Assert.assertFalse(
+ "Keyguard is visible, which is likely caused by a crash in SysUI, seeing keyguard"
+ + " for the first time = "
+ + !keyguardAlreadyVisible,
+ sSeenKeyguard);
+ }
+
+ @After
+ public void resetFreezeRecentTaskList() {
+ try {
+ mDevice.executeShellCommand("wm reset-freeze-recent-tasks");
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to reset fozen recent tasks list", e);
+ }
+ }
+
+ @After
+ public void verifyLauncherState() {
+ try {
+ // Limits UI tests affecting tests running after them.
+ mDevice.pressHome();
+ mLauncher.waitForLauncherInitialized();
+ if (mLauncherPid != 0) {
+ assertEquals("Launcher crashed, pid mismatch:",
+ mLauncherPid, mLauncher.getPid().intValue());
+ }
+ } finally {
+ mLauncher.onTestFinish();
+ }
+ }
+
+ protected void reinitializeLauncherData() {
+ reinitializeLauncherData(false);
+ }
+
+ protected void reinitializeLauncherData(boolean clearWorkspace) {
+ if (clearWorkspace) {
+ mLauncher.clearLauncherData();
+ } else {
+ mLauncher.reinitializeLauncherData();
+ }
+ mLauncher.waitForLauncherInitialized();
+ }
+
+ public static void startAppFast(String packageName) {
+ startIntent(
+ getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage(
+ packageName),
+ By.pkg(packageName).depth(0),
+ true /* newTask */);
+ }
+
+ public static void startTestActivity(String activityName, String activityLabel) {
+ final String packageName = getAppPackageName();
+ final Intent intent = getInstrumentation().getContext().getPackageManager()
+ .getLaunchIntentForPackage(packageName);
+ intent.setComponent(new ComponentName(packageName,
+ "com.android.launcher3.tests." + activityName));
+ startIntent(intent, By.pkg(packageName).text(activityLabel),
+ false /* newTask */);
+ }
+
+ public static void startTestActivity(int activityNumber) {
+ startTestActivity("Activity" + activityNumber, "TestActivity" + activityNumber);
+ }
+
+ public static void startImeTestActivity() {
+ final String packageName = getAppPackageName();
+ final Intent intent = getInstrumentation().getContext().getPackageManager()
+ .getLaunchIntentForPackage(packageName);
+ intent.setComponent(new ComponentName(packageName,
+ "com.android.launcher3.testcomponent.ImeTestActivity"));
+ startIntent(intent, By.pkg(packageName).text("ImeTestActivity"),
+ false /* newTask */);
+ }
+
+ /** Starts ExcludeFromRecentsTestActivity, which has excludeFromRecents="true". */
+ public static void startExcludeFromRecentsTestActivity() {
+ final String packageName = getAppPackageName();
+ final Intent intent = getInstrumentation().getContext().getPackageManager()
+ .getLaunchIntentForPackage(packageName);
+ intent.setComponent(new ComponentName(packageName,
+ "com.android.launcher3.testcomponent.ExcludeFromRecentsTestActivity"));
+ startIntent(intent, By.pkg(packageName).text("ExcludeFromRecentsTestActivity"),
+ false /* newTask */);
+ }
+
+ private static void startIntent(Intent intent, BySelector selector, boolean newTask) {
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ if (newTask) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ } else {
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ }
+ getInstrumentation().getTargetContext().startActivity(intent);
+ assertTrue("App didn't start: " + selector,
+ TestHelpers.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT));
+
+ // Wait for the Launcher to stop.
+ final LauncherInstrumentation launcherInstrumentation = new LauncherInstrumentation();
+ Wait.atMost("Launcher activity didn't stop",
+ () -> !launcherInstrumentation.isLauncherActivityStarted(),
+ launcherInstrumentation, DEFAULT_ACTIVITY_TIMEOUT);
+ }
+
+ public static ActivityInfo resolveSystemAppInfo(String category) {
+ return getInstrumentation().getContext().getPackageManager().resolveActivity(
+ new Intent(Intent.ACTION_MAIN).addCategory(category),
+ PackageManager.MATCH_SYSTEM_ONLY)
+ .activityInfo;
+ }
+
+
+ public static String resolveSystemApp(String category) {
+ return resolveSystemAppInfo(category).packageName;
+ }
+
+ protected HomeAppIcon createShortcutInCenterIfNotExist(String name) {
+ Point dimension = mLauncher.getWorkspace().getIconGridDimensions();
+ return createShortcutIfNotExist(name, dimension.x / 2, dimension.y / 2);
+ }
+
+ protected HomeAppIcon createShortcutIfNotExist(String name, Point cellPosition) {
+ return createShortcutIfNotExist(name, cellPosition.x, cellPosition.y);
+ }
+
+ protected HomeAppIcon createShortcutIfNotExist(String name, int cellX, int cellY) {
+ HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
+ Log.d(ICON_MISSING, "homeAppIcon: " + homeAppIcon + " name: " + name
+ + " cell: " + cellX + ", " + cellY);
+ if (homeAppIcon == null) {
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(name).dragToWorkspace(cellX, cellY);
+ } finally {
+ allApps.unfreeze();
+ }
+ homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
+ }
+ return homeAppIcon;
+ }
+
+ protected void commitTransactionAndLoadHome(FavoriteItemsTransaction transaction) {
+ transaction.commit();
+
+ // Launch the home activity
+ UiDevice.getInstance(getInstrumentation()).pressHome();
+ mLauncher.waitForLauncherInitialized();
+ }
+
+ /** Clears all recent tasks */
+ protected void clearAllRecentTasks() {
+ if (!mLauncher.getRecentTasks().isEmpty()) {
+ mLauncher.goHome().switchToOverview().dismissAllTasks();
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
new file mode 100644
index 0000000..bb645d7
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.ui.widget;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.celllayout.FavoriteItemsTransaction;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.testcomponent.WidgetConfigActivity;
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.BaseLauncherActivityTest;
+import com.android.launcher3.util.BlockingBroadcastReceiver;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.views.OptionsPopupView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.picker.WidgetsFullSheet;
+import com.android.launcher3.widget.picker.WidgetsListAdapter;
+import com.android.launcher3.widget.picker.WidgetsRecyclerView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test to verify widget configuration is properly shown.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AddConfigWidgetTest extends BaseLauncherActivityTest<Launcher> {
+
+ @Rule
+ public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+
+ private LauncherAppWidgetProviderInfo mWidgetInfo;
+ private AppWidgetManager mAppWidgetManager;
+
+ private int mWidgetId;
+
+ @Before
+ public void setUp() throws Exception {
+ mWidgetInfo = TestViewHelpers.findWidgetProvider(true /* hasConfigureScreen */);
+ mAppWidgetManager = AppWidgetManager.getInstance(targetContext());
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testWidgetConfig() throws Throwable {
+ runTest(true);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testConfigCancelled() throws Throwable {
+ runTest(false);
+ }
+
+ /**
+ * @param acceptConfig accept the config activity
+ */
+ private void runTest(boolean acceptConfig) throws Throwable {
+ new FavoriteItemsTransaction(targetContext()).commit();
+ loadLauncherSync();
+
+ // Add widget to homescreen
+ WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
+ executeOnLauncher(OptionsPopupView::openWidgets);
+ uiDevice.waitForIdle();
+
+ // Select the widget header
+ Context testContext = getInstrumentation().getContext();
+ String packageName = testContext.getPackageName();
+ executeOnLauncher(l -> {
+ WidgetsRecyclerView wrv = WidgetsFullSheet.getWidgetsView(l);
+ WidgetsListAdapter adapter = (WidgetsListAdapter) wrv.getAdapter();
+ int pos = adapter.getItems().indexOf(
+ adapter.getItems().stream()
+ .filter(entry -> packageName.equals(entry.mPkgItem.packageName))
+ .findFirst()
+ .get());
+ wrv.getLayoutManager().scrollToPosition(pos);
+ adapter.onHeaderClicked(true, new PackageUserKey(packageName, Process.myUserHandle()));
+ });
+ uiDevice.waitForIdle();
+
+ View widgetView = getOnceNotNull("Widget not found", l -> searchView(l.getDragLayer(), v ->
+ v instanceof WidgetCell
+ && v.getTag() instanceof PendingAddWidgetInfo pawi
+ && mWidgetInfo.provider.equals(pawi.componentName)));
+ addToWorkspace(widgetView);
+
+ // Widget id for which the config activity was opened
+ mWidgetId = monitor.getWidgetId();
+
+ // Verify that the widget id is valid and bound
+ assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
+ setResult(acceptConfig);
+
+ if (acceptConfig) {
+ getOnceNotNull("Widget was not added", l -> {
+ // Close the resize frame before searching for widget
+ AbstractFloatingView.closeAllOpenViews(l);
+ return l.getWorkspace().getFirstMatch(new WidgetSearchCondition());
+ });
+ assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
+ } else {
+ // Verify that the widget id is deleted.
+ Wait.atMost("", () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null);
+ }
+ }
+
+ private void setResult(boolean success) {
+ getInstrumentation().getTargetContext().sendBroadcast(
+ WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
+ success ? "clickOK" : "clickCancel"));
+ uiDevice.waitForIdle();
+ }
+
+ /**
+ * Condition for searching widget id
+ */
+ private class WidgetSearchCondition implements ItemOperator {
+
+ @Override
+ public boolean evaluate(ItemInfo info, View view) {
+ return info instanceof LauncherAppWidgetInfo lawi
+ && lawi.providerName.equals(mWidgetInfo.provider)
+ && lawi.appWidgetId == mWidgetId;
+ }
+ }
+
+ /**
+ * Broadcast receiver for receiving widget config activity status.
+ */
+ private static class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver {
+
+ WidgetConfigStartupMonitor() {
+ super(WidgetConfigActivity.class.getName());
+ }
+
+ public int getWidgetId() throws InterruptedException {
+ Intent intent = blockingGetExtraIntent();
+ assertNotNull("Null EXTRA_INTENT", intent);
+ assertEquals("Intent action is not ACTION_APPWIDGET_CONFIGURE",
+ AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
+ int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ LauncherAppWidgetInfo.NO_ID);
+ assertNotSame("Widget id is NO_ID", widgetId, LauncherAppWidgetInfo.NO_ID);
+ return widgetId;
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
similarity index 77%
rename from tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
rename to tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 4cdbd96..8846d65 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -1,17 +1,17 @@
/*
* Copyright (C) 2017 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
+ * 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
+ * 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.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.launcher3.ui.widget;
@@ -22,12 +22,12 @@
import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.TestUtil.getOnUiThread;
+import static com.android.launcher3.util.Wait.atMost;
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
@@ -36,6 +36,7 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
+import android.text.TextUtils;
import android.widget.RemoteViews;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -49,13 +50,12 @@
import com.android.launcher3.celllayout.FavoriteItemsTransaction;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.tapl.Widget;
-import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.BaseLauncherActivityTest;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetManagerHelper;
import org.junit.After;
@@ -67,6 +67,7 @@
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Tests for bind widget flow.
@@ -75,7 +76,7 @@
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class TaplBindWidgetTest extends AbstractLauncherUiTest<Launcher> {
+public class BindWidgetTest extends BaseLauncherActivityTest<Launcher> {
@Rule
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -87,11 +88,9 @@
private LauncherModel mModel;
- @Override
@Before
public void setUp() throws Exception {
- super.setUp();
- mModel = LauncherAppState.getInstance(mTargetContext).getModel();
+ mModel = LauncherAppState.getInstance(targetContext()).getModel();
}
@After
@@ -101,7 +100,7 @@
}
if (mSessionId > -1) {
- mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+ targetContext().getPackageManager().getPackageInstaller().abandonSession(mSessionId);
}
}
@@ -122,13 +121,12 @@
LauncherAppWidgetProviderInfo info = addWidgetToScreen(false, false,
item -> item.appWidgetId = -33);
- final Workspace workspace = mLauncher.getWorkspace();
// Item deleted from db
mCursor = queryItem();
assertEquals(0, mCursor.getCount());
// The view does not exist
- assertTrue("Widget exists", workspace.tryGetWidget(info.label, 0) == null);
+ verifyItemEventuallyNull("Widget exists", widgetProvider(info));
}
@Test
@@ -154,18 +152,19 @@
// Widget has a valid Id now.
assertEquals(0, mCursor.getInt(mCursor.getColumnIndex(LauncherSettings.Favorites.RESTORED))
& FLAG_ID_NOT_VALID);
- assertNotNull(AppWidgetManager.getInstance(mTargetContext)
+ assertNotNull(AppWidgetManager.getInstance(targetContext())
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
LauncherSettings.Favorites.APPWIDGET_ID))));
// send OPTION_APPWIDGET_RESTORE_COMPLETED
int appWidgetId = mCursor.getInt(
mCursor.getColumnIndex(LauncherSettings.Favorites.APPWIDGET_ID));
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mTargetContext);
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(targetContext());
Bundle b = new Bundle();
b.putBoolean(WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED, true);
- RemoteViews remoteViews = new RemoteViews(mTargetPackage, R.layout.appwidget_not_ready);
+ RemoteViews remoteViews = new RemoteViews(
+ targetContext().getPackageName(), R.layout.appwidget_not_ready);
appWidgetManager.updateAppWidgetOptions(appWidgetId, b);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
@@ -175,15 +174,14 @@
WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED));
executeOnLauncher(l -> l.getAppWidgetHolder().startListening());
verifyWidgetPresent(info);
- assertNull(mLauncher.getWorkspace().tryGetPendingWidget(100));
+ verifyItemEventuallyNull("Pending widget exists", pendingWidgetProvider());
}
@Test
public void testPendingWidget_notRestored_removed() {
addPendingItemToScreen(getInvalidWidgetInfo(), FLAG_ID_NOT_VALID | FLAG_PROVIDER_NOT_READY);
- assertTrue("Pending widget exists",
- mLauncher.getWorkspace().tryGetPendingWidget(0) == null);
+ verifyItemEventuallyNull("Pending widget exists", pendingWidgetProvider());
// Item deleted from db
mCursor = queryItem();
assertEquals(0, mCursor.getCount());
@@ -216,7 +214,7 @@
// Create an active installer session
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(item.providerName.getPackageName());
- PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
+ PackageInstaller installer = targetContext().getPackageManager().getPackageInstaller();
mSessionId = installer.createSession(params);
addPendingItemToScreen(item, FLAG_ID_NOT_VALID | FLAG_PROVIDER_NOT_READY);
@@ -234,36 +232,47 @@
}
private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) {
- final Widget widget = mLauncher.getWorkspace().tryGetWidget(info.label,
- TestUtil.DEFAULT_UI_TIMEOUT);
- assertTrue("Widget is not present",
- widget != null);
+ getOnceNotNull("Widget is not present", widgetProvider(info));
}
private void verifyPendingWidgetPresent() {
- final Widget widget = mLauncher.getWorkspace().tryGetPendingWidget(
- TestUtil.DEFAULT_UI_TIMEOUT);
- assertTrue("Pending widget is not present",
- widget != null);
+ getOnceNotNull("Widget is not present", pendingWidgetProvider());
+ }
+
+ private Function<Launcher, Object> pendingWidgetProvider() {
+ return l -> l.getWorkspace().getFirstMatch(
+ (item, view) -> view instanceof PendingAppWidgetHostView);
+ }
+
+ private Function<Launcher, Object> widgetProvider(LauncherAppWidgetProviderInfo info) {
+ return l -> l.getWorkspace().getFirstMatch((item, view) ->
+ view instanceof LauncherAppWidgetHostView
+ && TextUtils.equals(info.label, view.getContentDescription()));
+ }
+
+ private void verifyItemEventuallyNull(String message, Function<Launcher, Object> provider) {
+ atMost(message, () -> getFromLauncher(provider) == null);
}
private void addPendingItemToScreen(LauncherAppWidgetInfo item, int restoreStatus) {
item.restoreStatus = restoreStatus;
item.screenId = FIRST_SCREEN_ID;
- commitTransactionAndLoadHome(
- new FavoriteItemsTransaction(mTargetContext).addItem(() -> item));
+ new FavoriteItemsTransaction(targetContext()).addItem(() -> item).commit();
+ loadLauncherSync();
}
private LauncherAppWidgetProviderInfo addWidgetToScreen(boolean hasConfigureScreen,
boolean bindWidget, Consumer<LauncherAppWidgetInfo> itemOverride) {
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(hasConfigureScreen);
- commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
+ new FavoriteItemsTransaction(targetContext())
.addItem(() -> {
- LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, bindWidget);
+ LauncherAppWidgetInfo item =
+ createWidgetInfo(info, targetContext(), bindWidget);
item.screenId = FIRST_SCREEN_ID;
itemOverride.accept(item);
return item;
- }));
+ }).commit();
+ loadLauncherSync();
return info;
}
@@ -277,13 +286,13 @@
Set<String> activePackage = getOnUiThread(() -> {
Set<String> packages = new HashSet<>();
- InstallSessionHelper.INSTANCE.get(mTargetContext).getActiveSessions()
+ InstallSessionHelper.INSTANCE.get(targetContext()).getActiveSessions()
.keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName));
return packages;
});
while (true) {
try {
- mTargetContext.getPackageManager().getPackageInfo(
+ targetContext().getPackageManager().getPackageInfo(
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (Exception e) {
if (!activePackage.contains(pkg)) {
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
similarity index 62%
rename from tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
rename to tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index fe3b2ee..2fb7987 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -1,34 +1,41 @@
/*
* Copyright (C) 2017 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
+ * 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
+ * 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.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.launcher3.ui.widget;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -37,14 +44,13 @@
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.tapl.AddToHomeScreenPrompt;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.testcomponent.RequestPinItemActivity;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.BaseLauncherActivityTest;
+import com.android.launcher3.util.BlockingBroadcastReceiver;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.Wait.Condition;
+import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Before;
@@ -53,25 +59,27 @@
import org.junit.runner.RunWith;
import java.util.UUID;
+import java.util.regex.Pattern;
/**
* Test to verify pin item request flow.
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class TaplRequestPinItemTest extends AbstractLauncherUiTest<Launcher> {
+public class RequestPinItemTest extends BaseLauncherActivityTest<Launcher> {
@Rule
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+ @Rule
+ public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+
private String mCallbackAction;
private String mShortcutId;
private int mAppWidgetId;
- @Override
@Before
public void setUp() throws Exception {
- super.setUp();
mCallbackAction = UUID.randomUUID().toString();
mShortcutId = UUID.randomUUID().toString();
}
@@ -81,9 +89,9 @@
@Test
public void testPinWidgetNoConfig() throws Throwable {
- runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo
+ && ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId
+ && ((LauncherAppWidgetInfo) info).providerName.getClassName()
.equals(AppWidgetNoConfig.class.getName()));
}
@@ -94,18 +102,18 @@
RequestPinItemActivity.class, "setRemoteViewColor").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED);
- runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo
+ && ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId
+ && ((LauncherAppWidgetInfo) info).providerName.getClassName()
.equals(AppWidgetNoConfig.class.getName()), command);
}
@Test
public void testPinWidgetWithConfig() throws Throwable {
runTest("pinWidgetWithConfig", true,
- (info, view) -> info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ (info, view) -> info instanceof LauncherAppWidgetInfo
+ && ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId
+ && ((LauncherAppWidgetInfo) info).providerName.getClassName()
.equals(AppWidgetWithConfig.class.getName()));
}
@@ -119,47 +127,48 @@
runTest("pinShortcut", false, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
- return info instanceof WorkspaceItemInfo &&
- info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
- ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId);
+ return info instanceof WorkspaceItemInfo
+ && info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
+ && ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId);
}
}, command);
}
private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher,
Intent... commandIntents) throws Throwable {
- commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
+ new FavoriteItemsTransaction(targetContext()).commit();
+ loadLauncherSync();
// Open Pin item activity
BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
RequestPinItemActivity.class.getName());
- mLauncher.
- getWorkspace().
- switchToAllApps().
- getAppIcon("Test Pin Item").
- launch(getAppPackageName());
+ Context testContext = getInstrumentation().getContext();
+ startAppFast(
+ testContext.getPackageName(),
+ new Intent(testContext, RequestPinItemActivity.class));
assertNotNull(openMonitor.blockingGetExtraIntent());
// Set callback
- PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0,
- new Intent(mCallbackAction).setPackage(mTargetContext.getPackageName()),
+ PendingIntent callback = PendingIntent.getBroadcast(targetContext(), 0,
+ new Intent(mCallbackAction).setPackage(targetContext().getPackageName()),
FLAG_ONE_SHOT | FLAG_MUTABLE);
- mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
+ targetContext().sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, "setCallback").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", callback));
for (Intent command : commandIntents) {
- mTargetContext.sendBroadcast(command);
+ targetContext().sendBroadcast(command);
}
// call the requested method to start the flow
- mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
+ targetContext().sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, activityMethod));
- final AddToHomeScreenPrompt addToHomeScreenPrompt = mLauncher.getAddToHomeScreenPrompt();
// Accept confirmation:
BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction);
- addToHomeScreenPrompt.addAutomatically();
+ BySelector selector = By.text(Pattern.compile("^Add to home screen$", CASE_INSENSITIVE))
+ .pkg(targetContext().getPackageName());
+ uiDevice.wait(device -> device.findObject(selector), TestUtil.DEFAULT_UI_TIMEOUT).click();
Intent result = resultReceiver.blockingGetIntent();
assertNotNull(result);
mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
@@ -167,28 +176,9 @@
assertNotSame(-1, mAppWidgetId);
}
- // Go back to home
- mLauncher.goHome();
- Wait.atMost("", new ItemSearchCondition(itemMatcher), mLauncher);
- }
-
- /**
- * Condition for for an item
- */
- private class ItemSearchCondition implements Condition {
-
- private final ItemOperator mOp;
-
- ItemSearchCondition(ItemOperator op) {
- mOp = op;
- }
-
- @Override
- public boolean isTrue() throws Throwable {
- return mMainThreadExecutor.submit(() -> {
- Launcher l = Launcher.ACTIVITY_TRACKER.getCreatedContext();
- return l != null && l.getWorkspace().getFirstMatch(mOp) != null;
- }).get();
- }
+ // Reload activity, so that the activity is focused
+ closeCurrentActivity();
+ loadLauncherSync();
+ getOnceNotNull("", l -> l.getWorkspace().getFirstMatch(itemMatcher));
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
deleted file mode 100644
index 7845222..0000000
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.launcher3.ui.widget;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-
-import android.appwidget.AppWidgetManager;
-import android.content.Intent;
-import android.view.View;
-
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.testcomponent.WidgetConfigActivity;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test to verify widget configuration is properly shown.
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest<Launcher> {
-
- @Rule
- public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
-
- private LauncherAppWidgetProviderInfo mWidgetInfo;
- private AppWidgetManager mAppWidgetManager;
-
- private int mWidgetId;
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- mWidgetInfo = TestViewHelpers.findWidgetProvider(true /* hasConfigureScreen */);
- mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
- }
-
- @Test
- @PortraitLandscape
- public void testWidgetConfig() throws Throwable {
- runTest(true);
- }
-
- @Test
- @PortraitLandscape
- public void testConfigCancelled() throws Throwable {
- runTest(false);
- }
-
-
- /**
- * @param acceptConfig accept the config activity
- */
- private void runTest(boolean acceptConfig) throws Throwable {
- commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
-
- // Drag widget to homescreen
- WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
- mLauncher.getWorkspace()
- .openAllWidgets()
- .getWidget(mWidgetInfo.getLabel())
- .dragToWorkspace(true, false);
- // Widget id for which the config activity was opened
- mWidgetId = monitor.getWidgetId();
-
- // Verify that the widget id is valid and bound
- assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
-
- setResultAndWaitForAnimation(acceptConfig);
- if (acceptConfig) {
- Wait.atMost("", new WidgetSearchCondition(), mLauncher);
- assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
- } else {
- // Verify that the widget id is deleted.
- Wait.atMost("", () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
- mLauncher);
- }
- }
-
- private static void setResult(boolean success) {
- getInstrumentation().getTargetContext().sendBroadcast(
- WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
- success ? "clickOK" : "clickCancel"));
- }
-
- private void setResultAndWaitForAnimation(boolean success) {
- if (mLauncher.isLauncher3()) {
- setResult(success);
- } else {
- mLauncher.executeAndWaitForWallpaperAnimation(
- () -> setResult(success),
- "setting widget coinfig result");
- }
- }
-
- /**
- * Condition for searching widget id
- */
- private class WidgetSearchCondition implements Wait.Condition, ItemOperator {
-
- @Override
- public boolean isTrue() throws Throwable {
- return mMainThreadExecutor.submit(() -> {
- Launcher l = Launcher.ACTIVITY_TRACKER.getCreatedContext();
- return l != null && l.getWorkspace().getFirstMatch(this) != null;
- }).get();
- }
-
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo
- && ((LauncherAppWidgetInfo) info).providerName.getClassName().equals(
- mWidgetInfo.provider.getClassName())
- && ((LauncherAppWidgetInfo) info).appWidgetId == mWidgetId;
- }
- }
-
- /**
- * Broadcast receiver for receiving widget config activity status.
- */
- private class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver {
-
- public WidgetConfigStartupMonitor() {
- super(WidgetConfigActivity.class.getName());
- }
-
- public int getWidgetId() throws InterruptedException {
- Intent intent = blockingGetExtraIntent();
- assertNotNull("Null EXTRA_INTENT", intent);
- assertEquals("Intent action is not ACTION_APPWIDGET_CONFIGURE",
- AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
- int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
- LauncherAppWidgetInfo.NO_ID);
- assertNotSame("Widget id is NO_ID", widgetId, LauncherAppWidgetInfo.NO_ID);
- return widgetId;
- }
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/WidgetPickerTest.java
similarity index 68%
rename from tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
rename to tests/src/com/android/launcher3/ui/widget/WidgetPickerTest.java
index 19c5850..caad1d9 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/WidgetPickerTest.java
@@ -22,24 +22,30 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.tapl.Widgets;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.BaseLauncherActivityTest;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
/**
- * This test run in both Out of process (Oop) and in-process (Ipc).
* Make sure the basic interactions with the WidgetPicker works.
*/
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class TaplWidgetPickerTest extends AbstractLauncherUiTest<Launcher> {
+public class WidgetPickerTest extends BaseLauncherActivityTest<Launcher> {
+
+ @Rule
+ public TestRule screenRecordRule = new ScreenRecordRule();
private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
return WidgetsFullSheet.getWidgetsView(launcher);
@@ -56,30 +62,21 @@
@ScreenRecord
@PortraitLandscape
public void testWidgets() {
- mLauncher.goHome();
+ loadLauncherSync();
// Test opening widgets.
executeOnLauncher(launcher ->
assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
- Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
- assertNotNull("openAllWidgets() returned null", widgets);
- widgets = mLauncher.getAllWidgets();
+ assertNotNull("openAllWidgets() returned null",
+ getFromLauncher(OptionsPopupView::openWidgets));
+ WidgetsRecyclerView widgets = getFromLauncher(this::getWidgetsView);
assertNotNull("getAllWidgets() returned null", widgets);
- executeOnLauncher(launcher ->
- assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
+ executeOnLauncher(launcher -> assertTrue("Widgets is not shown", widgets.isShown()));
executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
0, getWidgetsScroll(launcher)));
- // Test flinging widgets.
- widgets.flingForward();
- Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
- executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
- flingForwardY > 0));
+ executeOnLauncher(AbstractFloatingView::closeAllOpenViews);
+ uiDevice.waitForIdle();
- widgets.flingBackward();
- executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
- getWidgetsScroll(launcher) < flingForwardY));
-
- mLauncher.goHome();
waitForLauncherCondition("Widgets were not closed",
launcher -> getWidgetsView(launcher) == null);
}
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index cfc0a6b..c623513 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.ui.workspace;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
@@ -29,11 +27,9 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
-import android.view.View;
import android.view.ViewGroup;
import androidx.test.filters.LargeTest;
-import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
@@ -49,9 +45,6 @@
import org.junit.Test;
-import java.util.ArrayDeque;
-import java.util.Queue;
-
/**
* Tests for theme icon support in Launcher
*
@@ -137,27 +130,10 @@
} catch (Exception e) {
throw new RuntimeException(e);
}
-
- // Find the app icon
- Queue<View> viewQueue = new ArrayDeque<>();
- viewQueue.add(parent);
- BubbleTextView icon = null;
- while (!viewQueue.isEmpty()) {
- View view = viewQueue.poll();
- if (view instanceof ViewGroup) {
- parent = (ViewGroup) view;
- for (int i = parent.getChildCount() - 1; i >= 0; i--) {
- viewQueue.add(parent.getChildAt(i));
- }
- } else if (view instanceof BubbleTextView btv) {
- if (btv.getContentDescription() != null
- && title.equals(btv.getContentDescription().toString())) {
- icon = btv;
- break;
- }
- }
- }
- return icon;
+ return (BubbleTextView) searchView(parent, v ->
+ v instanceof BubbleTextView btv
+ && btv.getContentDescription() != null
+ && title.equals(btv.getContentDescription().toString()));
}
private BubbleTextView verifyIconTheme(String title, ViewGroup parent, boolean isThemed) {
@@ -193,11 +169,4 @@
rv.getLayoutManager().scrollToPosition(pos);
});
}
-
- private void addToWorkspace(View btv) {
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () ->
- btv.getAccessibilityDelegate().performAccessibilityAction(
- btv, com.android.launcher3.R.id.action_add_to_workspace, null));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
- }
}
diff --git a/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
index 476e497..61fa7d5 100644
--- a/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
+++ b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
@@ -22,6 +22,9 @@
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.children
import androidx.lifecycle.Lifecycle.State.RESUMED
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ActivityScenario.ActivityAction
@@ -30,11 +33,13 @@
import com.android.launcher3.Launcher
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherState
+import com.android.launcher3.R
import com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST
import com.android.launcher3.tapl.TestHelpers
import com.android.launcher3.util.ModelTestExtensions.loadModelSync
import com.android.launcher3.util.Wait.atMost
import java.util.function.Function
+import java.util.function.Predicate
import java.util.function.Supplier
import org.junit.After
@@ -56,6 +61,8 @@
)
.also { currentScenario = it }
+ @JvmField val uiDevice = UiDevice.getInstance(getInstrumentation())
+
@After
fun closeCurrentActivity() {
currentScenario?.close()
@@ -117,9 +124,10 @@
@JvmOverloads
protected fun injectKeyEvent(keyCode: Int, actionDown: Boolean, metaState: Int = 0) {
+ uiDevice.waitForIdle()
val eventTime = SystemClock.uptimeMillis()
val event =
- KeyEvent.obtain(
+ KeyEvent(
eventTime,
eventTime,
if (actionDown) KeyEvent.ACTION_DOWN else MotionEvent.ACTION_UP,
@@ -130,24 +138,47 @@
/* scancode= */ 0,
/* flags= */ 0,
InputDevice.SOURCE_KEYBOARD,
- /* characters =*/ null,
)
executeOnLauncher { it.dispatchKeyEvent(event) }
- event.recycle()
}
- fun startAppFast(packageName: String) {
- val intent = targetContext().packageManager.getLaunchIntentForPackage(packageName)!!
+ @JvmOverloads
+ fun startAppFast(
+ packageName: String,
+ intent: Intent = targetContext().packageManager.getLaunchIntentForPackage(packageName)!!,
+ ) {
intent.addCategory(Intent.CATEGORY_LAUNCHER)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
targetContext().startActivity(intent)
- UiDevice.getInstance(getInstrumentation()).waitForIdle()
+ uiDevice.waitForIdle()
}
fun freezeAllApps() = executeOnLauncher {
it.appsView.appsStore.enableDeferUpdates(DEFER_UPDATES_TEST)
}
- fun executeShellCommand(cmd: String) =
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(cmd)
+ fun executeShellCommand(cmd: String) = uiDevice.executeShellCommand(cmd)
+
+ fun addToWorkspace(view: View) {
+ TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) {
+ view.accessibilityDelegate.performAccessibilityAction(
+ view,
+ R.id.action_add_to_workspace,
+ null,
+ )
+ }
+ UiDevice.getInstance(getInstrumentation()).waitForIdle()
+ }
+
+ fun ViewGroup.searchView(filter: Predicate<View>): View? {
+ if (filter.test(this)) return this
+ for (child in children) {
+ if (filter.test(child)) return child
+ if (child is ViewGroup)
+ child.searchView(filter)?.let {
+ return it
+ }
+ }
+ return null
+ }
}
diff --git a/tests/src/com/android/launcher3/util/BlockingBroadcastReceiver.kt b/tests/src/com/android/launcher3/util/BlockingBroadcastReceiver.kt
new file mode 100644
index 0000000..20881d1
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/BlockingBroadcastReceiver.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Parcelable
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit.SECONDS
+
+private const val DEFAULT_BROADCAST_TIMEOUT_SECS: Long = 10
+
+/** Broadcast receiver which blocks until the result is received. */
+open class BlockingBroadcastReceiver(action: String) : BroadcastReceiver() {
+
+ val value = CompletableFuture<Intent>()
+
+ init {
+ getInstrumentation()
+ .targetContext
+ .registerReceiver(this, IntentFilter(action), Context.RECEIVER_EXPORTED)
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+ value.complete(intent)
+ }
+
+ @Throws(InterruptedException::class)
+ fun blockingGetIntent(): Intent =
+ value.get(DEFAULT_BROADCAST_TIMEOUT_SECS, SECONDS).also {
+ getInstrumentation().targetContext.unregisterReceiver(this)
+ }
+
+ @Throws(InterruptedException::class)
+ fun blockingGetExtraIntent(): Intent? =
+ blockingGetIntent().getParcelableExtra<Parcelable>(Intent.EXTRA_INTENT) as Intent?
+}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 7bdc040..3b85309 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -12,7 +12,7 @@
import com.android.app.viewcapture.data.ExportedData;
import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.BaseLauncherTaplTest;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -57,7 +57,7 @@
@Override
protected void succeeded(Description description) {
super.succeeded(description);
- AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
+ BaseLauncherTaplTest.checkDetectedLeaks(mLauncher);
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java b/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
index 7ff55fe..7cb2614 100644
--- a/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
+++ b/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
@@ -163,6 +163,32 @@
}
/**
+ * Dismisses the Keyboard Quick Switch view by going home. After the Keyboard Quick Switch view
+ * gets hidden, it unpresses ALT key, which is generally used to keep the view visible.
+ */
+ public Workspace dismissByGoingHome() {
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "verifying keyboard quick switch view is shown")) {
+ mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
+ }
+
+ mLauncher.goHome();
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "waiting for keyboard quick switch dismissal");
+ LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ mLauncher.waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
+ }
+
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
+ "get workspace after releasing ALT key")) {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_HOME_ALT_LEFT_UP);
+ mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
+ return mLauncher.getWorkspace();
+ }
+ }
+
+ /**
* Launches the currently-focused app task.
* <p>
* This method should only be used if the focused task is for a recent running app, otherwise
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 08c5552..fac73d3 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1728,6 +1728,27 @@
scrollDownByDistance(container, distance, appsListBottomPadding);
}
+ /** Scrolls up by given distance within the container. */
+ void scrollUpByDistance(UiObject2 container, int distance) {
+ scrollUpByDistance(container, distance, 0);
+ }
+
+ /** Scrolls up by given distance within the container considering the given bottom padding. */
+ void scrollUpByDistance(UiObject2 container, int distance, int bottomPadding) {
+ final Rect containerRect = getVisibleBounds(container);
+ final int bottomGestureMarginInContainer = getBottomGestureMarginInContainer(container);
+ scroll(
+ container,
+ Direction.UP,
+ new Rect(
+ 0,
+ containerRect.height() - bottomGestureMarginInContainer - distance,
+ 0,
+ bottomGestureMarginInContainer + bottomPadding),
+ /* steps= */ 10,
+ /* slowDown= */ true);
+ }
+
void scrollDownByDistance(UiObject2 container, int distance) {
scrollDownByDistance(container, distance, 0);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 3097d9c..ac2748e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.LauncherInstrumentation.log;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -31,6 +32,7 @@
import com.android.launcher3.testing.shared.TestProtocol;
import java.util.Collection;
+import java.util.List;
/**
* All widgets container.
@@ -128,8 +130,10 @@
final UiObject2 searchBar = findSearchBar();
final int searchBarHeight = searchBar.getVisibleBounds().height();
final UiObject2 fullWidgetsPicker = verifyActiveContainer();
- mLauncher.assertTrue("Widgets container didn't become scrollable",
- fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
+
+ // Widget picker may not be scrollable if there are few items. Instead of waiting on
+ // picker being scrollable, we wait on widget headers to be available.
+ waitForWidgetListItems(fullWidgetsPicker);
final UiObject2 widgetsContainer =
findTestAppWidgetsTableContainer(testAppWidgetPackage);
@@ -176,6 +180,13 @@
}
}
+ private void waitForWidgetListItems(UiObject2 fullWidgetsPicker) {
+ List<UiObject2> headers = fullWidgetsPicker.wait(Until.findObjects(
+ By.res(mLauncher.getLauncherPackageName(), "widgets_list_header")), WAIT_TIME_MS);
+ mLauncher.assertTrue("Widgets list is not available",
+ headers != null && !headers.isEmpty());
+ }
+
private UiObject2 findSearchBar() {
final BySelector searchBarContainerSelector = By.res(mLauncher.getLauncherPackageName(),
"search_and_recommendations_container");
@@ -199,19 +210,38 @@
"container");
String packageName = mLauncher.getContext().getPackageName();
+ String packageNameToFind =
+ (testAppWidgetPackage == null || testAppWidgetPackage.isEmpty()) ? packageName
+ : testAppWidgetPackage;
+
final BySelector targetAppSelector = By
.clazz("android.widget.TextView")
- .text((testAppWidgetPackage == null || testAppWidgetPackage.isEmpty())
- ? packageName
- : testAppWidgetPackage);
+ .text(packageNameToFind);
+ final BySelector expandListButtonSelector =
+ By.res(mLauncher.getLauncherPackageName(), "widget_list_expand_button");
final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_table");
boolean hasHeaderExpanded = false;
+ // List was expanded by clicking "Show all" button.
+ boolean hasListExpanded = false;
+
int scrollDistance = 0;
for (int i = 0; i < SCROLL_ATTEMPTS; i++) {
UiObject2 widgetPicker = mLauncher.waitForLauncherObject(widgetPickerSelector);
UiObject2 widgetListView = verifyActiveContainer();
+
+ // Press "Show all" button if it exists. Otherwise, keep scrolling to
+ // find the header or show all button.
+ UiObject2 expandListButton =
+ mLauncher.findObjectInContainer(widgetListView, expandListButtonSelector);
+ if (expandListButton != null) {
+ expandListButton.click();
+ hasListExpanded = true;
+ i = -1;
+ continue;
+ }
+
UiObject2 header = mLauncher.waitForObjectInContainer(widgetListView,
headerSelector);
// If a header is barely visible in the bottom edge of the screen, its height could be
@@ -222,6 +252,17 @@
// Look for a header that has the test app name.
UiObject2 headerTitle = mLauncher.findObjectInContainer(widgetListView,
targetAppSelector);
+
+ final UiObject2 searchBar = findSearchBar();
+ // If header's title is under or above search bar, let's not process the header yet,
+ // scroll a bit more to bring the header into visible area.
+ if (headerTitle != null
+ && headerTitle.getVisibleCenter().y <= searchBar.getVisibleCenter().y) {
+ log("Test app's header is behind the searchbar, scrolling up");
+ mLauncher.scrollUpByDistance(widgetListView, scrollDistance);
+ continue;
+ }
+
if (headerTitle != null) {
// If we find the header and it has not been expanded, let's click it to see the
// widgets list. Note that we wait until the header is out of the gesture region at
@@ -258,11 +299,24 @@
widgetPicker,
widgetsContainerSelector);
- mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null
- ? rightPane
- : widgetListView, scrollDistance);
+ if (hasListExpanded && packageNameToFind.compareToIgnoreCase(
+ getFirstHeaderTitle(widgetListView)) < 0) {
+ mLauncher.scrollUpByDistance(hasHeaderExpanded && rightPane != null
+ ? rightPane
+ : widgetListView, scrollDistance);
+ } else {
+ mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null
+ ? rightPane
+ : widgetListView, scrollDistance);
+ }
}
return null;
}
+
+ @NonNull
+ private String getFirstHeaderTitle(UiObject2 widgetListView) {
+ UiObject2 firstHeader = mLauncher.getObjectsInContainer(widgetListView, "app_title").get(0);
+ return firstHeader != null ? firstHeader.getText() : "";
+ }
}