Merge "Log the input type for gesture nav gestures" into udc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index b1064f7..bf84820 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -177,7 +177,7 @@
ALL_APPS_SEARCH_RESULT_SUGGEST = 22 [deprecated = true];
ALL_APPS_SEARCH_RESULT_ASSISTANT = 23;
ALL_APPS_SEARCH_RESULT_CHROMETAB = 24;
- ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25;
+ ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25 [deprecated = true];
ALL_APPS_SEARCH_RESULT_TIPS = 26;
ALL_APPS_SEARCH_RESULT_PEOPLE_TILE = 27;
ALL_APPS_SEARCH_RESULT_LEGACY_SHORTCUT = 30;
diff --git a/quickstep/res/drawable/ic_save_app_pair.xml b/quickstep/res/drawable/ic_save_app_pair.xml
new file mode 100644
index 0000000..4a7ee1a
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M13.329,2.305H4.242C2.751,2.305 1.542,3.514 1.542,5.005V13.005C1.542,14.496 2.751,15.705 4.242,15.705H7.875V19.011C7.875,20.502 9.084,21.711 10.575,21.711H19.662C21.153,21.711 22.362,20.502 22.362,19.011V10.011C22.362,8.52 21.153,7.311 19.662,7.311H16.029V5.005C16.029,3.514 14.821,2.305 13.329,2.305ZM14.329,7.311V5.005C14.329,4.452 13.882,4.005 13.329,4.005H4.242C3.69,4.005 3.242,4.452 3.242,5.005V13.005C3.242,13.557 3.69,14.005 4.242,14.005H7.875V10.011C7.875,8.52 9.084,7.311 10.575,7.311H14.329ZM9.575,14.005V10.011C9.575,9.611 9.81,9.266 10.15,9.106C10.285,9.037 10.438,8.999 10.6,8.999H19.687C20.239,8.999 20.687,9.447 20.687,9.999V18.999C20.687,19.399 20.452,19.744 20.113,19.904C19.977,19.972 19.824,20.011 19.662,20.011H10.575C10.023,20.011 9.575,19.563 9.575,19.011V15.705H9.6V14.005H9.575ZM15.542,11.996V14H17.588V15H15.542V16.996H14.542V15H12.464V14H14.542V11.996H15.542Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 5c20a2d..64d3f67 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -25,7 +25,8 @@
android:clipToOutline="true"
android:alpha="0"
android:visibility="invisible"
- android:focusableInTouchMode="true">
+ android:focusableInTouchMode="true"
+ app:layout_ignoreInsets="true">
<HorizontalScrollView
android:id="@+id/scroll_view"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index 43439c6..2887518 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -205,15 +205,16 @@
android:id="@+id/checkmark_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginBottom="44dp"
android:gravity="center"
android:scaleType="centerCrop"
app:lottie_loop="false"
android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle" />
+ app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle"
+ app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/gesture_tutorial_fragment_action_button"
@@ -224,6 +225,7 @@
android:stateListAnimator="@null"
android:text="@string/gesture_tutorial_action_button_label"
android:visibility="invisible"
+ android:layout_marginBottom="60dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml
index d7daea3..f3856ba 100644
--- a/quickstep/res/layout/taskbar_edu.xml
+++ b/quickstep/res/layout/taskbar_edu.xml
@@ -55,7 +55,7 @@
style="@style/TaskbarEdu.Button.Close"
android:textColor="?android:attr/textColorPrimary"/>
- <com.android.launcher3.pageindicators.PageIndicatorDots
+ <com.android.launcher3.pageindicators.LauncherDotsPageIndicator
android:id="@+id/content_page_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -63,6 +63,7 @@
app:layout_constraintBottom_toBottomOf="@id/edu_start_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
+ app:indicatorDotColor="@color/folder_pagination_color"
android:elevation="1dp" />
<Button
diff --git a/quickstep/res/layout/taskbar_edu_tooltip.xml b/quickstep/res/layout/taskbar_edu_tooltip.xml
index 3fcd713..657066c 100644
--- a/quickstep/res/layout/taskbar_edu_tooltip.xml
+++ b/quickstep/res/layout/taskbar_edu_tooltip.xml
@@ -20,7 +20,6 @@
android:layout_marginBottom="16dp"
android:clipChildren="false"
android:clipToPadding="false"
- android:fitsSystemWindows="true"
android:focusable="true"
android:importantForAccessibility="yes"
android:gravity="center"
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 72e7a42..3df50c9 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -53,8 +53,7 @@
<string name="back_gesture_intro_title" msgid="19551256430224428">"Zum Zurückgehen wischen"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Wenn du zum letzten Bildschirm zurückgehen möchtest, wische vom linken oder rechten Rand zur Mitte."</string>
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Wenn du zum letzten Bildschirm zurückgehen möchtest, wische mit zwei Fingern vom linken oder rechten Displayrand zur Mitte."</string>
- <!-- no translation found for back_gesture_tutorial_title (1944737946101059789) -->
- <skip />
+ <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Zurück"</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Wische vom unteren Displayrand nach oben."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Achte darauf, nicht innezuhalten, bevor du loslässt."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Wische gerade nach oben."</string>
@@ -73,12 +72,11 @@
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Zwischen Apps wechseln"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Wische auf dem Display von unten nach oben, halte den Finger gedrückt und lass dann los, um zwischen Apps zu wechseln."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Wische zum App-Wechseln mit zwei Fingern vom unteren Displayrand nach oben, halte und lass dann los."</string>
- <!-- no translation found for overview_gesture_tutorial_title (4125835002668708720) -->
- <skip />
+ <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Apps wechseln"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Fertig"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Fertig"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Einstellungen"</string>
- <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Wiederholen"</string>
+ <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Noch einmal versuchen"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sehr gut!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Anleitung <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Fertig!"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index a0f23cb..4badb49 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -53,8 +53,7 @@
<string name="back_gesture_intro_title" msgid="19551256430224428">"पिछली स्क्रीन पर वापस जाने के लिए स्वाइप करें"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से बीचों-बीच तक स्वाइप करें."</string>
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से स्क्रीन के बीच तक दो उंगलियों से स्वाइप करें."</string>
- <!-- no translation found for back_gesture_tutorial_title (1944737946101059789) -->
- <skip />
+ <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"वापस जाएं"</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"देख लें कि आप स्क्रीन से अपनी उंगली उठाने से पहले, इसे कहीं न रोक रहे हों."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"देख लें कि आपने ऊपर की ओर बिलकुल सीधे स्वाइप किया हो."</string>
@@ -73,8 +72,7 @@
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"एक ऐप्लिकेशन से दूसरे पर जाने के लिए स्वाइप करें"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"एक ऐप से दूसरे पर जाने के लिए, स्क्रीन पर नीचे से ऊपर की ओर स्वाइप करें, दबाकर रखें, और फिर छोड़ दें."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"इन ऐप के बीच स्विच करने के लिए, दो उंगलियों से नीचे से ऊपर स्वाइप करें, होल्ड करें, और फिर छोड़ें."</string>
- <!-- no translation found for overview_gesture_tutorial_title (4125835002668708720) -->
- <skip />
+ <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"ऐप्लिकेशन के बीच स्विच करें"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"आप पूरी तरह तैयार हैं"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"हो गया"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"सेटिंग"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 2134d14..5ac931d 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -24,7 +24,7 @@
<string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
- <string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին օգտագործած հավելվածները"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին հավելվածներ"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Առաջադրանքը փակված է"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ր"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 6782013..6f30fe6 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -100,7 +100,7 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"タスクバーの説明を開きました"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"タスクバーの説明を閉じました"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"アプリを横にドラッグして 2 個のアプリを同時に使用できます"</string>
- <string name="taskbar_edu_stashing" msgid="5645461372669217294">"タスクバーを表示するには、ゆっくりと上にスワイプします"</string>
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"タスクバーを表示するには、上にゆっくりとスワイプします"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"毎日の使用状況に基づいてアプリの候補が表示されます"</string>
<string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"[設定] でジェスチャー ナビゲーションを ON にすると、タスクバーを自動的に非表示にできます"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"タスクバーの各種機能"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 66ffae5..a88d5e1 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -24,7 +24,7 @@
<string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
- <string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы пайдаланылған қолданбалар"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы қолданбалар"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Тапсырма жабылды."</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мин"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index de3b511..fa6e5d2 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -109,7 +109,7 @@
<string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ಮುಗಿದಿದೆ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ಮುಖಪುಟ"</string>
- <string name="taskbar_button_a11y" msgid="5241161324875094465">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"ಹಿಂದೆ"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ಪರಿವರ್ತಕ"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"ಇತ್ತೀಚಿನವು"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 79aba94..34285b7 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -114,7 +114,7 @@
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME которгучу"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"Акыркылар"</string>
<string name="taskbar_button_notifications" msgid="7471740351507357318">"Билдирмелер"</string>
- <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ыкчам жөндөөлөр"</string>
+ <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ыкчам параметрлер"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапшырмалар тактасы"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапшырмалар панели көрсөтүлдү"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапшырмалар панели жашырылды"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index fe0aff2..fe4e954 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -109,7 +109,7 @@
<string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ပြီးပြီ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ပင်မစာမျက်နှာ"</string>
- <string name="taskbar_button_a11y" msgid="5241161324875094465">"အများသုံးစွဲနိုင်မှု"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"အများသုံးနိုင်မှု"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"နောက်သို့"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ပြောင်းစနစ်"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"လတ်တလောများ"</string>
diff --git a/quickstep/res/values-sw600dp/config.xml b/quickstep/res/values-sw600dp/config.xml
deleted file mode 100644
index e1e442f..0000000
--- a/quickstep/res/values-sw600dp/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Applies to large tablet screens portrait -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">true</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp-land/config.xml b/quickstep/res/values-sw720dp-land/config.xml
deleted file mode 100644
index bf0f9ad..0000000
--- a/quickstep/res/values-sw720dp-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Applies to large tablet screens landscape -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">false</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp/config.xml b/quickstep/res/values-sw720dp/config.xml
deleted file mode 100644
index e1e442f..0000000
--- a/quickstep/res/values-sw720dp/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Applies to large tablet screens portrait -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">true</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 4c69b2b..d12513d 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -109,7 +109,7 @@
<string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Головний екран"</string>
- <string name="taskbar_button_a11y" msgid="5241161324875094465">"Спеціальні можливості"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"Доступність"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"Назад"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Перемикач IME"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"Нещодавні"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index ae3c445..0433177 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -24,7 +24,7 @@
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
- <string name="accessibility_recent_apps" msgid="4058661986695117371">"Yaqinda ishlatilgan ilovalar"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Oxirgi ilovalar"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Vazifalar yopildi"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 daqiqa"</string>
@@ -109,7 +109,7 @@
<string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Tayyor"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Bosh ekran"</string>
- <string name="taskbar_button_a11y" msgid="5241161324875094465">"Maxsus imkoniyatlar"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"Qulayliklar"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"Orqaga"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME tugmasi"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"Oxirgilar"</string>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 0d3aeb3..e45d9fd 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -52,10 +52,6 @@
<string name="setup_wizard_pkg" translatable="false" />
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">false</bool>
-
<!-- This is a float because it is converted to dp later in DeviceProfile -->
<item name="taskbar_icon_size" type="dimen" format="float">44</item>
</resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 8796d6c..7eecb29 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -321,7 +321,7 @@
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
new RemoteTransition(runner.toRemoteTransition(),
- mLauncher.getIApplicationThread()));
+ mLauncher.getIApplicationThread(), "QuickstepLaunch"));
return new ActivityOptionsWrapper(options, onEndCallback);
}
@@ -1122,7 +1122,7 @@
mLauncherOpenTransition = new RemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */).toRemoteTransition(),
- mLauncher.getIApplicationThread());
+ mLauncher.getIApplicationThread(), "QuickstepLaunchHome");
TransitionFilter homeCheck = new TransitionFilter();
// No need to handle the transition that also dismisses keyguard.
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index e8f2496..3510fbe 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -76,7 +76,6 @@
mFocusHelper = new SimpleFocusIndicatorHelper(this);
mActivityContext = ActivityContext.lookupContext(context);
- mActivityContext.addOnDeviceProfileChangeListener(this);
mNumPredictedAppsPerRow = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
updateVisibility();
}
@@ -84,6 +83,13 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
}
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index c165750..ed4a212 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
@@ -80,10 +81,13 @@
* Currently this animation just force stashes the taskbar in Overview.
*/
public Animator createAnimToRecentsState(RecentsState toState, long duration) {
- boolean useStashedLauncherState = toState.hasOverviewActions();
- boolean stashedLauncherState =
- useStashedLauncherState && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()
- && toState == RecentsState.MODAL_TASK;
+ // Force stash the taskbar in overview modal state or when going home. We do not force
+ // stash on home when running in a test as 3p launchers rely on taskbar instead of hotseat.
+ boolean isGoingHome = toState == RecentsState.HOME && !isRunningInTestHarness();
+ boolean useStashedLauncherState = toState.hasOverviewActions() || isGoingHome;
+ boolean stashedLauncherState = useStashedLauncherState && (
+ (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get() && toState == RecentsState.MODAL_TASK)
+ || isGoingHome);
TaskbarStashController stashController = mControllers.taskbarStashController;
// Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected.
// For all other states, just use the current stashed-in-app setting (e.g. if long clicked).
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 941b4b0..c4255bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -49,7 +49,8 @@
public static final int ALPHA_INDEX_STASHED = 0;
public static final int ALPHA_INDEX_HOME_DISABLED = 1;
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2;
- private static final int NUM_ALPHA_CHANNELS = 3;
+ public static final int ALPHA_INDEX_HIDDEN_WHILE_DREAMING = 3;
+ private static final int NUM_ALPHA_CHANNELS = 4;
/**
* The SharedPreferences key for whether the stashed handle region is dark.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 66a903b..41093bd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -55,7 +55,6 @@
import com.android.launcher3.R;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragDriver;
import com.android.launcher3.dragndrop.DragOptions;
@@ -188,12 +187,10 @@
DragOptions dragOptions = new DragOptions();
dragOptions.preDragCondition = null;
- if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
- PopupContainerWithArrow<BaseTaskbarContext> popupContainer =
- mControllers.taskbarPopupController.showForIcon(btv);
- if (popupContainer != null) {
- dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
- }
+ PopupContainerWithArrow<BaseTaskbarContext> popupContainer =
+ mControllers.taskbarPopupController.showForIcon(btv);
+ if (popupContainer != null) {
+ dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
}
if (dragOptions.preDragCondition == null) {
dragOptions.preDragCondition = new DragOptions.PreDragCondition() {
@@ -208,8 +205,7 @@
public void onPreDragStart(DropTarget.DragObject dragObject) {
mDragView = dragObject.dragView;
- if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()
- && !shouldStartDrag(0)) {
+ if (!shouldStartDrag(0)) {
mDragView.setOnAnimationEndCallback(() -> {
// Drag might be cancelled during the DragView animation, so check
// mIsPreDrag again.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 60b5c0d..77f681e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -53,6 +53,10 @@
// Translation property for taskbar background.
private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset);
+ // Used to fade in/out the entirety of the taskbar, for a smooth transition before/after sysui
+ // changes the inset visibility.
+ private final AnimatedFloat mTaskbarAlpha = new AnimatedFloat(this::updateTaskbarAlpha);
+
// Initialized in init.
private TaskbarControllers mControllers;
private TaskbarStashViaTouchController mTaskbarStashViaTouchController;
@@ -83,6 +87,9 @@
mAssistantBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
+
+ mTaskbarAlpha.value = 1;
+ updateTaskbarAlpha();
}
public void onDestroy() {
@@ -127,6 +134,10 @@
return mBgOffset;
}
+ public AnimatedFloat getTaskbarAlpha() {
+ return mTaskbarAlpha;
+ }
+
/**
* Make updates when configuration changes.
*/
@@ -165,6 +176,10 @@
updateOnBackgroundNavButtonColorIntensity();
}
+ private void updateTaskbarAlpha() {
+ mTaskbarDragLayer.setAlpha(mTaskbarAlpha.value);
+ }
+
@Override
public void setCornerRoundness(float cornerRoundness) {
mTaskbarDragLayer.setCornerRoundness(cornerRoundness);
@@ -197,6 +212,7 @@
pw.println(prefix + "TaskbarDragLayerController:");
pw.println(prefix + "\tmBgOffset=" + mBgOffset.value);
+ pw.println(prefix + "\tmTaskbarAlpha=" + mTaskbarAlpha.value);
pw.println(prefix + "\tmFolderMargin=" + mFolderMargin);
pw.println(prefix + "\tmLastSetBackgroundAlpha=" + mLastSetBackgroundAlpha);
pw.println(prefix + "\t\tmBgOverride=" + mBgOverride.value);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
index 6cd6512..d0e6386 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
@@ -25,12 +25,12 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
-import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.pageindicators.LauncherDotsPageIndicator;
import com.android.launcher3.taskbar.TaskbarEduController.TaskbarEduCallbacks;
import com.android.launcher3.views.ActivityContext;
/** Horizontal carousel of tutorial screens for Taskbar Edu. */
-public class TaskbarEduPagedView extends PagedView<PageIndicatorDots> {
+public class TaskbarEduPagedView extends PagedView<LauncherDotsPageIndicator> {
private TaskbarEduView mTaskbarEduView;
private TaskbarEduCallbacks mControllerCallbacks;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 1adbf39..fcb2042 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -70,20 +70,9 @@
fun init(controllers: TaskbarControllers) {
this.controllers = controllers
windowLayoutParams = context.windowLayoutParams
- windowLayoutParams.providedInsets =
- arrayOf(
- InsetsFrameProvider(insetsOwner, 0, navigationBars()),
- InsetsFrameProvider(insetsOwner, 0, tappableElement()),
- InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
- InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
- .setSource(SOURCE_DISPLAY),
- InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
- .setSource(SOURCE_DISPLAY)
- )
-
+ windowLayoutParams.insetsRoundedCornerFrame = true
onTaskbarWindowHeightOrInsetsChanged()
- windowLayoutParams.insetsRoundedCornerFrame = true
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
gestureNavSettingsObserver.registerForCallingUser()
}
@@ -94,6 +83,26 @@
}
fun onTaskbarWindowHeightOrInsetsChanged() {
+ if (context.isGestureNav) {
+ windowLayoutParams.providedInsets =
+ arrayOf(
+ InsetsFrameProvider(insetsOwner, 0, navigationBars()),
+ InsetsFrameProvider(insetsOwner, 0, tappableElement()),
+ InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
+ InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
+ .setSource(SOURCE_DISPLAY),
+ InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
+ .setSource(SOURCE_DISPLAY)
+ )
+ } else {
+ windowLayoutParams.providedInsets =
+ arrayOf(
+ InsetsFrameProvider(insetsOwner, 0, navigationBars()),
+ InsetsFrameProvider(insetsOwner, 0, tappableElement()),
+ InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures())
+ )
+ }
+
val touchableHeight = controllers.taskbarStashController.touchableHeight
touchableRegion.set(
0,
@@ -146,7 +155,8 @@
for (provider in windowLayoutParams.providedInsets) {
if (context.isGestureNav && provider.type == tappableElement()) {
provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
- } else {
+ } else if (provider.type != systemGestures()) {
+ // We only override insets at the bottom of the screen
provider.insetsSizeOverrides = insetsSizeOverride
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index edcd4c8..03d08eb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -1,17 +1,17 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
-import static com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
+import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_ASLEEP;
import android.app.KeyguardManager;
@@ -29,7 +29,7 @@
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING
| SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED
| SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
- | SYSUI_STATE_SCREEN_STATE_MASK;
+ | SYSUI_STATE_WAKEFULNESS_MASK;
// If any of these SysUi flags (via QuickstepContract) is set, the device to be considered
// locked.
@@ -75,13 +75,13 @@
keyguardOccluded);
updateIconsForBouncer();
- boolean screenOffOrTransitioningOff = (systemUiStateFlags & SYSUI_STATE_SCREEN_ON) == 0;
- boolean closeFloatingViews = keyguardShowing || screenOffOrTransitioningOff;
+ boolean asleepOrGoingToSleep = (systemUiStateFlags & SYSUI_STATE_AWAKE) == 0;
+ boolean closeFloatingViews = keyguardShowing || asleepOrGoingToSleep;
if (closeFloatingViews) {
- // animate the closing of the views, unless the screen is already fully turned off.
+ // animate the closing of the views, unless the screen is already asleep.
boolean animateViewClosing =
- (systemUiStateFlags & SYSUI_STATE_SCREEN_STATE_MASK) != SCREEN_STATE_OFF;
+ (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_ASLEEP;
AbstractFloatingView.closeOpenViews(mContext, animateViewClosing, TYPE_ALL);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index cf8148e..58cb558 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -22,12 +22,16 @@
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.systemui.animation.Interpolators.EMPHASIZED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
+import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -81,21 +85,37 @@
*
* This is cleared as soon as the screen begins to transition off.
*/
- private static final int FLAG_SCREEN_ON = 1 << 3;
+ private static final int FLAG_AWAKE = 1 << 3;
/**
- * Captures whether the launcher was active at the time the FLAG_SCREEN_ON was cleared.
- * Always cleared when FLAG_SCREEN_ON is set.
+ * Captures whether the launcher was active at the time the FLAG_AWAKE was cleared.
+ * Always cleared when FLAG_AWAKE is set.
* <p>
- * FLAG_RESUMED will be cleared when the screen is off, since all apps get paused at this point.
- * Thus, this flag indicates whether the launcher will be shown when the screen gets turned on
+ * FLAG_RESUMED will be cleared when the device is asleep, since all apps get paused at this
+ * point. Thus, this flag indicates whether the launcher will be shown when the device wakes up
* again.
*/
- private static final int FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF = 1 << 4;
+ private static final int FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE = 1 << 4;
- /** Whether the device is currently locked. */
+ /**
+ * Whether the device is currently locked.
+ * <ul>
+ * <li>While locked, the taskbar is always stashed.<li/>
+ * <li>Navbar animations on FLAG_DEVICE_LOCKED transitions will get special treatment.</li>
+ * </ul>
+ */
private static final int FLAG_DEVICE_LOCKED = 1 << 5;
+ /**
+ * Whether the complete taskbar is completely hidden (neither visible stashed or unstashed).
+ * This is tracked to allow a nice transition of the taskbar before SysUI forces it away by
+ * hiding the inset.
+ *
+ * This flag is predominanlty set while FLAG_DEVICE_LOCKED is set, thus the taskbar's invisible
+ * resting state while hidden is stashed.
+ */
+ private static final int FLAG_TASKBAR_HIDDEN = 1 << 6;
+
private static final int FLAGS_LAUNCHER_ACTIVE = FLAG_RESUMED | FLAG_TRANSITION_TO_RESUMED;
/** Equivalent to an int with all 1s for binary operation purposes */
private static final int FLAGS_ALL = ~0;
@@ -104,11 +124,21 @@
private static final float TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT = 0.33f;
private static final float TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT = 0.25f;
+ /**
+ * Delay for the taskbar fade-in.
+ *
+ * Helps to avoid visual noise when unlocking successfully via SFPS, and the device transitions
+ * to launcher directly. The delay avoids the navbar to become briefly visible. The duration
+ * is the same as in SysUI, see http://shortn/_uNSbDoRUSr.
+ */
+ private static final long TASKBAR_SHOW_DELAY_MS = 250;
+
private final AnimatedFloat mIconAlignment =
new AnimatedFloat(this::onIconAlignmentRatioChanged);
private TaskbarControllers mControllers;
private AnimatedFloat mTaskbarBackgroundAlpha;
+ private AnimatedFloat mTaskbarAlpha;
private AnimatedFloat mTaskbarCornerRoundness;
private MultiProperty mIconAlphaForHome;
private QuickstepLauncher mLauncher;
@@ -117,6 +147,9 @@
private int mState;
private LauncherState mLauncherState = LauncherState.NORMAL;
+ // Time when FLAG_TASKBAR_HIDDEN was last cleared, SystemClock.elapsedRealtime (milliseconds).
+ private long mLastUnlockTimeMs = 0;
+
private @Nullable TaskBarRecentsAnimationListener mTaskBarRecentsAnimationListener;
private boolean mIsAnimatingToLauncher;
@@ -187,6 +220,7 @@
mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
.getTaskbarBackgroundAlpha();
+ mTaskbarAlpha = mControllers.taskbarDragLayerController.getTaskbarAlpha();
mTaskbarCornerRoundness = mControllers.getTaskbarCornerRoundness();
mIconAlphaForHome = mControllers.taskbarViewController
.getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
@@ -265,20 +299,29 @@
/** SysUI flags updated, see QuickStepContract.SYSUI_STATE_* values. */
public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
- final boolean prevScreenIsOn = hasAnyFlag(FLAG_SCREEN_ON);
- final boolean currScreenIsOn = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_ON);
+ final boolean prevIsAwake = hasAnyFlag(FLAG_AWAKE);
+ final boolean currIsAwake = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_AWAKE);
- updateStateForFlag(FLAG_SCREEN_ON, currScreenIsOn);
- if (prevScreenIsOn != currScreenIsOn) {
+ updateStateForFlag(FLAG_AWAKE, currIsAwake);
+ if (prevIsAwake != currIsAwake) {
// The screen is switching between on/off. When turning off, capture whether the
// launcher is active and memoize this state.
- updateStateForFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
- prevScreenIsOn && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
+ updateStateForFlag(FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE,
+ prevIsAwake && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
}
boolean isDeviceLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
updateStateForFlag(FLAG_DEVICE_LOCKED, isDeviceLocked);
+ // Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
+ // interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
+ // when the device is asleep, the second condition extends ensures that the transition from
+ // and to the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar
+ // hide/reveal animation timings.
+ boolean isTaskbarHidden = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+ || (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_AWAKE;
+ updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden);
+
if (skipAnim) {
applyState(0);
} else {
@@ -377,7 +420,7 @@
}
}
- if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER_ACTIVE | FLAG_SCREEN_ON)) {
+ if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER_ACTIVE | FLAG_AWAKE)) {
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -406,6 +449,41 @@
AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext);
}
+ if (hasAnyFlag(changedFlags, FLAG_TASKBAR_HIDDEN) && !hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
+ // Take note of the current time, as the taskbar is made visible again.
+ mLastUnlockTimeMs = SystemClock.elapsedRealtime();
+ }
+
+ boolean isHidden = hasAnyFlag(FLAG_TASKBAR_HIDDEN);
+ float taskbarAlpha = isHidden ? 0 : 1;
+ if (mTaskbarAlpha.isAnimating() || mTaskbarAlpha.value != taskbarAlpha) {
+ Animator taskbarVisibility = mTaskbarAlpha.animateToValue(taskbarAlpha);
+
+ taskbarVisibility.setDuration(duration);
+ if (isHidden) {
+ // Stash the transient taskbar once the taskbar is not visible. This reduces
+ // visual noise when unlocking the device afterwards.
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ TaskbarStashController stashController =
+ mControllers.taskbarStashController;
+ stashController.updateAndAnimateTransientTaskbar(
+ /* stash */ true, /* duration */ 0);
+ }
+ });
+ } else {
+ // delay the fade in animation a bit to reduce visual noise when waking up a device
+ // with a fingerprint reader. This should only be done when the device was woken
+ // up via fingerprint reader, however since this information is currently not
+ // available, opting to always delay the fade-in a bit.
+ long durationSinceLastUnlockMs = SystemClock.elapsedRealtime() - mLastUnlockTimeMs;
+ taskbarVisibility.setStartDelay(
+ Math.max(0, TASKBAR_SHOW_DELAY_MS - durationSinceLastUnlockMs));
+ }
+ animatorSet.play(taskbarVisibility);
+ }
+
float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
// Don't animate if background has reached desired value.
@@ -564,7 +642,7 @@
long resetDuration = mControllers.taskbarStashController.isInApp()
? duration
: duration / 2;
- if (!mControllers.taskbarTranslationController.willAnimateToZeroBefore(resetDuration)
+ if (mControllers.taskbarTranslationController.shouldResetBackToZero(resetDuration)
&& (isAnimatingToLauncher() || mLauncherState == LauncherState.NORMAL)) {
animatorSet.play(mControllers.taskbarTranslationController
.createAnimToResetTranslation(resetDuration));
@@ -573,10 +651,10 @@
/** Whether the launcher is considered active. */
private boolean isInLauncher() {
- if (hasAnyFlag(FLAG_SCREEN_ON)) {
+ if (hasAnyFlag(FLAG_AWAKE)) {
return hasAnyFlag(FLAGS_LAUNCHER_ACTIVE);
} else {
- return hasAnyFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF);
+ return hasAnyFlag(FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE);
}
}
@@ -677,9 +755,9 @@
appendFlag(result, flags, FLAG_TRANSITION_TO_RESUMED, "transition_to_resumed");
appendFlag(result, flags, FLAG_LAUNCHER_IN_STATE_TRANSITION,
"launcher_in_state_transition");
- appendFlag(result, flags, FLAG_SCREEN_ON, "screen_on");
- appendFlag(result, flags, FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
- "launcher_active_at_screen_off");
+ appendFlag(result, flags, FLAG_AWAKE, "awake");
+ appendFlag(result, flags, FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE,
+ "was_active_while_awake");
appendFlag(result, flags, FLAG_DEVICE_LOCKED, "device_locked");
return result.toString();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index c537106..3d8bf9e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
+import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -63,6 +64,7 @@
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
+import java.util.StringJoiner;
/**
* Class to manage taskbar lifecycle
@@ -147,6 +149,8 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ debugWhyTaskbarNotDestroyed(
+ "TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
DeviceProfile dp = mUserUnlocked
? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
: null;
@@ -179,6 +183,9 @@
}
}
+ debugWhyTaskbarNotDestroyed("ComponentCallbacks#onConfigurationChanged() "
+ + "configDiffForRecreate="
+ + Configuration.configurationDiffToString(configDiffForRecreate));
if ((configDiffForRecreate & configsRequiringRecreate) != 0) {
recreateTaskbar();
} else {
@@ -207,6 +214,8 @@
mNavMode = info.navigationMode;
recreateTaskbar();
}
+ debugWhyTaskbarNotDestroyed("DisplayInfoChangeListener#"
+ + mDisplayController.getChangeFlagsString(flags));
};
mNavMode = mDisplayController.getInfo().navigationMode;
mDisplayController.addChangeListener(mDispInfoChangeListener);
@@ -227,10 +236,13 @@
new IntentFilter(ACTION_SHOW_TASKBAR),
RECEIVER_NOT_EXPORTED);
});
+
+ debugWhyTaskbarNotDestroyed("TaskbarManager created");
recreateTaskbar();
}
private void destroyExistingTaskbar() {
+ debugWhyTaskbarNotDestroyed("destroyExistingTaskbar: " + mTaskbarActivityContext);
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.onDestroy();
if (!FLAG_HIDE_NAVBAR_WINDOW) {
@@ -274,7 +286,12 @@
if (mActivity == activity) {
return;
}
+ if (mActivity != null) {
+ mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
+ }
mActivity = activity;
+ debugWhyTaskbarNotDestroyed("Set mActivity=" + mActivity);
+ mActivity.addOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
getUnfoldTransitionProgressProviderForActivity(activity);
mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider);
@@ -318,7 +335,9 @@
*/
public void clearActivity(@NonNull StatefulActivity activity) {
if (mActivity == activity) {
+ mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
mActivity = null;
+ debugWhyTaskbarNotDestroyed("clearActivity");
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
}
@@ -338,8 +357,12 @@
destroyExistingTaskbar();
- boolean isTaskBarEnabled = dp != null && isTaskbarPresent(dp);
- if (!isTaskBarEnabled) {
+ boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp);
+ debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
+ + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ + " FLAG_HIDE_NAVBAR_WINDOW=" + FLAG_HIDE_NAVBAR_WINDOW
+ + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
+ if (!isTaskbarEnabled) {
SystemUiProxy.INSTANCE.get(mContext)
.notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
return;
@@ -440,6 +463,11 @@
* Called when the manager is no longer needed
*/
public void destroy() {
+ debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
+ if (mActivity != null) {
+ mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
+ }
+
UI_HELPER_EXECUTOR.execute(
() -> mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext));
destroyExistingTaskbar();
@@ -464,4 +492,46 @@
mTaskbarActivityContext.dumpLogs(prefix + "\t", pw);
}
}
+
+ /** Temp logs for b/254119092. */
+ public void debugWhyTaskbarNotDestroyed(String debugReason) {
+ StringJoiner log = new StringJoiner("\n");
+ log.add(debugReason);
+
+ boolean activityTaskbarPresent = mActivity != null
+ && mActivity.getDeviceProfile().isTaskbarPresent;
+ boolean contextTaskbarPresent = mUserUnlocked
+ && LauncherAppState.getIDP(mContext).getDeviceProfile(mContext).isTaskbarPresent;
+ if (activityTaskbarPresent == contextTaskbarPresent) {
+ log.add("mActivity and mContext agree taskbarIsPresent=" + contextTaskbarPresent);
+ Log.d(TASKBAR_NOT_DESTROYED_TAG, log.toString());
+ return;
+ }
+
+ log.add("mActivity and mContext device profiles have different values, add more logs.");
+
+ log.add("\tmActivity logs:");
+ log.add("\t\tmActivity=" + mActivity);
+ if (mActivity != null) {
+ log.add("\t\tmActivity.getResources().getConfiguration()="
+ + mActivity.getResources().getConfiguration());
+ log.add("\t\tmActivity.getDeviceProfile().isTaskbarPresent="
+ + activityTaskbarPresent);
+ }
+ log.add("\tmContext logs:");
+ log.add("\t\tmContext=" + mContext);
+ log.add("\t\tmContext.getResources().getConfiguration()="
+ + mContext.getResources().getConfiguration());
+ if (mUserUnlocked) {
+ log.add("\t\tLauncherAppState.getIDP().getDeviceProfile(mContext).isTaskbarPresent="
+ + contextTaskbarPresent);
+ } else {
+ log.add("\t\tCouldn't get DeviceProfile because !mUserUnlocked");
+ }
+
+ Log.d(TASKBAR_NOT_DESTROYED_TAG, log.toString());
+ }
+
+ private final DeviceProfile.OnDeviceProfileChangeListener mDebugActivityDeviceProfileChanged =
+ dp -> debugWhyTaskbarNotDestroyed("mActivity onDeviceProfileChanged");
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 5bb958a..610efeb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
+import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -265,6 +266,7 @@
}
private void navigateHome() {
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
index c10b57a..054689b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
@@ -32,7 +32,6 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -75,7 +74,7 @@
@Override
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
- if (ShortcutUtil.supportsShortcuts(item) && FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
+ if (ShortcutUtil.supportsShortcuts(item)) {
out.add(mActions.get(NotificationListener.getInstanceIfConnected() != null
? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c43b621..69ea9fd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -36,6 +36,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -43,6 +44,7 @@
import android.app.RemoteAction;
import android.content.SharedPreferences;
import android.graphics.drawable.Icon;
+import android.os.SystemClock;
import android.util.Log;
import android.view.InsetsController;
import android.view.View;
@@ -50,6 +52,7 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -68,6 +71,8 @@
import com.android.quickstep.SystemUiProxy;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.StringJoiner;
import java.util.function.IntPredicate;
@@ -184,6 +189,40 @@
// Auto stashes when user has not interacted with the Taskbar after X ms.
private static final long NO_TOUCH_TIMEOUT_TO_STASH_MS = 5000;
+ // Duration for which an unlock event is considered "current", as other events are received
+ // asynchronously.
+ private static final long UNLOCK_TRANSITION_MEMOIZATION_MS = 200;
+
+ /**
+ * The default stash animation, morphing the taskbar into the navbar.
+ */
+ private static final int TRANSITION_DEFAULT = 0;
+ /**
+ * Transitioning from launcher to app. Same as TRANSITION_DEFAULT, differs in internal
+ * animation timings.
+ */
+ private static final int TRANSITION_HOME_TO_APP = 1;
+ /**
+ * Fading the navbar in and out, where the taskbar jumpcuts in and out at the very begin/end of
+ * the transition. Used to transition between the hotseat and navbar` without the stash/unstash
+ * transition.
+ */
+ private static final int TRANSITION_HANDLE_FADE = 2;
+ /**
+ * Same as TRANSITION_DEFAULT, but exclusively used during an "navbar unstash to hotseat
+ * animation" bound to the progress of a swipe gesture. It differs from TRANSITION_DEFAULT
+ * by not scaling the height of the taskbar background.
+ */
+ private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ TRANSITION_DEFAULT,
+ TRANSITION_HOME_TO_APP,
+ TRANSITION_HANDLE_FADE,
+ TRANSITION_UNSTASH_SUW_MANUAL,
+ })
+ private @interface StashAnimation {}
+
private final TaskbarActivityContext mActivity;
private final SharedPreferences mPrefs;
private final int mStashedHeight;
@@ -472,9 +511,16 @@
}
/**
- * Stash or unstashes the transient taskbar.
+ * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
*/
public void updateAndAnimateTransientTaskbar(boolean stash) {
+ updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION);
+ }
+
+ /**
+ * Stash or unstashes the transient taskbar.
+ */
+ public void updateAndAnimateTransientTaskbar(boolean stash, long duration) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
@@ -553,8 +599,7 @@
createAnimToIsStashed(
/* isStashed= */ false,
placeholderDuration,
- /* animateBg= */ false,
- /* changedFlags=*/ 0);
+ TRANSITION_UNSTASH_SUW_MANUAL);
animation.play(mAnimator);
}
@@ -562,10 +607,15 @@
* Create a stash animation and save to {@link #mAnimator}.
* @param isStashed whether it's a stash animation or an unstash animation
* @param duration duration of the animation
- * @param animateBg whether the taskbar's background should be animated
+ * @param animationType what transition type to play.
*/
- private void createAnimToIsStashed(boolean isStashed, long duration, boolean animateBg,
- int changedFlags) {
+ private void createAnimToIsStashed(boolean isStashed, long duration,
+ @StashAnimation int animationType) {
+ if (animationType == TRANSITION_UNSTASH_SUW_MANUAL && isStashed) {
+ // The STASH_ANIMATION_SUW_MANUAL must only be used during an unstash animation.
+ Log.e(TAG, "Illegal arguments:Using TRANSITION_UNSTASH_SUW_MANUAL to stash taskbar");
+ }
+
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -591,23 +641,10 @@
return;
}
- // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
- // already stashed Taskbar.
- boolean hotseatTopElement = mControllers.uiController.isHotseatIconOnTopWhenAligned()
- || !hasAnyFlag(changedFlags, FLAG_IN_APP);
- // If transitioning to unlocked device, do not play a stash animation.
- // Keep isUnlockTransition in sync with its counterpart in
- // TaskbarLauncherStateController#onStateChangeApplied.
- boolean isUnlockTransition = hasAnyFlag(changedFlags, FLAG_STASHED_DEVICE_LOCKED)
- && !hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
- boolean skipStashAnimation = !hotseatTopElement || isUnlockTransition;
-
if (isTransientTaskbar) {
- createTransientAnimToIsStashed(mAnimator, isStashed, duration, animateBg, changedFlags,
- skipStashAnimation);
+ createTransientAnimToIsStashed(mAnimator, isStashed, duration, animationType);
} else {
- createAnimToIsStashed(mAnimator, isStashed, duration, animateBg, skipStashAnimation,
- stashTranslation);
+ createAnimToIsStashed(mAnimator, isStashed, duration, stashTranslation, animationType);
}
mAnimator.addListener(new AnimatorListenerAdapter() {
@@ -636,7 +673,7 @@
}
private void createAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- boolean animateBg, boolean skipStashAnimation, float stashTranslation) {
+ float stashTranslation, @StashAnimation int animationType) {
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
@@ -650,12 +687,7 @@
secondHalfDurationScale = 0.5f;
fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
- if (animateBg) {
- fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1));
- } else {
- fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(1)));
- }
+ fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1));
firstHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(0),
@@ -666,7 +698,7 @@
mTaskbarStashedHandleAlpha.animateToValue(1)
);
- if (skipStashAnimation) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
fullLengthAnimatorSet.setInterpolator(INSTANT);
firstHalfAnimatorSet.setInterpolator(INSTANT);
}
@@ -677,6 +709,8 @@
fullLengthAnimatorSet.playTogether(
mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(0));
+
+ final boolean animateBg = animationType != TRANSITION_UNSTASH_SUW_MANUAL;
if (animateBg) {
fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(0));
} else {
@@ -691,7 +725,7 @@
mIconAlphaForStash.animateToValue(1)
);
- if (skipStashAnimation) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
fullLengthAnimatorSet.setInterpolator(FINAL_FRAME);
secondHalfAnimatorSet.setInterpolator(FINAL_FRAME);
}
@@ -714,61 +748,78 @@
}
private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- boolean animateBg, int changedFlags, boolean skipStashAnimation) {
- Interpolator skipInterpolator = null;
+ @StashAnimation int animationType) {
+ // Target values of the properties this is going to set
+ final float backgroundOffsetTarget = isStashed ? 1 : 0;
+ final float iconAlphaTarget = isStashed ? 0 : 1;
+ final float stashedHandleAlphaTarget = isStashed ? 1 : 0;
+
+ // Timing for the alpha values depend on the animation played
+ long iconAlphaStartDelay = 0, iconAlphaDuration = 0, stashedHandleAlphaDelay = 0,
+ stashedHandleAlphaDuration = 0;
+ if (duration > 0) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
+ // When fading, the handle fades in/out at the beginning of the transition with
+ // TASKBAR_STASH_ALPHA_DURATION.
+ stashedHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ // The iconAlphaDuration must be set to duration for the skippable interpolators
+ // below to work.
+ iconAlphaDuration = duration;
+ } else {
+ iconAlphaStartDelay = TASKBAR_STASH_ALPHA_START_DELAY;
+ iconAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ stashedHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+
+ if (isStashed) {
+ if (animationType == TRANSITION_HOME_TO_APP) {
+ iconAlphaStartDelay = TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY;
+ }
+ stashedHandleAlphaDelay = iconAlphaStartDelay;
+ stashedHandleAlphaDuration = Math.max(0, duration - iconAlphaStartDelay);
+ }
+
+ }
+ }
+
+ play(as, mTaskbarStashedHandleAlpha.animateToValue(stashedHandleAlphaTarget),
+ stashedHandleAlphaDelay,
+ stashedHandleAlphaDuration, LINEAR);
+
+ // The rest of the animations might be "skipped" in TRANSITION_HANDLE_FADE transitions.
+ AnimatorSet skippable = as;
+ if (animationType == TRANSITION_HANDLE_FADE) {
+ skippable = new AnimatorSet();
+ as.play(skippable);
+ skippable.setInterpolator(isStashed ? INSTANT : FINAL_FRAME);
+ }
+
+ final boolean animateBg = animationType != TRANSITION_UNSTASH_SUW_MANUAL;
+ if (animateBg) {
+ play(skippable, mTaskbarBackgroundOffset.animateToValue(backgroundOffsetTarget), 0,
+ duration, EMPHASIZED);
+ } else {
+ skippable.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundOffset.updateValue(backgroundOffsetTarget)));
+ }
+
+ play(skippable, mIconAlphaForStash.animateToValue(iconAlphaTarget), iconAlphaStartDelay,
+ iconAlphaDuration,
+ LINEAR);
if (isStashed) {
- if (animateBg) {
- play(as, mTaskbarBackgroundOffset.animateToValue(1), 0, duration, EMPHASIZED);
- } else {
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(1)));
- }
-
- long alphaStartDelay = duration == 0 ? 0 : (changedFlags == FLAG_IN_APP)
- ? TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY
- : TASKBAR_STASH_ALPHA_START_DELAY;
- long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
- play(as, mIconAlphaForStash.animateToValue(0), alphaStartDelay, alphaDuration, LINEAR);
- play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay,
- Math.max(0, duration - alphaStartDelay), LINEAR);
-
- play(as, mControllers.taskbarSpringOnStashController.createSpringToStash(), 0, duration,
- LINEAR);
-
- if (skipStashAnimation) {
- skipInterpolator = INSTANT;
- }
- } else {
- if (animateBg) {
- play(as, mTaskbarBackgroundOffset.animateToValue(0), 0, duration, EMPHASIZED);
- } else {
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(0)));
- }
-
- long alphaStartDelay = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_START_DELAY;
- long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
- play(as, mIconAlphaForStash.animateToValue(1), alphaStartDelay, alphaDuration, LINEAR);
- play(as, mTaskbarStashedHandleAlpha.animateToValue(0), 0, alphaDuration, LINEAR);
-
- if (skipStashAnimation) {
- skipInterpolator = FINAL_FRAME;
- }
+ play(skippable, mControllers.taskbarSpringOnStashController.createSpringToStash(),
+ 0, duration, LINEAR);
}
- mControllers.taskbarViewController.addRevealAnimToIsStashed(as, isStashed, duration,
+
+ mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
EMPHASIZED);
- if (skipInterpolator != null) {
- as.setInterpolator(skipInterpolator);
- }
-
- play(as, mControllers.stashedHandleViewController
+ play(skippable, mControllers.stashedHandleViewController
.createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
- as.play(mTaskbarStashedHandleHintScale.animateToValue(1f)
+ skippable.play(mTaskbarStashedHandleHintScale.animateToValue(1f)
.setDuration(isStashed ? duration / 2 : duration));
}
@@ -927,17 +978,10 @@
updateStateForFlag(FLAG_STASHED_SYSUI,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
- boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
- boolean wasLocked = hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
+ boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED)
+ && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY);
updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked);
- if (isLocked && !wasLocked && DisplayController.isTransientTaskbar(mActivity)) {
- // Stash the transient taskbar when locking the device. This improves the transition
- // to AoD (otherwise the taskbar stays a bit too long above the collapsing AoD scrim),
- // and ensures the taskar state is reset when unlocking the device afterwards.
- updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, true);
- }
-
// Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
@@ -1150,9 +1194,11 @@
private final IntPredicate mStashCondition;
private boolean mIsStashed;
- private boolean mIsHotseatIconOnTopWhenAligned;
+ private @StashAnimation int mLastStartedTransitionType = TRANSITION_DEFAULT;
private int mPrevFlags;
+ private long mLastUnlockTransitionTimeout = 0;
+
StatePropertyHolder(IntPredicate stashCondition) {
mStashCondition = stashCondition;
}
@@ -1170,7 +1216,7 @@
if (DEBUG) {
String stateString = formatFlagChange(flags, mPrevFlags,
- TaskbarStashController::getStateString);
+ TaskbarStashController::getStateString);
Log.d(TAG, "createSetStateAnimator: flags: " + stateString
+ ", duration: " + duration
+ ", isStashed: " + isStashed
@@ -1182,28 +1228,76 @@
onStateChangeApplied(changedFlags);
mPrevFlags = flags;
}
- boolean isHotseatIconOnTopWhenAligned =
- mControllers.uiController.isHotseatIconOnTopWhenAligned();
- // If an animation has started and mIsHotseatIconOnTopWhenAligned is changed, we need
- // to restart the animation with new parameters.
- if (mIsStashed != isStashed
- || (mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned
- && mAnimator != null && mAnimator.isStarted())) {
+
+ boolean isUnlockTransition = hasAnyFlag(changedFlags, FLAG_STASHED_DEVICE_LOCKED)
+ && !hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
+ if (isUnlockTransition) {
+ // the launcher might not be resumed at the time the device is considered
+ // unlocked (when the keyguard goes away), but possibly shortly afterwards.
+ // To play the unlock transition at the time the unstash animation actually happens,
+ // this memoizes the state transition for UNLOCK_TRANSITION_MEMOIZATION_MS.
+ mLastUnlockTransitionTimeout =
+ SystemClock.elapsedRealtime() + UNLOCK_TRANSITION_MEMOIZATION_MS;
+ }
+
+ @StashAnimation int animationType = computeTransitionType(changedFlags);
+
+ // Allow re-starting animation if upgrading from default animation type, otherwise
+ // stick with the already started transition.
+ boolean transitionTypeChanged = mAnimator != null && mAnimator.isStarted()
+ && mLastStartedTransitionType == TRANSITION_DEFAULT
+ && animationType != TRANSITION_DEFAULT;
+
+ if (mIsStashed != isStashed || transitionTypeChanged) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.TASKBAR_IN_APP_STATE, String.format(
- "setState: mIsStashed=%b, isStashed=%b, duration=%d",
+ "setState: mIsStashed=%b, isStashed=%b, "
+ + "mAnimationType=%d, animationType=%d, duration=%d",
mIsStashed,
isStashed,
+ mLastStartedTransitionType,
+ animationType,
duration));
}
mIsStashed = isStashed;
- mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
+ mLastStartedTransitionType = animationType;
// This sets mAnimator.
- createAnimToIsStashed(mIsStashed, duration, /* animateBg= */ true, changedFlags);
+ createAnimToIsStashed(mIsStashed, duration, animationType);
return mAnimator;
}
return null;
}
+
+ private @StashAnimation int computeTransitionType(int changedFlags) {
+
+ boolean hotseatHiddenDuringAppLaunch =
+ !mControllers.uiController.isHotseatIconOnTopWhenAligned()
+ && hasAnyFlag(changedFlags, FLAG_IN_APP);
+ if (hotseatHiddenDuringAppLaunch) {
+ // When launching an app from the all-apps drawer, the hotseat is hidden behind the
+ // drawer. In this case, the navbar must just fade in, without a stash transition,
+ // as the taskbar stash animation would otherwise be visible above the all-apps
+ // drawer once the hotseat is detached.
+ return TRANSITION_HANDLE_FADE;
+ }
+
+ boolean isUnlockTransition =
+ SystemClock.elapsedRealtime() < mLastUnlockTransitionTimeout;
+ if (isUnlockTransition) {
+ // When transitioning to unlocked device, the hotseat will already be visible on
+ // the homescreen, thus do not play an un-stash animation.
+ // Keep isUnlockTransition in sync with its counterpart in
+ // TaskbarLauncherStateController#onStateChangeApplied.
+ return TRANSITION_HANDLE_FADE;
+ }
+
+ boolean homeToApp = hasAnyFlag(changedFlags, FLAG_IN_APP) && hasAnyFlag(FLAG_IN_APP);
+ if (homeToApp) {
+ return TRANSITION_HOME_TO_APP;
+ }
+
+ return TRANSITION_DEFAULT;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 065d111..4b18bb6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -54,6 +54,7 @@
private boolean mHasSprungOnceThisGesture;
private @Nullable ValueAnimator mSpringBounce;
private boolean mGestureEnded;
+ private boolean mGestureInProgress;
private boolean mAnimationToHomeRunning;
private final boolean mIsTransientTaskbar;
@@ -123,6 +124,7 @@
private void reset() {
mGestureEnded = false;
+ mGestureInProgress = false;
mHasSprungOnceThisGesture = false;
}
@@ -134,18 +136,24 @@
}
/**
- * Returns true if we will animate to zero before the input duration.
+ * Returns {@code true} if we should reset the animation back to zero.
+ *
+ * Returns {@code false} if there is a gesture in progress, or if we are already animating
+ * to 0 within the specified duration.
*/
- public boolean willAnimateToZeroBefore(long duration) {
+ public boolean shouldResetBackToZero(long duration) {
+ if (mGestureInProgress) {
+ return false;
+ }
if (mSpringBounce != null && mSpringBounce.isRunning()) {
long springDuration = mSpringBounce.getDuration();
long current = mSpringBounce.getCurrentPlayTime();
- return (springDuration - current < duration);
+ return (springDuration - current >= duration);
}
if (mTranslationYForSwipe.isAnimatingToValue(0)) {
- return mTranslationYForSwipe.getRemainingTime() < duration;
+ return mTranslationYForSwipe.getRemainingTime() >= duration;
}
- return false;
+ return true;
}
/**
@@ -188,6 +196,7 @@
mAnimationToHomeRunning = false;
cancelSpringIfExists();
reset();
+ mGestureInProgress = true;
}
/**
* Called when there is movement to move the taskbar.
@@ -211,6 +220,7 @@
mGestureEnded = true;
startSpring();
}
+ mGestureInProgress = false;
}
}
@@ -222,6 +232,7 @@
pw.println(prefix + "\tmHasSprungOnceThisGesture=" + mHasSprungOnceThisGesture);
pw.println(prefix + "\tmAnimationToHomeRunning=" + mAnimationToHomeRunning);
pw.println(prefix + "\tmGestureEnded=" + mGestureEnded);
+ pw.println(prefix + "\tmGestureInProgress=" + mGestureInProgress);
pw.println(prefix + "\tmSpringBounce is running=" + (mSpringBounce != null
&& mSpringBounce.isRunning()));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index b9242b2..1435cb0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -244,7 +244,8 @@
taskAttributes.getIconView().getDrawable(),
taskAttributes.getThumbnailView(),
taskAttributes.getThumbnailView().getThumbnail(),
- null /* intent */);
+ null /* intent */,
+ null /* user */);
return;
}
}
@@ -256,7 +257,8 @@
new BitmapDrawable(info.bitmap.icon),
startingView,
null /* thumbnail */,
- intent);
+ intent,
+ info.user);
}
);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 87df5b0..a3e6814 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -57,7 +57,8 @@
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
-public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable {
+public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
+ DeviceProfile.OnDeviceProfileChangeListener {
private static final String TAG = TaskbarView.class.getSimpleName();
private static final Rect sTmpRect = new Rect();
@@ -92,7 +93,7 @@
private float mTransientTaskbarAllAppsButtonTranslationXOffset;
- private final boolean mShouldTryStartAlign;
+ private boolean mShouldTryStartAlign;
public TaskbarView(@NonNull Context context) {
this(context, null);
@@ -121,8 +122,8 @@
resources.getDimension(isTransientTaskbar
? R.dimen.transient_taskbar_all_apps_button_translation_x_offset
: R.dimen.taskbar_all_apps_button_translation_x_offset);
- mShouldTryStartAlign = mActivityContext.isThreeButtonNav()
- && resources.getBoolean(R.bool.start_align_taskbar);
+
+ onDeviceProfileChanged(mActivityContext.getDeviceProfile());
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
@@ -162,6 +163,23 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ mShouldTryStartAlign = mActivityContext.isThreeButtonNav() && dp.startAlignTaskbar;
+ }
+
+ @Override
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) {
announceForAccessibility(mContext.getString(R.string.taskbar_a11y_shown_title));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4ab093f..6eb409e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -286,7 +286,7 @@
}
private ValueAnimator createRevealAnimForView(View view, boolean isStashed, float newWidth,
- boolean shouldStartAlign) {
+ boolean isQsb) {
Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
int centerY = viewBounds.centerY();
int halfHandleHeight = mStashedHandleHeight / 2;
@@ -295,7 +295,8 @@
final int left;
final int right;
- if (shouldStartAlign) {
+ // QSB will crop from the 'start' whereas all other icons will crop from the center.
+ if (isQsb) {
if (mIsRtl) {
right = viewBounds.right;
left = (int) (right - newWidth);
@@ -311,7 +312,10 @@
}
Rect stashedRect = new Rect(left, top, right, bottom);
- float radius = viewBounds.height() / 2f;
+ // QSB radius can be > 0 since it does not have any UI elements outside of it bounds.
+ float radius = isQsb
+ ? viewBounds.height() / 2f
+ : 0f;
float stashedRadius = stashedRect.height() / 2f;
return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 7f6d78a..623e234 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -18,10 +18,10 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
-import android.view.WindowInsets;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
/** All apps container accessible from taskbar. */
@@ -37,13 +37,11 @@
}
@Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
- return super.onApplyWindowInsets(insets);
- }
-
- @Override
protected View inflateSearchBox() {
+ if (isSearchSupported()) {
+ return super.inflateSearchBox();
+ }
+
// Remove top padding of header, since we do not have any search
mHeader.setPadding(mHeader.getPaddingLeft(), 0,
mHeader.getPaddingRight(), mHeader.getPaddingBottom());
@@ -57,7 +55,7 @@
@Override
protected boolean isSearchSupported() {
- return false;
+ return FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 9db4ddd..d69769a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -112,13 +112,24 @@
DeviceProfile dp = mActivityContext.getDeviceProfile();
setShiftRange(dp.allAppsShiftRange);
- mActivityContext.addOnDeviceProfileChangeListener(this);
setContentBackgroundWithParent(
getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet),
mAppsView.getBottomSheetBackground());
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
protected void onScaleProgressChanged() {
super.onScaleProgressChanged();
mAppsView.setClipChildren(!mIsBackProgressing);
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index ec64128..2c3e1ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -120,7 +120,9 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- return updateInsetsDueToStashing(insets);
+ insets = updateInsetsDueToStashing(insets);
+ setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
+ return insets;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 6475b74..b2b0623 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -641,7 +641,7 @@
PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration());
RectF startingTaskRect = new RectF();
final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(this,
- source.view, null /* thumbnail */, source.drawable, startingTaskRect);
+ source.getView(), null /* thumbnail */, source.getDrawable(), startingTaskRect);
floatingTaskView.setAlpha(1);
floatingTaskView.addStagingAnimation(anim, startingTaskRect, tempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
@@ -745,6 +745,10 @@
@Override
protected void registerBackDispatcher() {
+ if (!FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) {
+ super.registerBackDispatcher();
+ return;
+ }
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new OnBackAnimationCallback() {
@@ -1241,6 +1245,9 @@
Trace.instantForTrack(TRACE_TAG_APP, "QuickstepLauncher#DeviceProfileChanged",
getDeviceProfile().toSmallString());
SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx);
+ if (mTaskbarManager != null) {
+ mTaskbarManager.debugWhyTaskbarNotDestroyed("QuickstepLauncher#onDeviceProfileChanged");
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
index d4944d0..481e200 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
@@ -15,16 +15,20 @@
*/
package com.android.launcher3.uioverrides.flags;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+import com.android.launcher3.config.FeatureFlags.FlagState;
class DebugFlag extends BooleanFlag {
public final String key;
public final String description;
- public final boolean defaultValue;
+ @NonNull
+ public final FlagState defaultValue;
- public DebugFlag(String key, String description, boolean defaultValue, boolean currentValue) {
+ DebugFlag(String key, String description, FlagState defaultValue, boolean currentValue) {
super(currentValue);
this.key = key;
this.defaultValue = defaultValue;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
index 67ea1af..89aba90 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
@@ -39,6 +39,7 @@
import android.os.Bundle;
import android.provider.Settings;
import android.text.Editable;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.ArrayMap;
import android.util.Pair;
@@ -182,9 +183,16 @@
}
private PreferenceCategory newCategory(String title) {
+ return newCategory(title, null);
+ }
+
+ private PreferenceCategory newCategory(String title, @Nullable String summary) {
PreferenceCategory category = new PreferenceCategory(getContext());
category.setOrder(Preference.DEFAULT_ORDER);
category.setTitle(title);
+ if (!TextUtils.isEmpty(summary)) {
+ category.setSummary(summary);
+ }
mPreferenceScreen.addPreference(category);
return category;
}
@@ -195,7 +203,7 @@
}
mFlagTogglerPrefUi = new FlagTogglerPrefUi(this);
- mFlagTogglerPrefUi.applyTo(newCategory("Feature flags"));
+ mFlagTogglerPrefUi.applyTo(newCategory("Feature flags", "Long press to reset"));
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
index 3900ebb..035beb4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
@@ -16,11 +16,13 @@
package com.android.launcher3.uioverrides.flags;
+import com.android.launcher3.config.FeatureFlags.FlagState;
+
class DeviceFlag extends DebugFlag {
private final boolean mDefaultValueInCode;
- public DeviceFlag(String key, String description, boolean defaultValue,
+ DeviceFlag(String key, String description, FlagState defaultValue,
boolean currentValue, boolean defaultValueInCode) {
super(key, description, defaultValue, currentValue);
mDefaultValueInCode = defaultValueInCode;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
index b7fb2ed..9c59361 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
@@ -17,11 +17,15 @@
package com.android.launcher3.uioverrides.flags;
import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME;
+import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG;
import android.content.Context;
import android.content.SharedPreferences;
+import android.os.Handler;
import android.os.Process;
import android.text.Html;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -30,6 +34,7 @@
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreference;
import com.android.launcher3.R;
@@ -59,12 +64,7 @@
@Override
public boolean getBoolean(String key, boolean defaultValue) {
- for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
- if (flag.key.equals(key)) {
- return mSharedPreferences.getBoolean(key, flag.defaultValue);
- }
- }
- return defaultValue;
+ return mSharedPreferences.getBoolean(key, defaultValue);
}
};
@@ -87,18 +87,41 @@
: f1.key.compareToIgnoreCase(f2.key);
});
+ // Ensure that teamfood flag comes on the top
+ if (flags.remove(TEAMFOOD_FLAG)) {
+ flags.add(0, (DebugFlag) TEAMFOOD_FLAG);
+ }
+
// For flag overrides we only want to store when the engineer chose to override the
// flag with a different value than the default. That way, when we flip flags in
// future, engineers will pick up the new value immediately. To accomplish this, we use a
// custom preference data store.
for (DebugFlag flag : flags) {
- SwitchPreference switchPreference = new SwitchPreference(mContext);
+ SwitchPreference switchPreference = new SwitchPreference(mContext) {
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ holder.itemView.setOnLongClickListener(v -> {
+ mSharedPreferences.edit().remove(flag.key).apply();
+ setChecked(getFlagStateFromSharedPrefs(flag));
+ updateSummary(this, flag);
+ updateMenu();
+ return true;
+ });
+ }
+ };
switchPreference.setKey(flag.key);
- switchPreference.setDefaultValue(flag.defaultValue);
+ switchPreference.setDefaultValue(FlagsFactory.getEnabledValue(flag.defaultValue));
switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
switchPreference.setTitle(flag.key);
updateSummary(switchPreference, flag);
switchPreference.setPreferenceDataStore(mDataStore);
+ switchPreference.setOnPreferenceChangeListener((p, v) -> {
+ new Handler().post(() -> updateSummary(switchPreference, flag));
+ return true;
+ });
+
+
parent.addPreference(switchPreference);
}
updateMenu();
@@ -108,10 +131,15 @@
* Updates the summary to show the description and whether the flag overrides the default value.
*/
private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) {
- String onWarning = flag.defaultValue ? "" : "<b>OVERRIDDEN</b><br>";
- String offWarning = flag.defaultValue ? "<b>OVERRIDDEN</b><br>" : "";
- switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.description));
- switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.description));
+ String summary = flag.defaultValue == TEAMFOOD
+ ? "<font color='blue'><b>[TEAMFOOD]</b> </font>" : "";
+ if (mSharedPreferences.contains(flag.key)) {
+ summary += "<font color='red'><b>[OVERRIDDEN]</b> </font>";
+ }
+ if (!TextUtils.isEmpty(summary)) {
+ summary += "<br>";
+ }
+ switchPreference.setSummary(Html.fromHtml(summary + flag.description));
}
private void updateMenu() {
@@ -143,7 +171,8 @@
}
private boolean getFlagStateFromSharedPrefs(DebugFlag flag) {
- return mDataStore.getBoolean(flag.key, flag.defaultValue);
+ boolean defaultValue = FlagsFactory.getEnabledValue(flag.defaultValue);
+ return mDataStore.getBoolean(flag.key, defaultValue);
}
private boolean anyChanged() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index f748e8a..d066abe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -18,6 +18,10 @@
import static android.app.ActivityThread.currentApplication;
+import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE;
+import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
+import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
+import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
@@ -26,8 +30,8 @@
import android.provider.DeviceConfig.Properties;
import android.util.Log;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+import com.android.launcher3.config.FeatureFlags.FlagState;
import com.android.launcher3.config.FeatureFlags.IntFlag;
import com.android.launcher3.util.ScreenOnTracker;
@@ -53,6 +57,9 @@
private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
+ static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag(
+ 0, "LAUNCHER_TEAMFOOD", DISABLED, "Enable this flag to opt-in all team food flags");
+
private final Set<String> mKeySet = new HashSet<>();
private boolean mRestartRequested = false;
@@ -64,35 +71,54 @@
NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged);
}
- /**
- * Creates a new debug flag
- */
- public static BooleanFlag getDebugFlag(
- int bugId, String key, boolean defaultValue, String description) {
- if (Utilities.IS_DEBUG_DEVICE) {
- SharedPreferences prefs = currentApplication()
- .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
- boolean currentValue = prefs.getBoolean(key, defaultValue);
- DebugFlag flag = new DebugFlag(key, description, defaultValue, currentValue);
- sDebugFlags.add(flag);
- return flag;
+ static boolean getEnabledValue(FlagState flagState) {
+ if (IS_DEBUG_DEVICE) {
+ switch (flagState) {
+ case ENABLED:
+ return true;
+ case TEAMFOOD:
+ return TEAMFOOD_FLAG.get();
+ default:
+ return false;
+ }
} else {
- return new BooleanFlag(defaultValue);
+ return flagState == ENABLED;
}
}
/**
- * Creates a new release flag
+ * Creates a new debug flag. Debug flags always take their default value in release builds. On
+ * dogfood builds, they can be manually turned on using the flag toggle UI.
+ */
+ public static BooleanFlag getDebugFlag(
+ int bugId, String key, FlagState flagState, String description) {
+ if (IS_DEBUG_DEVICE) {
+ SharedPreferences prefs = currentApplication()
+ .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
+ boolean defaultValue = getEnabledValue(flagState);
+ boolean currentValue = prefs.getBoolean(key, defaultValue);
+ DebugFlag flag = new DebugFlag(key, description, flagState, currentValue);
+ sDebugFlags.add(flag);
+ return flag;
+ } else {
+ return new BooleanFlag(getEnabledValue(flagState));
+ }
+ }
+
+ /**
+ * Creates a new release flag. Release flags can be rolled out using server configurations and
+ * also allow manual overrides on debug builds.
*/
public static BooleanFlag getReleaseFlag(
- int bugId, String key, boolean defaultValueInCode, String description) {
+ int bugId, String key, FlagState flagState, String description) {
INSTANCE.mKeySet.add(key);
+ boolean defaultValueInCode = getEnabledValue(flagState);
boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode);
- if (Utilities.IS_DEBUG_DEVICE) {
+ if (IS_DEBUG_DEVICE) {
SharedPreferences prefs = currentApplication()
.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
boolean currentValue = prefs.getBoolean(key, defaultValue);
- DebugFlag flag = new DeviceFlag(key, description, defaultValue, currentValue,
+ DebugFlag flag = new DeviceFlag(key, description, flagState, currentValue,
defaultValueInCode);
sDebugFlags.add(flag);
return flag;
@@ -111,7 +137,7 @@
}
static List<DebugFlag> getDebugFlags() {
- if (!Utilities.IS_DEBUG_DEVICE) {
+ if (!IS_DEBUG_DEVICE) {
return Collections.emptyList();
}
synchronized (sDebugFlags) {
@@ -123,7 +149,7 @@
* Dumps the current flags state to the print writer
*/
public static void dump(PrintWriter pw) {
- if (!Utilities.IS_DEBUG_DEVICE) {
+ if (!IS_DEBUG_DEVICE) {
return;
}
pw.println("DeviceFlags:");
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 3f8da56..253341d 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -267,7 +267,8 @@
new RemoteAnimationAdapter(wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY),
- new RemoteTransition(wrapper.toRemoteTransition(), getIApplicationThread()));
+ new RemoteTransition(wrapper.toRemoteTransition(), getIApplicationThread(),
+ "LaunchFromRecents"));
final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(options,
onEndCallback);
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
@@ -405,7 +406,8 @@
getMainThreadHandler(), mAnimationToHomeFactory, true);
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
new RemoteAnimationAdapter(runner, HOME_APPEAR_DURATION, 0),
- new RemoteTransition(runner.toRemoteTransition(), getIApplicationThread()));
+ new RemoteTransition(runner.toRemoteTransition(), getIApplicationThread(),
+ "StartHomeFromRecents"));
startHomeIntentSafely(this, options.toBundle());
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 1f99d6e..73f05c2 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -218,29 +218,15 @@
mUnfoldAnimation = unfoldAnimation;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
- if (mPipAnimationListener != null && mPip != null) {
- setPipAnimationListener(mPipAnimationListener);
- }
- if (mSplitScreenListener != null && mSplitScreen != null) {
- registerSplitScreenListener(mSplitScreenListener);
- }
- if (mStartingWindowListener != null && mStartingWindow != null) {
- setStartingWindowListener(mStartingWindowListener);
- }
- if (mSysuiUnlockAnimationController != null && mLauncherUnlockAnimationController != null) {
- setLauncherUnlockAnimationController(mLauncherUnlockAnimationController);
- }
+ setPipAnimationListener(mPipAnimationListener);
+ registerSplitScreenListener(mSplitScreenListener);
+ setStartingWindowListener(mStartingWindowListener);
+ setLauncherUnlockAnimationController(mLauncherUnlockAnimationController);
new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition);
setupTransactionQueue();
- if (mRecentTasksListener != null && mRecentTasks != null) {
- registerRecentTasksListener(mRecentTasksListener);
- }
- if (mBackAnimation != null && mBackToLauncherCallback != null) {
- setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
- }
- if (unfoldAnimation != null && mUnfoldAnimationListener != null) {
- setUnfoldAnimationListener(mUnfoldAnimationListener);
- }
+ registerRecentTasksListener(mRecentTasksListener);
+ setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
+ setUnfoldAnimationListener(mUnfoldAnimationListener);
}
public void clearProxy() {
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 6e47ff4..2aa0be6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -129,7 +129,8 @@
TaskShortcutFactory.PIN,
TaskShortcutFactory.INSTALL,
TaskShortcutFactory.FREE_FORM,
- TaskShortcutFactory.WELLBEING
+ TaskShortcutFactory.WELLBEING,
+ TaskShortcutFactory.SAVE_APP_PAIR
};
/**
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 255b910..fd7b343 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -40,6 +40,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@@ -63,7 +64,8 @@
import java.util.stream.Collectors;
/**
- * Represents a system shortcut that can be shown for a recent task.
+ * Represents a system shortcut that can be shown for a recent task. Appears as a single entry in
+ * the dropdown menu that shows up when you tap an app icon in Overview.
*/
public interface TaskShortcutFactory {
@Nullable
@@ -122,6 +124,26 @@
}
}
+ /**
+ * A menu item, "Save app pair", that allows the user to preserve the current app combination as
+ * a single persistent icon on the Home screen, allowing for quick split screen initialization.
+ */
+ class SaveAppPairSystemShortcut extends SystemShortcut {
+
+ private final TaskView mTaskView;
+
+ public SaveAppPairSystemShortcut(BaseDraggingActivity target, TaskView taskView) {
+ super(R.drawable.ic_save_app_pair, R.string.save_app_pair, target,
+ taskView.getItemInfo(), taskView);
+ mTaskView = taskView;
+ }
+
+ @Override
+ public void onClick(View view) {
+ // TODO (b/274189428): Call "saveAppPair" function in new AppPairController class
+ }
+ }
+
class FreeformSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
private static final String TAG = "FreeformSystemShortcut";
@@ -257,9 +279,6 @@
final PagedOrientationHandler orientationHandler =
recentsView.getPagedOrientationHandler();
- int[] taskViewTaskIds = taskView.getTaskIds();
- boolean taskViewHasMultipleTasks = taskViewTaskIds[0] != -1 &&
- taskViewTaskIds[1] != -1;
boolean notEnoughTasksToSplit = recentsView.getTaskViewCount() < 2;
boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
boolean isTaskInExpectedScrollPosition =
@@ -267,11 +286,11 @@
boolean isTaskSplitNotSupported = !task.isDockable;
boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode;
- if (taskViewHasMultipleTasks ||
- notEnoughTasksToSplit ||
- isTaskSplitNotSupported ||
- hideForExistingMultiWindow ||
- (isFocusedTask && isTaskInExpectedScrollPosition)) {
+ if (taskView.containsMultipleTasks()
+ || notEnoughTasksToSplit
+ || isTaskSplitNotSupported
+ || hideForExistingMultiWindow
+ || (isFocusedTask && isTaskInExpectedScrollPosition)) {
return null;
}
@@ -283,6 +302,26 @@
}
};
+ TaskShortcutFactory SAVE_APP_PAIR = new TaskShortcutFactory() {
+ @Nullable
+ @Override
+ public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+ TaskIdAttributeContainer taskContainer) {
+ final TaskView taskView = taskContainer.getTaskView();
+
+ if (!FeatureFlags.ENABLE_APP_PAIRS.get() || !taskView.containsMultipleTasks()) {
+ return null;
+ }
+
+ return Collections.singletonList(new SaveAppPairSystemShortcut(activity, taskView));
+ }
+
+ @Override
+ public boolean showForSplitscreen() {
+ return true;
+ }
+ };
+
TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5e14d19..9ca8928 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -22,6 +22,7 @@
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -72,7 +73,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import com.android.app.viewcapture.SettingsAwareViewCapture;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
@@ -514,7 +514,7 @@
if (isHomeAndOverviewSame) {
Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
- .setAction(Intent.ACTION_ALL_APPS);
+ .setAction(INTENT_ACTION_ALL_APPS_TOGGLE);
RemoteAction allAppsAction = new RemoteAction(
Icon.createWithResource(this, R.drawable.ic_apps),
getString(R.string.all_apps_label),
@@ -910,10 +910,6 @@
private void logInputConsumerSelectionReason(
InputConsumer consumer, CompoundString reasonString) {
- if (!FeatureFlags.ENABLE_INPUT_CONSUMER_REASON_LOGGING.get()) {
- ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + consumer.getName());
- return;
- }
ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
.append(consumer.getName())
.append(". reason(s):")
@@ -1235,10 +1231,6 @@
createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
}
mTaskbarManager.dumpLogs("", pw);
-
- if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
- SettingsAwareViewCapture.getInstance(this).dump(pw, fd, this);
- }
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 6dd67de..b76fe5c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -24,6 +24,7 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
+import com.android.quickstep.views.IconView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
@@ -52,21 +53,22 @@
* depending on the state of the surface from which the split was initiated
*/
fun getFirstAnimInitViews(taskViewSupplier: Supplier<TaskView>,
- splitSelectSourceSupplier: Supplier<SplitSelectSource>)
+ splitSelectSourceSupplier: Supplier<SplitSelectSource?>)
: SplitAnimInitProps {
+ val splitSelectSource = splitSelectSourceSupplier.get()
if (!splitSelectStateController.isAnimateCurrentTaskDismissal) {
// Initiating from home
- val splitSelectSource = splitSelectSourceSupplier.get()
- return SplitAnimInitProps(splitSelectSource.view, originalBitmap = null,
+ return SplitAnimInitProps(splitSelectSource!!.view, originalBitmap = null,
splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true,
iconView = null)
} else if (splitSelectStateController.isDismissingFromSplitPair) {
// Initiating split from overview, but on a split pair
val taskView = taskViewSupplier.get()
for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
- if (container.task.key.id == splitSelectStateController.initialTaskId) {
+ if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
+ val drawable = getDrawable(container.iconView, splitSelectSource)
return SplitAnimInitProps(container.thumbnailView,
- container.thumbnailView.thumbnail, container.iconView.drawable!!,
+ container.thumbnailView.thumbnail, drawable!!,
fadeWithThumbnail = true, isStagedTask = true,
iconView = container.iconView
)
@@ -77,14 +79,28 @@
} else {
// Initiating split from overview on fullscreen task TaskView
val taskView = taskViewSupplier.get()
+ val drawable = getDrawable(taskView.iconView, splitSelectSource)
return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
- taskView.iconView.drawable!!, fadeWithThumbnail = true, isStagedTask = true,
+ drawable!!, fadeWithThumbnail = true, isStagedTask = true,
taskView.iconView
)
}
}
/**
+ * Returns the drawable that's provided in iconView, however if that
+ * is null it falls back to the drawable that's in splitSelectSource.
+ * TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen
+ * @return [Drawable]
+ */
+ fun getDrawable(iconView: IconView, splitSelectSource: SplitSelectSource?) : Drawable? {
+ if (iconView.drawable == null && splitSelectSource != null) {
+ return splitSelectSource.drawable
+ }
+ return iconView.drawable
+ }
+
+ /**
* When selecting first app from split pair, second app's thumbnail remains. This animates
* the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying
* it with [TaskThumbnailView]'s splashView. Adds animations to the provided builder.
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 00d6571..11e1fbd 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -89,11 +89,17 @@
private final StateManager mStateManager;
@Nullable
private DepthController mDepthController;
- private @StagePosition int mStagePosition;
+ private @StagePosition int mInitialStagePosition;
private ItemInfo mItemInfo;
+ /** {@link #mInitialTaskIntent} and {@link #mInitialUser} (the user of the Intent) are set
+ * together when split is initiated from an Intent. */
private Intent mInitialTaskIntent;
+ private UserHandle mInitialUser;
private int mInitialTaskId = INVALID_TASK_ID;
+ /** {@link #mSecondTaskIntent} and {@link #mSecondUser} (the user of the Intent) are set
+ * together when split is confirmed with an Intent. */
private Intent mSecondTaskIntent;
+ private UserHandle mSecondUser;
private int mSecondTaskId = INVALID_TASK_ID;
private boolean mRecentsAnimationRunning;
/** If {@code true}, animates the existing task view split placeholder view */
@@ -103,8 +109,6 @@
* split pair task view without wanting to animate current task dismissal overall
*/
private boolean mDismissingFromSplitPair;
- @Nullable
- private UserHandle mUser;
/** If not null, this is the TaskView we want to launch from */
@Nullable
private GroupedTaskView mLaunchingTaskView;
@@ -138,7 +142,7 @@
mInitialTaskId = alreadyRunningTask;
} else {
mInitialTaskIntent = intent;
- mUser = itemInfo.user;
+ mInitialUser = itemInfo.user;
}
setInitialData(stagePosition, splitEvent, itemInfo);
@@ -158,7 +162,7 @@
private void setInitialData(@StagePosition int stagePosition,
StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) {
mItemInfo = itemInfo;
- mStagePosition = stagePosition;
+ mInitialStagePosition = stagePosition;
mSplitEvent = splitEvent;
}
@@ -215,7 +219,7 @@
Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
LogUtils.getShellShareableInstanceId();
launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent,
- mStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
+ mInitialStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
instanceIds.first);
mStatsLogManager.logger()
@@ -232,8 +236,14 @@
mSecondTaskId = task.key.id;
}
- public void setSecondTask(Intent intent) {
+ /**
+ * To be called as soon as user selects the second app (even if animations aren't complete)
+ * @param intent The second intent that will be launched.
+ * @param user The user of that intent.
+ */
+ public void setSecondTask(Intent intent, UserHandle user) {
mSecondTaskIntent = intent;
+ mSecondUser = user;
}
/**
@@ -284,22 +294,24 @@
final RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(taskId1, taskId2, callback);
final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
- ActivityThread.currentActivityThread().getApplicationThread());
+ ActivityThread.currentActivityThread().getApplicationThread(),
+ "LaunchSplitPair");
if (intent1 == null && intent2 == null) {
mSystemUiProxy.startTasks(taskId1, options1.toBundle(), taskId2,
null /* options2 */, stagePosition, splitRatio, remoteTransition,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcut(intent1, options1, taskId2, stagePosition, splitRatio,
- remoteTransition, shellInstanceId);
+ launchIntentOrShortcut(intent1, mInitialUser, options1, taskId2, stagePosition,
+ splitRatio, remoteTransition, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcut(intent2, options1, taskId1,
+ launchIntentOrShortcut(intent2, mSecondUser, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
shellInstanceId);
} else {
- mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(),
- getPendingIntent(intent2), null /* options2 */, stagePosition,
- splitRatio, remoteTransition, shellInstanceId);
+ mSystemUiProxy.startIntents(getPendingIntent(intent1, mInitialUser),
+ options1.toBundle(), getPendingIntent(intent2, mSecondUser),
+ null /* options2 */, stagePosition, splitRatio, remoteTransition,
+ shellInstanceId);
}
} else {
final RemoteSplitLaunchAnimationRunner animationRunner =
@@ -313,61 +325,64 @@
taskId2, null /* options2 */, stagePosition, splitRatio, adapter,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcutLegacy(intent1, options1, taskId2, stagePosition, splitRatio,
- adapter, shellInstanceId);
+ launchIntentOrShortcutLegacy(intent1, mInitialUser, options1, taskId2,
+ stagePosition, splitRatio, adapter, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcutLegacy(intent2, options1, taskId1,
+ launchIntentOrShortcutLegacy(intent2, mSecondUser, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, adapter,
shellInstanceId);
} else {
mSystemUiProxy.startIntentsWithLegacyTransition(
- getPendingIntent(intent1), getShortcutInfo(intent1), options1.toBundle(),
- getPendingIntent(intent2), getShortcutInfo(intent2), null /* options2 */,
- stagePosition, splitRatio, adapter, shellInstanceId);
+ getPendingIntent(intent1, mInitialUser),
+ getShortcutInfo(intent1, mInitialUser), options1.toBundle(),
+ getPendingIntent(intent2, mSecondUser),
+ getShortcutInfo(intent2, mSecondUser), null /* options2 */, stagePosition,
+ splitRatio, adapter, shellInstanceId);
}
}
}
- private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId,
- @StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition,
- @Nullable InstanceId shellInstanceId) {
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
+ private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
+ int taskId, @StagePosition int stagePosition, float splitRatio,
+ RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTask(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, remoteTransition, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTask(getPendingIntent(intent), options1.toBundle(), taskId,
- null /* options2 */, stagePosition, splitRatio, remoteTransition,
- shellInstanceId);
+ mSystemUiProxy.startIntentAndTask(getPendingIntent(intent, user),
+ options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
}
}
- private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId,
- @StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ private void launchIntentOrShortcutLegacy(Intent intent, UserHandle user,
+ ActivityOptions options1, int taskId, @StagePosition int stagePosition,
+ float splitRatio, RemoteAnimationAdapter adapter,
@Nullable InstanceId shellInstanceId) {
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, adapter, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(getPendingIntent(intent),
- options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
- adapter, shellInstanceId);
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(
+ getPendingIntent(intent, user), options1.toBundle(), taskId,
+ null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId);
}
}
- private PendingIntent getPendingIntent(Intent intent) {
- return intent == null ? null : (mUser != null
+ private PendingIntent getPendingIntent(Intent intent, UserHandle user) {
+ return intent == null ? null : (user != null
? PendingIntent.getActivityAsUser(mContext, 0, intent,
- FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, null /* options */, mUser)
+ FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, null /* options */, user)
: PendingIntent.getActivity(mContext, 0, intent,
FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT));
}
public @StagePosition int getActiveSplitStagePosition() {
- return mStagePosition;
+ return mInitialStagePosition;
}
public StatsLogManager.EventEnum getSplitEvent() {
@@ -379,7 +394,7 @@
}
@Nullable
- private ShortcutInfo getShortcutInfo(Intent intent) {
+ private ShortcutInfo getShortcutInfo(Intent intent, UserHandle user) {
if (intent == null || intent.getPackage() == null) {
return null;
}
@@ -391,7 +406,7 @@
try {
final Context context = mContext.createPackageContextAsUser(
- intent.getPackage(), 0 /* flags */, mUser);
+ intent.getPackage(), 0 /* flags */, user);
return new ShortcutInfo.Builder(context, shortcutId).build();
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage());
@@ -521,7 +536,9 @@
mInitialTaskIntent = null;
mSecondTaskId = INVALID_TASK_ID;
mSecondTaskIntent = null;
- mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
+ mInitialUser = null;
+ mSecondUser = null;
+ mInitialStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
mItemInfo = null;
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index e5c74dc..dd10c2d 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.os.UserHandle;
import android.view.View;
import com.android.launcher3.DeviceProfile;
@@ -66,21 +67,24 @@
}
Object tag = view.getTag();
Intent intent;
+ UserHandle user;
BitmapInfo bitmapInfo;
if (tag instanceof WorkspaceItemInfo) {
final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
intent = workspaceItemInfo.intent;
+ user = workspaceItemInfo.user;
bitmapInfo = workspaceItemInfo.bitmap;
} else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
final com.android.launcher3.model.data.AppInfo appInfo =
(com.android.launcher3.model.data.AppInfo) tag;
intent = appInfo.intent;
+ user = appInfo.user;
bitmapInfo = appInfo.bitmap;
} else {
return false;
}
- mController.setSecondTask(intent);
+ mController.setSecondTask(intent, user);
boolean isTablet = mLauncher.getDeviceProfile().isTablet;
SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9a25e9c..cf6ee2d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -185,6 +185,7 @@
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
@@ -801,8 +802,29 @@
// if multi-instance feature is enabled
if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
- // invalidate the current list of tasks if filter changes
- mFilterState.setOnFilterUpdatedListener(this::invalidateTaskList);
+ // invalidate the current list of tasks if filter changes with a fading in/out animation
+ mFilterState.setOnFilterUpdatedListener(() -> {
+ Animator animatorFade = mActivity.getStateManager().createStateElementAnimation(
+ RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 1f, 0f);
+ Animator animatorAppear = mActivity.getStateManager().createStateElementAnimation(
+ RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 0f, 1f);
+ animatorFade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation) {
+ RecentsView.this.invalidateTaskList();
+ updateClearAllFunction();
+ reloadIfNeeded();
+ if (mPendingAnimation != null) {
+ mPendingAnimation.addEndListener(success -> {
+ animatorAppear.start();
+ });
+ } else {
+ animatorAppear.start();
+ }
+ }
+ });
+ animatorFade.start();
+ });
}
// make sure filter is turned off by default
mFilterState.setFilterBy(null);
@@ -821,8 +843,6 @@
*/
public void setAndApplyFilter(@Nullable String packageName) {
mFilterState.setFilterBy(packageName);
- updateClearAllFunction();
- reloadIfNeeded();
}
/**
@@ -4569,11 +4589,13 @@
* is (either the ThumbnailView or the tapped icon).
* @param intent If we are launching a fresh instance of the app, this is the Intent for it. If
* the second app is already running in Recents, this will be null.
+ * @param user If we are launching a fresh instance of the app, this is the UserHandle for it.
+ * If the second app is already running in Recents, this will be null.
* @return true if waiting for confirmation of second app or if split animations are running,
* false otherwise
*/
public boolean confirmSplitSelect(TaskView containerTaskView, Task task, Drawable drawable,
- View secondView, @Nullable Bitmap thumbnail, Intent intent) {
+ View secondView, @Nullable Bitmap thumbnail, Intent intent, UserHandle user) {
if (canLaunchFullscreenTask()) {
return false;
}
@@ -4589,7 +4611,7 @@
}
mSplitSelectStateController.setSecondTask(task);
} else {
- mSplitSelectStateController.setSecondTask(intent);
+ mSplitSelectStateController.setSecondTask(intent, user);
}
RectF secondTaskStartingBounds = new RectF();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index df90583..42589ce 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -761,7 +761,8 @@
if (container != null) {
return getRecentsView().confirmSplitSelect(this, container.getTask(),
container.getIconView().getDrawable(), container.getThumbnailView(),
- container.getThumbnailView().getThumbnail(), /* intent */ null);
+ container.getThumbnailView().getThumbnail(), /* intent */ null,
+ /* user */ null);
}
return false;
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9a65b4f..c39d095 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -186,35 +186,6 @@
actionsView.clickAndDismissScreenshot();
}
- @Test
- @PortraitLandscape
- public void testSplitFromOverview() {
- assumeTrue(!mLauncher.isTablet());
-
- startTestActivity(2);
- startTestActivity(3);
-
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
-
- @Test
- @PortraitLandscape
- public void testSplitFromOverviewForTablet() {
- assumeTrue(mLauncher.isTablet());
-
- startTestActivity(2);
- startTestActivity(3);
-
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- }
-
private int getCurrentOverviewPage(Launcher launcher) {
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index d3fbe93..2ae512a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -15,14 +15,18 @@
*/
package com.android.quickstep;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
import android.content.Intent;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.After;
-import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
@@ -37,13 +41,6 @@
super.setUp();
TaplTestsLauncher3.initialize(this);
- mLauncher.getWorkspace()
- .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
- .switchToAllApps()
- .getAppIcon(CALCULATOR_APP_NAME)
- .dragToHotseat(0);
-
- startAppFast(CALCULATOR_APP_PACKAGE);
if (mLauncher.isTablet()) {
mLauncher.enableBlockTimeout(true);
mLauncher.showTaskbarIfHidden();
@@ -58,14 +55,29 @@
}
@Test
+ @PortraitLandscape
+ public void testSplitFromOverview() {
+ createAndLaunchASplitPair();
+ }
+
+ @Test
// TODO (b/270201357): When this test is proven stable, remove this TestStabilityRule and
- // introduce into presubmit as well.
+ // introduce into presubmit as well.
@TestStabilityRule.Stability(
flavors = TestStabilityRule.LOCAL | TestStabilityRule.PLATFORM_POSTSUBMIT)
@PortraitLandscape
@TaskbarModeSwitch
public void testSplitAppFromHomeWithItself() throws Exception {
- Assume.assumeTrue(mLauncher.isTablet());
+ // Currently only tablets have Taskbar in Overview, so test is only active on tablets
+ assumeTrue(mLauncher.isTablet());
+
+ mLauncher.getWorkspace()
+ .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
+ .switchToAllApps()
+ .getAppIcon(CALCULATOR_APP_NAME)
+ .dragToHotseat(0);
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
mLauncher.goHome()
.switchToAllApps()
@@ -79,4 +91,50 @@
.getAppIcon(CALCULATOR_APP_NAME)
.launchIntoSplitScreen();
}
+
+ @Test
+ public void testSaveAppPairMenuItemExistsOnSplitPair() throws Exception {
+ assumeTrue(FeatureFlags.ENABLE_APP_PAIRS.get());
+
+ createAndLaunchASplitPair();
+
+ assertTrue("Save app pair menu item is missing",
+ mLauncher.goHome()
+ .switchToOverview()
+ .getCurrentTask()
+ .tapMenu()
+ .hasMenuItem("Save app pair"));
+ }
+
+ @Test
+ public void testSaveAppPairMenuItemDoesNotExistOnSingleTask() throws Exception {
+ assumeTrue(FeatureFlags.ENABLE_APP_PAIRS.get());
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
+
+ assertFalse("Save app pair menu item is erroneously appearing on single task",
+ mLauncher.goHome()
+ .switchToOverview()
+ .getCurrentTask()
+ .tapMenu()
+ .hasMenuItem("Save app pair"));
+ }
+
+ private void createAndLaunchASplitPair() {
+ startTestActivity(2);
+ startTestActivity(3);
+
+ if (mLauncher.isTablet()) {
+ mLauncher.goHome().switchToOverview().getOverviewActions()
+ .clickSplit()
+ .getTestActivityTask(2)
+ .open();
+ } else {
+ mLauncher.goHome().switchToOverview().getCurrentTask()
+ .tapMenu()
+ .tapSplitMenuItem()
+ .getCurrentTask()
+ .open();
+ }
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
new file mode 100644
index 0000000..7e07b81
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.quickstep.util
+
+import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.quickstep.views.GroupedTaskView
+import com.android.quickstep.views.IconView
+import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskView
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.systemui.shared.recents.model.Task
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+class SplitAnimationControllerTest {
+
+ private val taskId = 9
+
+ @Mock lateinit var mockSplitSelectStateController: SplitSelectStateController
+ // TaskView
+ @Mock lateinit var mockTaskView: TaskView
+ @Mock lateinit var mockThumbnailView: TaskThumbnailView
+ @Mock lateinit var mockBitmap: Bitmap
+ @Mock lateinit var mockIconView: IconView
+ @Mock lateinit var mockTaskViewDrawable: Drawable
+ // GroupedTaskView
+ @Mock lateinit var mockGroupedTaskView: GroupedTaskView
+ @Mock lateinit var mockTask: Task
+ @Mock lateinit var mockTaskKey: Task.TaskKey
+ @Mock lateinit var mockTaskIdAttributeContainer: TaskIdAttributeContainer
+
+ // SplitSelectSource
+ @Mock lateinit var splitSelectSource: SplitConfigurationOptions.SplitSelectSource
+ @Mock lateinit var mockSplitSourceDrawable: Drawable
+ @Mock lateinit var mockSplitSourceView: View
+
+ lateinit var splitAnimationController: SplitAnimationController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(mockTaskView.thumbnail).thenReturn(mockThumbnailView)
+ whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
+ whenever(mockTaskView.iconView).thenReturn(mockIconView)
+ whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
+
+ whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
+ whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
+
+ splitAnimationController = SplitAnimationController(mockSplitSelectStateController)
+ }
+
+ @Test
+ fun getFirstAnimInitViews_nullTaskViewIcon_useSplitSourceIcon() {
+ // Hit fullscreen task dismissal state
+ whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true)
+ whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false)
+
+ // Missing taskView icon
+ whenever(mockIconView.drawable).thenReturn(null)
+
+ val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps =
+ splitAnimationController.getFirstAnimInitViews(
+ { mockTaskView }, { splitSelectSource })
+
+ assertEquals("Did not fallback to use splitSource icon drawable",
+ mockSplitSourceDrawable, splitAnimInitProps.iconDrawable)
+ }
+
+ @Test
+ fun getFirstAnimInitViews_validTaskViewIcon_useTaskViewIcon() {
+ // Hit fullscreen task dismissal state
+ whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true)
+ whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false)
+
+ val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps =
+ splitAnimationController.getFirstAnimInitViews(
+ { mockTaskView }, { splitSelectSource })
+
+ assertEquals("Did not use taskView icon drawable", mockTaskViewDrawable,
+ splitAnimInitProps.iconDrawable)
+ }
+
+ @Test
+ fun getFirstAnimInitViews_validTaskViewNullSplitSource_useTaskViewIcon() {
+ // Hit fullscreen task dismissal state
+ whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true)
+ whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false)
+
+ // Set split source to null
+ whenever(splitSelectSource.drawable).thenReturn(null)
+
+ val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps =
+ splitAnimationController.getFirstAnimInitViews(
+ { mockTaskView }, { splitSelectSource })
+
+ assertEquals("Did not use taskView icon drawable", mockTaskViewDrawable,
+ splitAnimInitProps.iconDrawable)
+ }
+
+ @Test
+ fun getFirstAnimInitViews_nullTaskViewValidSplitSource_noTaskDismissal() {
+ // Hit initiating split from home
+ whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(false)
+ whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(false)
+
+ val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps =
+ splitAnimationController.getFirstAnimInitViews(
+ { mockTaskView }, { splitSelectSource })
+
+ assertEquals("Did not use splitSource icon drawable", mockSplitSourceDrawable,
+ splitAnimInitProps.iconDrawable)
+ }
+
+ @Test
+ fun getFirstAnimInitViews_nullTaskViewValidSplitSource_groupedTaskView() {
+ // Hit groupedTaskView dismissal
+ whenever(mockSplitSelectStateController.isAnimateCurrentTaskDismissal).thenReturn(true)
+ whenever(mockSplitSelectStateController.isDismissingFromSplitPair).thenReturn(true)
+
+ // Remove icon view from GroupedTaskView
+ whenever(mockIconView.drawable).thenReturn(null)
+
+ whenever(mockTaskIdAttributeContainer.task).thenReturn(mockTask)
+ whenever(mockTaskIdAttributeContainer.iconView).thenReturn(mockIconView)
+ whenever(mockTaskIdAttributeContainer.thumbnailView).thenReturn(mockThumbnailView)
+ whenever(mockTask.getKey()).thenReturn(mockTaskKey)
+ whenever(mockTaskKey.getId()).thenReturn(taskId)
+ whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
+ whenever(mockGroupedTaskView.taskIdAttributeContainers)
+ .thenReturn(Array(1) { mockTaskIdAttributeContainer })
+ val splitAnimInitProps : SplitAnimationController.Companion.SplitAnimInitProps =
+ splitAnimationController.getFirstAnimInitViews(
+ { mockGroupedTaskView }, { splitSelectSource })
+
+ assertEquals("Did not use splitSource icon drawable", mockSplitSourceDrawable,
+ splitAnimInitProps.iconDrawable)
+ }
+}
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_large_screen.xml b/res/drawable/bg_widgets_header_two_pane.xml
similarity index 100%
rename from res/drawable/bg_widgets_header_large_screen.xml
rename to res/drawable/bg_widgets_header_two_pane.xml
diff --git a/res/drawable/page_indicator.xml b/res/drawable/page_indicator.xml
deleted file mode 100644
index c0ccc49..0000000
--- a/res/drawable/page_indicator.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?attr/folderPaginationColor"/>
- <size android:width="@dimen/page_indicator_size" android:height="@dimen/page_indicator_size"/>
-</shape>
\ No newline at end of file
diff --git a/res/layout/page_indicator_dots.xml b/res/layout/page_indicator_dots.xml
index d5fe51e..41844b7 100644
--- a/res/layout/page_indicator_dots.xml
+++ b/res/layout/page_indicator_dots.xml
@@ -14,9 +14,13 @@
limitations under the License.
-->
-<com.android.launcher3.pageindicators.PageIndicatorDots xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.pageindicators.LauncherDotsPageIndicator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/page_indicator"
android:layout_width="match_parent"
android:layout_height="@dimen/workspace_page_indicator_height"
android:layout_gravity="bottom | center_horizontal"
- android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file
+ android:theme="@style/HomeScreenElementTheme"
+ launcher:indicatorDotColor="?attr/workspaceTextColor"
+ />
\ No newline at end of file
diff --git a/res/layout/system_shortcut_content.xml b/res/layout/system_shortcut_content.xml
index ddcef09..3008339 100644
--- a/res/layout/system_shortcut_content.xml
+++ b/res/layout/system_shortcut_content.xml
@@ -22,15 +22,12 @@
android:id="@+id/bubble_text"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
- android:paddingTop="@dimen/bg_popup_item_vertical_padding"
- android:paddingBottom="@dimen/bg_popup_item_vertical_padding"
android:minHeight="@dimen/bg_popup_item_height"
android:textAlignment="viewStart"
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
android:paddingEnd="@dimen/popup_padding_end"
android:textSize="14sp"
- android:minLines="1"
- android:maxLines="2"
+ android:lines="1"
android:ellipsize="end"
android:hyphenationFrequency="full"
android:textColor="@color/system_shortcut_text"
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 5518dc8..35ccc5a 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -53,12 +53,13 @@
android:textColorHighlight="?android:attr/colorControlHighlight"
android:textColorHint="?attr/folderHintColor"/>
- <com.android.launcher3.pageindicators.PageIndicatorDots
+ <com.android.launcher3.pageindicators.LauncherDotsPageIndicator
android:id="@+id/folder_page_indicator"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="1dp"
+ launcher:indicatorDotColor="@color/folder_pagination_color"
/>
</LinearLayout>
diff --git a/res/layout/widgets_list_row_header_two_pane.xml b/res/layout/widgets_list_row_header_two_pane.xml
index 6465db5..c0a6ea8 100644
--- a/res/layout/widgets_list_row_header_two_pane.xml
+++ b/res/layout/widgets_list_row_header_two_pane.xml
@@ -24,7 +24,7 @@
android:focusable="true"
launcher:appIconSize="48dp"
android:descendantFocusability="afterDescendants"
- android:background="@drawable/bg_widgets_header_large_screen" >
+ android:background="@drawable/bg_widgets_header_two_pane" >
<ImageView
android:id="@+id/app_icon"
diff --git a/res/layout/widgets_full_sheet_large_screen.xml b/res/layout/widgets_two_pane_sheet.xml
similarity index 97%
rename from res/layout/widgets_full_sheet_large_screen.xml
rename to res/layout/widgets_two_pane_sheet.xml
index f563baa..4333a80 100644
--- a/res/layout/widgets_full_sheet_large_screen.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -42,7 +42,7 @@
android:layout_marginTop="24dp"
android:gravity="center_horizontal"
android:layout_below="@id/collapse_handle"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:text="@string/widget_button_text"
android:textColor="?android:attr/textColorSecondary"
android:textSize="24sp" />
@@ -76,7 +76,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:visibility="gone" />
</FrameLayout>
@@ -85,8 +85,8 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.67"
- android:layout_marginEnd="@dimen/widget_list_horizontal_margin_large_screen"
- android:paddingTop="@dimen/widget_list_horizontal_margin_large_screen"
+ android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+ android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
android:gravity="end"
android:layout_gravity="end"
android:orientation="horizontal">
@@ -118,7 +118,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal=
- "@dimen/widget_list_horizontal_margin_large_screen"
+ "@dimen/widget_list_horizontal_margin_two_pane"
android:visibility="gone" />
</LinearLayout>
</ScrollView>
diff --git a/res/layout/widgets_full_sheet_paged_view_large_screen.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
similarity index 93%
rename from res/layout/widgets_full_sheet_paged_view_large_screen.xml
rename to res/layout/widgets_two_pane_sheet_paged_view.xml
index f729981..d3a8584 100644
--- a/res/layout/widgets_full_sheet_paged_view_large_screen.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
- android:id="@+id/widgets_full_sheet_paged_view_large_screen"
+ android:id="@+id/widgets_two_pane_sheet_paged_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
@@ -29,7 +29,7 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
launcher:pageIndicator="@+id/tabs" >
<com.android.launcher3.widget.picker.WidgetsRecyclerView
@@ -62,7 +62,7 @@
android:clipToPadding="false"
android:elevation="0.1dp"
android:paddingBottom="8dp"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
launcher:layout_sticky="true">
<include layout="@layout/widgets_search_bar" />
@@ -73,8 +73,10 @@
android:layout_height="match_parent"
android:id="@+id/suggestions_header"
android:layout_marginTop="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
- android:orientation="horizontal">
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:orientation="horizontal"
+ android:background="?android:attr/colorBackground"
+ launcher:layout_sticky="true">
</LinearLayout>
<com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
@@ -84,7 +86,7 @@
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingVertical="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:background="?android:attr/colorBackground"
style="@style/TextHeadline"
launcher:layout_sticky="true">
diff --git a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml b/res/layout/widgets_two_pane_sheet_recyclerview.xml
similarity index 88%
rename from res/layout/widgets_full_sheet_recyclerview_large_screen.xml
rename to res/layout/widgets_two_pane_sheet_recyclerview.xml
index 8fef303..8f2a25e 100644
--- a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
+++ b/res/layout/widgets_two_pane_sheet_recyclerview.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
- android:id="@+id/widgets_full_sheet_recyclerview_large_screen"
+ android:id="@+id/widgets_two_pane_sheet_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
@@ -28,7 +28,7 @@
android:id="@+id/primary_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:clipToPadding="false" />
<!-- SearchAndRecommendationsView without the tab layout as well -->
@@ -47,7 +47,7 @@
android:clipToPadding="false"
android:elevation="0.1dp"
android:paddingBottom="8dp"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
launcher:layout_sticky="true">
<include layout="@layout/widgets_search_bar" />
@@ -58,8 +58,11 @@
android:layout_height="match_parent"
android:id="@+id/suggestions_header"
android:layout_marginTop="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
- android:orientation="horizontal">
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:paddingBottom="16dp"
+ android:orientation="horizontal"
+ android:background="?android:attr/colorBackground"
+ launcher:layout_sticky="true">
</LinearLayout>
</com.android.launcher3.views.StickyHeaderLayout>
</FrameLayout>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 5c4313a..99cbd53 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Tuis"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Verdeelde skerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Raak en hou om \'n legstuk te skuif."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en hou om \'n legstuk te skuif of gebruik gepasmaakte handelinge."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index df4525e..5b10654 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"መነሻ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"የተከፈለ ማያ ገጽ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ምግብርን ለማንቀሳቀስ ይንኩ እና ይያዙ።"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ምግብርን ለማንቀሳቀስ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ ያድርጉ እና ይያዙ።"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 9155e7b..8f55646 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"الشاشة الرئيسية"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"تقسيم الشاشة"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index dc7ed51..2378f23 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"গৃহ স্ক্ৰীন"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"বিভাজিত স্ক্ৰীন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ৱিজেট স্থানান্তৰ কৰিবলৈ টিপি ধৰি ৰাখক।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"কোনো ৱিজেট স্থানান্তৰ কৰিবলৈ দুবাৰ টিপি ধৰি ৰাখক অথবা কাষ্টম কাৰ্য ব্যৱহাৰ কৰক।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 6b1d484..c24b9a5 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Əsas səhifə"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekran bölünməsi"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidceti daşımaq üçün toxunub saxlayın."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidceti daşımaq üçün iki dəfə toxunub saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 4e3ec96..197b3b0 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite radi pomeranja vidžeta."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da biste pomerali vidžet ili koristite prilagođene radnje."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 05d58f7..cff40b6 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Галоўны экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Падзелены экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Націсніце і ўтрымлівайце віджэт для перамяшчэння."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Дакраніцеся двойчы і ўтрымлівайце, каб перамясціць віджэт або выкарыстоўваць спецыяльныя дзеянні."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b847083..4d94341 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Начален екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Докоснете и задръжте за преместване на приспособление"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Докоснете двукратно и задръжте за преместване на приспособление или използвайте персонал. действия."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 9351f9b..d277a3a 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"হোম"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"স্প্লিট স্ক্রিন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"কোনও উইজেট সরাতে সেটি টাচ করে ধরে রাখুন।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"একটি উইজেট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 6ce2412..45fb7f1 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da pomjerite vidžet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da pomjerite vidžet ili da koristite prilagođene radnje."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index d5eeec5..be80552 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Inici"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Fes doble toc i mantén premut per moure un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Fes doble toc i mantén premut per moure un widget o per utilitzar accions personalitzades."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 9e4faeb..3402b75 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Domů"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělená obrazovka"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget přesunete klepnutím a podržením."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 26185c7..b8aa02f 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Startskærm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Opdel skærm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Hold en widget nede for at flytte den."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryk to gange, og hold en widget nede for at flytte den eller bruge tilpassede handlinger."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 1fba8e7..199bf54 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Startbildschirm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Geteilter Bildschirm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets berühren und halten"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 34556c0..31fa51e 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Αρχική οθόνη"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Διαχωρισμός οθόνης"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Πατήστε παρατετ. για μετακίνηση γραφ. στοιχείου."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Πατήστε δύο φορές παρατεταμένα για μετακίνηση γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 02f3396..c7b55d7 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index a36f39a..7a4e094 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch & hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 02f3396..c7b55d7 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 02f3396..c7b55d7 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 9719a96..5324bdf 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch & hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 48c422c..1ff063d 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén presionado para mover un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Presiona dos veces y mantén presionado para mover un widget o usar acciones personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ddde58f..777f4c9 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index be889cc..91d9352 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Avakuva"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jagatud ekraanikuva"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidina teisaldamiseks puudutage ja hoidke all."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidina teisaldamiseks või kohandatud toimingute kasutamiseks topeltpuudutage ja hoidke all."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index c11b9ca..66b8679 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Hasierako pantaila"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Zatitu pantaila"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Eduki sakatuta widget bat mugitzeko."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Sakatu birritan eta eduki sakatuta widget bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index f33f9a6..42d44ee 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"صفحهٔ دونیمه"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"اطلاعات برنامه %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابهجا کردن ابزارک، لمس کنید و نگه دارید."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دوضربه بزنید و نگه دارید."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 9ef7b4b..a6ecd8b 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Etusivu"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jaettu näyttö"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Kosketa pitkään, niin voit siirtää widgetiä."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Kaksoisnapauta ja paina pitkään, niin voit siirtää widgetiä tai käyttää muokattuja toimintoja."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 78470a1..ad60e26 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index b8debf7..983d5a9 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Appuyez de manière prolongée sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Appuyez deux fois et maintenez la pression pour déplacer widget ou utiliser actions personnalisées."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 8ac5b81..c11c514 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén premido un widget para movelo."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dúas veces un widget e manteno premido para movelo ou utiliza accións personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index f6bd907..4b48e7a 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"હોમ સ્ક્રીન"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"સ્ક્રીનને વિભાજિત કરો"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"વિજેટ ખસેડવા ટચ કરીને થોડી વાર દબાવી રાખો."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"વિજેટ ખસેડવા બે વાર ટૅપ કરીને દબાવી રાખો અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરો."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 32ea26f..be64ff1 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उसे दबाकर रखें."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उस पर दो बार टैप करके दबाकर रखें या पसंद के मुताबिक कार्रवाइयां इस्तेमाल करें."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index c6180a9..b757619 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Početni zaslon"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da biste premjestili widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite pritisak da biste premjestili widget ili upotrijebite prilagođene radnje"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index e084231..d499022 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Kezdőképernyő"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Osztott képernyő"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tartsa lenyomva a modult az áthelyezéshez."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Modul áthelyezéséhez koppintson duplán, tartsa nyomva az ujját, vagy használjon egyéni műveleteket."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index fd75fb2..6881661 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Հպեք և պահեք՝ վիջեթ տեղափոխելու համար։"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Կրկնակի հպեք և պահեք՝ վիջեթ տեղափոխելու համար, կամ օգտվեք հատուկ գործողություններից։"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 4a6a225..beff9ea 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Layar utama"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Layar terpisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh lama untuk memindahkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketuk dua kali & tahan untuk memindahkan widget atau gunakan tindakan khusus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index f7824dd..29b11aa 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Heim"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skipta skjá"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Haltu fingri á græju til að færa hana."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ýttu tvisvar og haltu fingri á græju til að færa hana eða notaðu sérsniðnar aðgerðir."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 06d86fe..519cd5c 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Schermo diviso"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tocca e tieni premuto per spostare un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tocca due volte e tieni premuto per spostare un widget o per usare le azioni personalizzate."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 07f325b..ca3230c 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"בית"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 471b523..2948525 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ホーム"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割画面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"長押ししてウィジェットを移動させます。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ウィジェットをダブルタップして長押ししながら移動するか、カスタム操作を使用してください。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 750edce..9937836 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"მთავარი გვერდი"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ეკრანის გაყოფა"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ორმაგი შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index f0bfaef..a1730eb 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Негізгі экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлу"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетті жылжыту үшін басып тұрыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетті жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 3e87275..b993eaa 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"អេក្រង់ដើម"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"មុខងារបំបែកអេក្រង់"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធីសម្រាប់ %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ចុចឱ្យជាប់ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក។"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ចុចពីរដង រួចសង្កត់ឱ្យជាប់ ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក ឬប្រើសកម្មភាពតាមបំណង។"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 7237e4e..06af44c 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ವಿಜೆಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ವಿಜೆಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 8fe07c4..29933e1 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"홈"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"화면 분할"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"길게 터치하여 위젯을 이동하세요."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"두 번 탭한 다음 길게 터치하여 위젯을 이동하거나 맞춤 작업을 사용하세요."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 149c2c1..ecae23a 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Башкы экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетти кое бербей басып туруп жылдырыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетти жылдыруу үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 74f4e85..7158916 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ໂຮມສະກຣີນ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ແບ່ງໜ້າຈໍ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ແຕະຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ ຫຼື ໃຊ້ຄຳສັ່ງກຳນົດເອງ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index e251fd0..81164bd 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Pagrindinis"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Išskaidyto ekrano režimas"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dukart pal. ir palaik., kad perkeltumėte valdiklį."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dukart palieskite ir palaikykite, kad perkeltumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 89a5423..e8e25b8 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Sākums"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Sadalīt ekrānu"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Lai pārvietotu logrīku, pieskarieties un turiet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Lai pārvietotu logrīku, uz tā veiciet dubultskārienu un turiet. Varat arī veikt pielāgotas darbības."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 9859c8e..1b95dcf 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Почетен екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Поделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Допрете и задржете за да преместите виџет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Допрете двапати и задржете за да преместите виџет или користете приспособени дејства."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 0af89d3..ab04493 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ഹോം"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"സ്ക്രീൻ വിഭജന മോഡ്"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"വിജറ്റ് നീക്കാൻ സ്പർശിച്ച് പിടിക്കുക."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"വിജറ്റ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യൂ, ഹോൾഡ് ചെയ്യൂ അല്ലെങ്കിൽ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കൂ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index f535bce..511718c 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Нүүр"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Дэлгэцийг хуваах"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетийг зөөх бол хүрээд, удаан дарна уу."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетийг зөөх эсвэл захиалгат үйлдлийг ашиглахын тулд хоёр товшоод, удаан дарна уу."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index ec197d2..893d041 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"विजेट हलवण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"विजेट हलवण्यासाठी किंवा कस्टम कृती वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index bc90305..55befdd 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Rumah"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skrin pisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh & tahan untuk menggerakkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketik dua kali & tahan untuk menggerakkan widget atau menggunakan tindakan tersuai."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 102ddbc..ccdb08e 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ပင်မစာမျက်နှာ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ဝိဂျက်ကို ရွှေ့ရန် တို့ပြီး ဖိထားပါ။"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ဝိဂျက်ကို ရွှေ့ရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c78425a..bb05261 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Startskjerm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delt skjerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Trykk og hold for å flytte en modul."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dobbelttrykk og hold inne for å flytte en modul eller bruke tilpassede handlinger."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index b8ddced..3547557 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रिन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"कुनै विजेट सार्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"कुनै विजेट सार्न वा आफ्नो रोजाइका कारबाही प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index f331361..3b85b88 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -26,4 +26,6 @@
<color name="home_settings_track_off_color">@android:color/system_neutral1_700</color>
<color name="all_apps_button_color">@android:color/system_neutral2_200</color>
+
+ <color name="folder_pagination_color">@android:color/system_accent2_100</color>
</resources>
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 17fe419..ee27d99 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -18,4 +18,6 @@
<resources>
<color name="all_apps_button_color">#BFC8CC</color>
+ <color name="folder_pagination_color">#ffbfebe3</color>
+
</resources>
\ No newline at end of file
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index f167111..f4c1017 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Startscherm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gesplitst scherm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tik en houd vast om een widget te verplaatsen."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en houd vast om een widget te verplaatsen of aangepaste acties te gebruiken."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index b9b69ae..52560c1 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ହୋମ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ସ୍କ୍ରିନକୁ ସ୍ପ୍ଲିଟ୍ କରନ୍ତୁ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index a559c47..0f65479 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ਮੁੱਖ ਪੰਨਾ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ਕਿਸੇ ਵਿਜੇਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ਵਿਜੇਟ ਲਿਜਾਉਣ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰਕੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 19de527..d8645f0 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Ekran główny"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podziel ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Naciśnij i przytrzymaj, aby przenieść widżet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Naciśnij dwukrotnie i przytrzymaj, aby przenieść widżet lub użyć działań niestandardowych."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 73caaa7..e74feac 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Página inicial"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecrã dividido"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque sem soltar para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes sem soltar para mover um widget ou utilizar ações personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 9cffd85..4373c06 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Início"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Tela dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque e pressione para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes e mantenha a tela pressionada para mover um widget ou usar ações personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 983bb42..295809d 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Pagina de pornire"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecran împărțit"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Atinge și ține apăsat pentru a muta un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Atinge de două ori și ține apăsat pentru a muta un widget sau folosește acțiuni personalizate."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b3dd441..d2dd2d6 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Главный экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Чтобы переместить виджет, нажмите на него и удерживайте"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Чтобы использовать специальные действия или перенести виджет, нажмите на него дважды и удерживайте."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index e6e067b..bde8ca8 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"මුල් පිටුව"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"බෙදුම් තිරය"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"විජට් එකක් ගෙන යාමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"විජට් එකක් ගෙන යාමට හෝ අභිරුචි ක්රියා භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 1fdd277..3bcc7a2 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Domov"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdeliť obrazovku"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 345e25a..b5d3eb1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Začetni zaslon"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Razdeljen zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržite pripomoček, da ga premaknete."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvakrat se dotaknite pripomočka in ga pridržite, da ga premaknete, ali pa uporabite dejanja po meri."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index b590455..02169c8 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Ekrani bazë"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekrani i ndarë"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Prek dhe mbaj shtypur një miniaplikacion për ta zhvendosur."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Trokit dy herë dhe mbaje shtypur një miniapliikacion për ta zhvendosur atë ose për të përdorur veprimet e personalizuara."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 7a9e50d..f924fe7 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Почетни екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 5454c66..c5b4ae2 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Startskärm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tryck länge för att flytta en widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryck snabbt två gånger och håll kvar för att flytta en widget eller använda anpassade åtgärder."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index f49256e..f4621a1 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Skrini ya kwanza"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gawa skrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Gusa na ushikilie ili usogeze wijeti."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Gusa mara mbili na ushikilie ili usogeze wijeti au utumie vitendo maalum."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index b89910d..4d0ac38 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -31,7 +31,7 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
- <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
+ <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index b22ee7c..56b9a8c 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"முகப்பு"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"திரைப் பிரிப்பு"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"விட்ஜெட்டை நகர்த்தத் தொட்டுப் பிடிக்கவும்."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"விட்ஜெட்டை நகர்த்த இருமுறை தட்டிப் பிடிக்கவும் அல்லது பிரத்தியேகச் செயல்களைப் பயன்படுத்தவும்."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 274310e..16b5f5a 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"మొదటి ట్యాబ్"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"స్క్రీన్ను విభజించు"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"విడ్జెట్ను తరలించడానికి తాకి & నొక్కి ఉంచండి."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"విడ్జెట్ను తరలించడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కండి & హోల్డ్ చేయి."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 619fee0..45c3914 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"หน้าแรก"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"แบ่งหน้าจอ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"แตะค้างไว้เพื่อย้ายวิดเจ็ต"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"แตะสองครั้งค้างไว้เพื่อย้ายวิดเจ็ตหรือใช้การดำเนินการที่กำหนดเอง"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index c15b6e5..2d43182 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pindutin nang matagal para ilipat ang widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"I-double tap at pindutin nang matagal para ilipat ang widget o gumamit ng mga custom na pagkilos."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 01aa4aa..b886cf2 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Ana ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Bölünmüş ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget\'ı taşımak için dokunup basılı tutun."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Widget\'ı taşımak veya özel işlemleri kullanmak için iki kez dokunup basılı tutun."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8288aa4..5758c75 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Головний екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Розділити екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Натисніть і втримуйте, щоб перемістити віджет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двічі натисніть і втримуйте віджет, щоб перемістити його або виконати інші дії."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 4e09d54..5a5dcc5 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"ہوم"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"اسپلٹ اسکرین"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s کے لیے ایپ کی معلومات"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ویجیٹ منتقل کرنے کے لیے ٹچ کریں اور پکڑ کر رکھیں۔"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ویجیٹ کو منتقل کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کے لیے دوبار تھپتھپائیں اور پکڑ کر رکھیں۔"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 5df3238..5595179 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Bosh ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekranni ikkiga ajratish"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidjetni bosib turgan holatda suring."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -106,7 +108,7 @@
<string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon burilganda"</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">"Yoqilmagan"</string>
+ <string name="notification_dots_desc_off" msgid="1760796511504341095">"Oʻchiq"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirishnomalarga ruxsat berilmagan"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirishnoma belgilarini ko‘rsatish uchun <xliff:g id="NAME">%1$s</xliff:g> ilovasida bildirishnomalarni yoqing"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Sozlamalarni o‘zgartirish"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 054fe47..0c87ff4 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -41,8 +41,7 @@
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
<color name="folder_dot_color">@android:color/system_accent3_100</color>
- <color name="folder_pagination_color_light">@android:color/system_accent1_600</color>
- <color name="folder_pagination_color_dark">@android:color/system_accent2_100</color>
+ <color name="folder_pagination_color">@android:color/system_accent1_600</color>
<color name="home_settings_header_accent">@android:color/system_accent1_600</color>
<color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 43bdf04..32ea78e 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Màn hình chính"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Chia đôi màn hình"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Chạm và giữ để di chuyển một tiện ích."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Nhấn đúp và giữ để di chuyển một tiện ích hoặc sử dụng các thao tác tùy chỉnh."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3e66cb9..2c06691 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"主屏幕"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分屏"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住即可移动微件。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index fac5dc3..d7954de 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割螢幕"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"輕觸並按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"㩒兩下之後㩒住,就可以郁小工具或者用自訂操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 8b96553..30d7860 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割畫面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"輕觸兩下並按住即可移動小工具或使用自訂操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 97fffd5..ba195b2 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -29,6 +29,8 @@
<string name="home_screen" msgid="5629429142036709174">"Ikhaya"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Hlukanisa isikrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
+ <!-- no translation found for save_app_pair (5647523853662686243) -->
+ <skip />
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Thinta uphinde ubambe ukuze uhambise iwijethi."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Thepha kabili uphinde ubambe ukuze uhambise iwijethi noma usebenzise izindlela ezingokwezifiso."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 682153f..82bab56 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -42,7 +42,6 @@
<attr name="popupNotificationDotColor" format="color" />
<attr name="folderDotColor" format="color" />
- <attr name="folderPaginationColor" format="color" />
<attr name="folderPreviewColor" format="color" />
<attr name="folderBackgroundColor" format="color" />
<attr name="folderIconRadius" format="float" />
@@ -405,6 +404,16 @@
<!-- defaults to iconTextSize, if not specified -->
<attr name="iconTextSizeTwoPanelLandscape" format="float" />
+ <!-- If true, used to layout taskbar in 3 button navigation mode. -->
+ <!-- defaults to false if not specified -->
+ <attr name="startAlignTaskbar" format="boolean" />
+ <!-- defaults to startAlignTaskbar, if not specified -->
+ <attr name="startAlignTaskbarLandscape" format="boolean" />
+ <!-- defaults to startAlignTaskbarLandscape, if not specified -->
+ <attr name="startAlignTaskbarTwoPanelLandscape" format="boolean" />
+ <!-- defaults to startAlignTaskbar, if not specified -->
+ <attr name="startAlignTaskbarTwoPanelPortrait" format="boolean" />
+
<!-- If set, this display option is used to determine the default grid -->
<attr name="canBeDefault" format="boolean" />
@@ -491,4 +500,10 @@
<!-- The icon drawable of a widget category. -->
<attr name="sectionDrawable" format="reference" />
</declare-styleable>
+
+ <!-- Attributes for PagedIndicator -->
+ <declare-styleable name="PagedIndicator">
+ <!-- Color used to draw dots -->
+ <attr name="indicatorDotColor" format="color" />
+ </declare-styleable>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 8788557..1ef918d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -67,8 +67,7 @@
<color name="folder_preview_dark">#464746</color>
<color name="folder_dot_color">?attr/colorPrimary</color>
- <color name="folder_pagination_color_light">#ff006c5f</color>
- <color name="folder_pagination_color_dark">#ffbfebe3</color>
+ <color name="folder_pagination_color">#ff006c5f</color>
<color name="text_color_primary_dark">#FFFFFFFF</color>
<color name="text_color_secondary_dark">#FFFFFFFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 68e668f..923883b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -193,7 +193,7 @@
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
<dimen name="widget_list_entry_spacing">2dp</dimen>
<dimen name="widget_list_horizontal_margin">16dp</dimen>
- <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
+ <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f2fb8f5..7552b22 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -42,6 +42,9 @@
<string name="recent_task_option_split_screen">Split screen</string>
<string name="split_app_info_accessibility">App info for %1$s</string>
+ <!-- App pairs -->
+ <string name="save_app_pair">Save app pair</string>
+
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
<string name="long_press_widget_to_add">Touch & hold to move a widget.</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5dc4f0a..517bb87 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -50,7 +50,6 @@
<item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
<item name="folderDotColor">@color/folder_dot_color</item>
- <item name="folderPaginationColor">@color/folder_pagination_color_light</item>
<item name="folderPreviewColor">@color/folder_preview_light</item>
<item name="folderBackgroundColor">@color/folder_background_light</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
@@ -104,7 +103,6 @@
<item name="popupShadeThird">@color/popup_shade_third_dark</item>
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
<item name="folderDotColor">@color/folder_dot_color</item>
- <item name="folderPaginationColor">@color/folder_pagination_color_dark</item>
<item name="folderPreviewColor">@color/folder_preview_dark</item>
<item name="folderBackgroundColor">@color/folder_background_dark</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 27c41c2..2083726 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -24,30 +24,29 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Patterns;
import android.util.Xml;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.icons.GraphicsUtils;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.qsb.QsbContainerView;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Partner;
@@ -58,6 +57,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
@@ -135,6 +135,7 @@
private static final String ATTR_TITLE = "title";
private static final String ATTR_TITLE_TEXT = "titleText";
private static final String ATTR_SCREEN = "screen";
+ private static final String ATTR_SHORTCUT_ID = "shortcutId";
// x and y can be specified as negative integers, in which case -1 represents the
// last row / column, -2 represents the second last, and so on.
@@ -143,8 +144,6 @@
private static final String ATTR_SPAN_X = "spanX";
private static final String ATTR_SPAN_Y = "spanY";
- private static final String ATTR_ICON = "icon";
- private static final String ATTR_URL = "url";
// Attrs for "Include"
private static final String ATTR_WORKSPACE = "workspace";
@@ -156,10 +155,8 @@
private static final String HOTSEAT_CONTAINER_NAME =
Favorites.containerToString(Favorites.CONTAINER_HOTSEAT);
- @Thunk
- final Context mContext;
- @Thunk
- final LauncherWidgetHolder mAppWidgetHolder;
+ protected final Context mContext;
+ protected final LauncherWidgetHolder mAppWidgetHolder;
protected final LayoutParserCallback mCallback;
protected final PackageManager mPackageManager;
@@ -308,7 +305,15 @@
mValues.put(Favorites.SPANY, 1);
mValues.put(Favorites._ID, id);
- maybeReplaceShortcut(intent.getComponent().getPackageName(), type);
+ if (type == ITEM_TYPE_APPLICATION) {
+ ComponentName cn = intent.getComponent();
+ if (cn != null && mActivityOverride.containsKey(cn.getPackageName())) {
+ LauncherActivityInfo replacementInfo = mActivityOverride.get(cn.getPackageName());
+ mValues.put(Favorites.PROFILE_ID, UserCache.INSTANCE.get(mContext)
+ .getSerialNumberForUser(replacementInfo.getUser()));
+ mValues.put(Favorites.INTENT, AppInfo.makeLaunchIntent(replacementInfo).toUri(0));
+ }
+ }
if (mCallback.insertAndCheck(mDb, mValues) < 0) {
return -1;
@@ -321,7 +326,7 @@
ArrayMap<String, TagParser> parsers = new ArrayMap<>();
parsers.put(TAG_APP_ICON, new AppShortcutParser());
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -332,7 +337,7 @@
parsers.put(TAG_FOLDER, new FolderParser());
parsers.put(TAG_APPWIDGET, new PendingWidgetParser());
parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -420,59 +425,27 @@
}
/**
- * Parses a web shortcut. Required attributes url, icon, title
+ * Parses a deep shortcut. Required attributes packageName and shortcutId
*/
protected class ShortcutParser implements TagParser {
- private final Resources mIconRes;
-
- public ShortcutParser(Resources iconRes) {
- mIconRes = iconRes;
- }
-
@Override
public int parseAndAdd(XmlPullParser parser) {
- final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
- final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
+ final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
+ final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID);
- if (titleResId == 0 || iconId == 0) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut");
- return -1;
+ try {
+ LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+ launcherApps.pinShortcuts(packageName, Collections.singletonList(shortcutId),
+ Process.myUserHandle());
+ Intent intent = ShortcutKey.makeIntent(shortcutId, packageName);
+ mValues.put(Favorites.RESTORED, WorkspaceItemInfo.FLAG_RESTORED_ICON);
+ return addShortcut(null, intent, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to pin the shortcut for shortcut id = " + shortcutId
+ + " and package name = " + packageName, e);
}
-
- final Intent intent = parseIntent(parser);
- if (intent == null) {
- return -1;
- }
-
- Drawable icon = mIconRes.getDrawable(iconId);
- if (icon == null) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut, can't load icon");
- return -1;
- }
-
- // Auto installs should always support the current platform version.
- LauncherIcons li = LauncherIcons.obtain(mContext);
- mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(
- li.createBadgedIconBitmap(icon).icon));
- li.recycle();
-
- mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
- mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
-
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- return addShortcut(mSourceRes.getString(titleResId),
- intent, Favorites.ITEM_TYPE_SHORTCUT);
- }
-
- protected Intent parseIntent(XmlPullParser parser) {
- final String url = getAttributeValue(parser, ATTR_URL);
- if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
- return null;
- }
- return new Intent(Intent.ACTION_VIEW, null).setData(Uri.parse(url));
+ return -1;
}
}
@@ -728,12 +701,4 @@
to.put(key, from.getAsInteger(key));
}
- private void maybeReplaceShortcut(String packageName, int type) {
- if (mActivityOverride.containsKey(packageName) && type == ITEM_TYPE_APPLICATION) {
- LauncherActivityInfo replacementInfo = mActivityOverride.get(packageName);
- mValues.put(Favorites.PROFILE_ID, UserCache.INSTANCE.get(mContext)
- .getSerialNumberForUser(replacementInfo.getUser()));
- mValues.put(Favorites.INTENT, AppInfo.makeLaunchIntent(replacementInfo).toUri(0));
- }
- }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 53d9281..961c254 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -872,7 +872,9 @@
if (mIcon instanceof PreloadIconDrawable) {
preloadIconDrawable = (PreloadIconDrawable) mIcon;
preloadIconDrawable.setLevel(progressLevel);
- preloadIconDrawable.setIsDisabled(!info.isAppStartable());
+ preloadIconDrawable.setIsDisabled(ENABLE_DOWNLOAD_APP_UX_V2.get()
+ ? info.getProgressLevel() == 0
+ : !info.isAppStartable());
} else {
preloadIconDrawable = makePreloadIcon();
setIcon(preloadIconDrawable);
@@ -897,8 +899,9 @@
final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
- preloadDrawable.setIsDisabled(!info.isAppStartable());
-
+ preloadDrawable.setIsDisabled(ENABLE_DOWNLOAD_APP_UX_V2.get()
+ ? info.getProgressLevel() == 0
+ : !info.isAppStartable());
return preloadDrawable;
}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index c69ae4d..c748693 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -6,19 +6,15 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
-import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -28,7 +24,6 @@
import java.io.IOException;
import java.net.URISyntaxException;
-import java.util.Collections;
import java.util.List;
/**
@@ -49,8 +44,6 @@
private static final String ATTR_CONTAINER = "container";
private static final String ATTR_SCREEN = "screen";
private static final String ATTR_FOLDER_ITEMS = "folderItems";
- private static final String ATTR_SHORTCUT_ID = "shortcutId";
- private static final String ATTR_PACKAGE_NAME = "packageName";
public static final String RES_PARTNER_FOLDER = "partner_folder";
public static final String RES_PARTNER_DEFAULT_LAYOUT = "partner_default_layout";
@@ -66,14 +59,9 @@
@Override
protected ArrayMap<String, TagParser> getFolderElementsMap() {
- return getFolderElementsMap(mSourceRes);
- }
-
- @Thunk
- ArrayMap<String, TagParser> getFolderElementsMap(Resources res) {
ArrayMap<String, TagParser> parsers = new ArrayMap<>();
parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
- parsers.put(TAG_SHORTCUT, new UriShortcutParser(res));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -83,7 +71,7 @@
parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
parsers.put(TAG_APPWIDGET, new AppWidgetParser());
parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser());
- parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
parsers.put(TAG_RESOLVE, new ResolveParser());
parsers.put(TAG_FOLDER, new MyFolderParser());
parsers.put(TAG_PARTNER_FOLDER, new PartnerFolderParser());
@@ -190,57 +178,6 @@
}
/**
- * Shortcut parser which allows any uri and not just web urls.
- */
- public class UriShortcutParser extends ShortcutParser {
-
- public UriShortcutParser(Resources iconRes) {
- super(iconRes);
- }
-
- @Override
- public int parseAndAdd(XmlPullParser parser) {
- final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID);
- if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(shortcutId)) {
- return parseAndAddDeepShortcut(shortcutId, packageName);
- }
- return super.parseAndAdd(parser);
- }
-
- /**
- * This method parses and adds a deep shortcut.
- * @return item id if the shortcut is successfully added else -1
- */
- private int parseAndAddDeepShortcut(String shortcutId, String packageName) {
- try {
- LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
- launcherApps.pinShortcuts(packageName, Collections.singletonList(shortcutId),
- Process.myUserHandle());
- Intent intent = ShortcutKey.makeIntent(shortcutId, packageName);
- mValues.put(Favorites.RESTORED, WorkspaceItemInfo.FLAG_RESTORED_ICON);
- return addShortcut(null, intent, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
- } catch (Exception e) {
- Log.e(TAG, "Unable to pin the shortcut for shortcut id = " + shortcutId
- + " and package name = " + packageName);
- }
- return -1;
- }
-
- @Override
- protected Intent parseIntent(XmlPullParser parser) {
- String uri = null;
- try {
- uri = getAttributeValue(parser, ATTR_URI);
- return Intent.parseUri(uri, 0);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Shortcut has malformed uri: " + uri);
- return null; // Oh well
- }
- }
- }
-
- /**
* Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
*/
public class ResolveParser implements TagParser {
@@ -284,11 +221,9 @@
if (partner != null) {
final int resId = partner.getXmlResId(RES_PARTNER_FOLDER);
if (resId != 0) {
- final Resources partnerRes = partner.getResources();
- final XmlPullParser partnerParser = partnerRes.getXml(resId);
+ final XmlPullParser partnerParser = partner.getResources().getXml(resId);
beginDocument(partnerParser, TAG_FOLDER);
-
- FolderParser folderParser = new FolderParser(getFolderElementsMap(partnerRes));
+ FolderParser folderParser = new FolderParser(getFolderElementsMap());
return folderParser.parseAndAdd(partnerParser);
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index fcb220e..86c9f16 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -267,6 +267,8 @@
public final int stashedTaskbarHeight;
public final int taskbarBottomMargin;
public final int taskbarIconSize;
+ // If true, used to layout taskbar in 3 button navigation mode.
+ public final boolean startAlignTaskbar;
// DragController
public int flingToDeleteThresholdVelocity;
@@ -338,12 +340,14 @@
res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_height);
taskbarBottomMargin =
res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+ startAlignTaskbar = false;
} else {
taskbarIconSize = pxFromDp(ResourcesCompat.getFloat(res, R.dimen.taskbar_icon_size),
mMetrics);
taskbarHeight = res.getDimensionPixelSize(R.dimen.taskbar_size);
stashedTaskbarHeight = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
taskbarBottomMargin = 0;
+ startAlignTaskbar = inv.startAlignTaskbar[mTypeIndex];
}
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 0c19e4b..4c34648 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -41,7 +41,6 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TypedValue;
import android.util.Xml;
import android.view.Display;
@@ -58,11 +57,9 @@
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
-import com.android.launcher3.util.Themes;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -76,6 +73,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
public class InvariantDeviceProfile {
@@ -151,7 +149,7 @@
public float[] transientTaskbarIconSize;
- private SparseArray<TypedValue> mExtraAttrs;
+ public boolean[] startAlignTaskbar;
/**
* Number of icons inside the hotseat area.
@@ -360,8 +358,6 @@
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
- mExtraAttrs = closestProfile.extraAttrs;
-
iconSize = displayOption.iconSizes;
float maxIconSize = iconSize[0];
for (int i = 1; i < iconSize.length; i++) {
@@ -400,6 +396,8 @@
transientTaskbarIconSize = displayOption.transientTaskbarIconSize;
+ startAlignTaskbar = displayOption.startAlignTaskbar;
+
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, metrics);
@@ -495,9 +493,8 @@
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
- GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser),
- deviceType);
- if (gridOption.isEnabled || allowDisabledGrid) {
+ GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
+ if (gridOption.isEnabled(deviceType) || allowDisabledGrid) {
final int displayDepth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG
|| parser.getDepth() > displayDepth)
@@ -519,7 +516,7 @@
if (!TextUtils.isEmpty(gridName)) {
for (DisplayOption option : profiles) {
if (gridName.equals(option.grid.name)
- && (option.grid.isEnabled || allowDisabledGrid)) {
+ && (option.grid.isEnabled(deviceType) || allowDisabledGrid)) {
filteredProfiles.add(option);
}
}
@@ -542,6 +539,16 @@
* @return all the grid options that can be shown on the device
*/
public List<GridOption> parseAllGridOptions(Context context) {
+ return parseAllDefinedGridOptions(context)
+ .stream()
+ .filter(go -> go.isEnabled(deviceType))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * @return all the grid options that can be shown on the device
+ */
+ public static List<GridOption> parseAllDefinedGridOptions(Context context) {
List<GridOption> result = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
@@ -551,11 +558,7 @@
|| parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
- GridOption option =
- new GridOption(context, Xml.asAttributeSet(parser), deviceType);
- if (option.isEnabled) {
- result.add(option);
- }
+ result.add(new GridOption(context, Xml.asAttributeSet(parser)));
}
}
} catch (IOException | XmlPullParserException e) {
@@ -774,7 +777,7 @@
public final int numRows;
public final int numColumns;
public final int numSearchContainerColumns;
- public final boolean isEnabled;
+ public final int deviceCategory;
private final int numFolderRows;
private final int numFolderColumns;
@@ -800,9 +803,7 @@
private final boolean isScalable;
private final int devicePaddingId;
- private final SparseArray<TypedValue> extraAttrs;
-
- public GridOption(Context context, AttributeSet attrs, @DeviceType int deviceType) {
+ public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridDisplayOption);
name = a.getString(R.styleable.GridDisplayOption_name);
@@ -859,16 +860,8 @@
R.styleable.GridDisplayOption_isScalable, false);
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, INVALID_RESOURCE_HANDLE);
-
- int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
+ deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
DEVICE_CATEGORY_ALL);
- isEnabled = (deviceType == TYPE_PHONE
- && ((deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE))
- || (deviceType == TYPE_TABLET
- && ((deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET))
- || (deviceType == TYPE_MULTI_DISPLAY
- && ((deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
- == DEVICE_CATEGORY_MULTI_DISPLAY));
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
DONT_INLINE_QSB);
@@ -884,8 +877,20 @@
== INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE;
a.recycle();
- extraAttrs = Themes.createValueMap(context, attrs,
- IntArray.wrap(R.styleable.GridDisplayOption));
+ }
+
+ public boolean isEnabled(@DeviceType int deviceType) {
+ switch (deviceType) {
+ case TYPE_PHONE:
+ return (deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE;
+ case TYPE_TABLET:
+ return (deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET;
+ case TYPE_MULTI_DISPLAY:
+ return (deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
+ == DEVICE_CATEGORY_MULTI_DISPLAY;
+ default:
+ return false;
+ }
}
}
@@ -914,6 +919,8 @@
private final float[] transientTaskbarIconSize = new float[COUNT_SIZES];
+ private final boolean[] startAlignTaskbar = new boolean[COUNT_SIZES];
+
DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
this.grid = grid;
@@ -1146,6 +1153,18 @@
R.styleable.ProfileDisplayOption_transientTaskbarIconSizeTwoPanelPortrait,
transientTaskbarIconSize[INDEX_DEFAULT]);
+ startAlignTaskbar[INDEX_DEFAULT] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbar, false);
+ startAlignTaskbar[INDEX_LANDSCAPE] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarLandscape,
+ startAlignTaskbar[INDEX_DEFAULT]);
+ startAlignTaskbar[INDEX_TWO_PANEL_LANDSCAPE] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarTwoPanelLandscape,
+ startAlignTaskbar[INDEX_LANDSCAPE]);
+ startAlignTaskbar[INDEX_TWO_PANEL_PORTRAIT] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarTwoPanelPortrait,
+ startAlignTaskbar[INDEX_DEFAULT]);
+
a.recycle();
}
@@ -1168,6 +1187,7 @@
allAppsIconTextSizes[i] = 0;
allAppsBorderSpaces[i] = new PointF();
transientTaskbarIconSize[i] = 0;
+ startAlignTaskbar[i] = false;
}
}
@@ -1212,6 +1232,7 @@
allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y;
transientTaskbarIconSize[i] += p.transientTaskbarIconSize[i];
+ startAlignTaskbar[i] |= p.startAlignTaskbar[i];
}
return this;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2e382c8..8fcc08d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -85,7 +85,6 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
@@ -289,6 +288,9 @@
// Type PendingSplitSelectInfo<Parcelable>
protected static final String PENDING_SPLIT_SELECT_INFO = "launcher.pending_split_select_info";
+ public static final String INTENT_ACTION_ALL_APPS_TOGGLE =
+ "launcher.intent_action_all_apps_toggle";
+
public static final String ON_CREATE_EVT = "Launcher.onCreate";
public static final String ON_START_EVT = "Launcher.onStart";
public static final String ON_RESUME_EVT = "Launcher.onResume";
@@ -1353,10 +1355,6 @@
if (SHOW_DOT_PAGINATION.get()) {
mWorkspace.getPageIndicator().setShouldAutoHide(true);
- mWorkspace.getPageIndicator().setPaintColor(
- Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)
- ? Color.BLACK
- : Color.WHITE);
}
}
@@ -1692,6 +1690,8 @@
handleGestureContract(intent);
} else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
showAllAppsFromIntent(alreadyOnHome);
+ } else if (INTENT_ACTION_ALL_APPS_TOGGLE.equals(intent.getAction())) {
+ toggleAllAppsFromIntent(alreadyOnHome);
} else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) {
showAllAppsWorkTabFromIntent(alreadyOnHome);
}
@@ -1699,6 +1699,14 @@
TraceHelper.INSTANCE.endSection(traceToken);
}
+ protected void toggleAllAppsFromIntent(boolean alreadyOnHome) {
+ if (getStateManager().isInStableState(ALL_APPS)) {
+ getStateManager().goToState(NORMAL, alreadyOnHome);
+ } else {
+ showAllAppsFromIntent(alreadyOnHome);
+ }
+ }
+
protected void showAllAppsFromIntent(boolean alreadyOnHome) {
AbstractFloatingView.closeAllOpenViews(this);
getStateManager().goToState(ALL_APPS, alreadyOnHome);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 62e7ef3..26ad4b5 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -153,8 +153,8 @@
Interpolator workspaceFadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
- propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
- workspacePageIndicatorAlpha, workspaceFadeInterpolator);
+ mLauncher.getWorkspace().getPageIndicator().setAlpha(
+ propertySetter, workspacePageIndicatorAlpha, workspaceFadeInterpolator);
Interpolator hotseatFadeInterpolator = config.getInterpolator(ANIM_HOTSEAT_FADE,
workspaceFadeInterpolator);
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index c3ac53e..b485780 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -184,7 +184,7 @@
this, mActivityContext.getStatsLogManager());
mAH = Arrays.asList(null, null, null);
mNavBarScrimPaint = new Paint();
- mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
+ mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
AllAppsStore.OnUpdateListener onAppsUpdated = this::onAppsUpdated;
if (TestProtocol.sDebugTracing) {
@@ -192,7 +192,6 @@
onAppsUpdated);
}
mAllAppsStore.addUpdateListener(onAppsUpdated);
- mActivityContext.addOnDeviceProfileChangeListener(this);
// This is a focus listener that proxies focus from a view into the list view. This is to
// work around the search box from getting first focus and showing the cursor.
@@ -263,6 +262,18 @@
mSearchUiManager.initializeSearch(this);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
+ }
+
public SearchUiManager getSearchUiManager() {
return mSearchUiManager;
}
@@ -347,16 +358,10 @@
public boolean shouldContainerScroll(MotionEvent ev) {
BaseDragLayer dragLayer = mActivityContext.getDragLayer();
- // IF the MotionEvent is inside the search box, and the container keeps on receiving
- // touch input, container should move down.
- if (dragLayer.isEventOverView(mSearchContainer, ev)) {
- return true;
- }
- // Scroll if not within the container view (e.g. over large-screen scrim).
- if (!dragLayer.isEventOverView(getVisibleContainerView(), ev)) {
- return true;
- }
- if (dragLayer.isEventOverView(mBottomSheetHandleArea, ev)) {
+ // IF the MotionEvent is inside the search box or handle area, and the container keeps on
+ // receiving touch input, container should move down.
+ if (dragLayer.isEventOverView(mSearchContainer, ev)
+ || dragLayer.isEventOverView(mBottomSheetHandleArea, ev)) {
return true;
}
AllAppsRecyclerView rv = getActiveRecyclerView();
@@ -368,10 +373,30 @@
&& dragLayer.isEventOverView(rv.getScrollbar(), ev)) {
return false;
}
+ // Scroll if not within the container view (e.g. over large-screen scrim).
+ if (!dragLayer.isEventOverView(getVisibleContainerView(), ev)) {
+ return true;
+ }
return rv.shouldContainerScroll(ev, dragLayer);
}
+ /**
+ * Resets the UI to be ready for fresh interactions in the future. Exits search and returns to
+ * A-Z apps list.
+ *
+ * @param animate Whether to animate the header during the reset (e.g. switching profile tabs).
+ **/
public void reset(boolean animate) {
+ reset(animate, true);
+ }
+
+ /**
+ * Resets the UI to be ready for fresh interactions in the future.
+ *
+ * @param animate Whether to animate the header during the reset (e.g. switching profile tabs).
+ * @param exitSearch Whether to force exit the search state and return to A-Z apps list.
+ **/
+ public void reset(boolean animate, boolean exitSearch) {
for (int i = 0; i < mAH.size(); i++) {
if (mAH.get(i).mRecyclerView != null) {
mAH.get(i).mRecyclerView.scrollToTop();
@@ -385,10 +410,12 @@
}
// Reset the base recycler view after transitioning home.
updateHeaderScroll(0);
- // Reset the search bar after transitioning home.
- mSearchUiManager.resetSearch();
- // Animate to A-Z with 0 time to reset the animation with proper state management.
- animateToSearchState(false, 0);
+ if (exitSearch) {
+ // Reset the search bar after transitioning home.
+ mSearchUiManager.resetSearch();
+ // Animate to A-Z with 0 time to reset the animation with proper state management.
+ animateToSearchState(false, 0);
+ }
}
@Override
@@ -432,7 +459,7 @@
}
// Header keeps track of active recycler view to properly render header protection.
mHeader.setActiveRV(currentActivePage);
- reset(true /* animate */);
+ reset(true /* animate */, !isSearching() /* exitSearch */);
mWorkManager.onActivePageChanged(currentActivePage);
}
@@ -453,12 +480,6 @@
return;
}
- if (isSearching()) {
- mUsingTabs = showTabs;
- mWorkManager.detachWorkModeSwitch();
- return;
- }
-
if (!FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
getSearchRecyclerView().removeItemDecoration(decoration);
@@ -523,7 +544,7 @@
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.SEARCH).mRecyclerView);
}
- protected View replaceAppsRVContainer(boolean showTabs) {
+ private void replaceAppsRVContainer(boolean showTabs) {
for (int i = AdapterHolder.MAIN; i <= AdapterHolder.WORK; i++) {
AdapterHolder adapterHolder = mAH.get(i);
if (adapterHolder.mRecyclerView != null) {
@@ -577,7 +598,7 @@
layoutBelowSearchContainer(getSearchRecyclerView(), /* tabs= */ false);
}
- return rvContainer;
+ updateSearchResultsVisibility();
}
void setupHeader() {
@@ -810,6 +831,12 @@
}
}
updateBackground(dp);
+
+ int navBarScrimColor = Themes.getNavBarScrimColor(mActivityContext);
+ if (mNavBarScrimPaint.getColor() != navBarScrimColor) {
+ mNavBarScrimPaint.setColor(navBarScrimColor);
+ invalidate();
+ }
}
protected void updateBackground(DeviceProfile deviceProfile) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 85d7a05..4d1006a 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -521,7 +521,6 @@
*/
private void onProgressAnimationEnd() {
if (Float.compare(mProgress, 1f) == 0) {
- mAppsView.reset(false /* animate */);
if (mShouldControlKeyboard) {
mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index b3ea3ab..330d13d 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -228,7 +228,7 @@
updateExpectedHeight();
mTabsHidden = tabsHidden;
- mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
+ maybeSetTabVisibility(VISIBLE);
mMainRV = mainRV;
mWorkRV = workRV;
mSearchRV = searchRV;
@@ -250,6 +250,12 @@
rvType == AdapterHolder.MAIN ? mMainRV
: rvType == AdapterHolder.WORK ? mWorkRV : mSearchRV;
mCurrentRV.addOnScrollListener(mOnScrollListener);
+ maybeSetTabVisibility(rvType == AdapterHolder.SEARCH ? GONE : VISIBLE);
+ }
+
+ /** Update tab visibility to the given state, only if tabs are active (work profile exists). */
+ void maybeSetTabVisibility(int visibility) {
+ mTabLayout.setVisibility(mTabsHidden ? GONE : visibility);
}
private void updateExpectedHeight() {
diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java
index 5056782..de65302 100644
--- a/src/com/android/launcher3/allapps/SearchTransitionController.java
+++ b/src/com/android/launcher3/allapps/SearchTransitionController.java
@@ -125,6 +125,7 @@
mAllAppsContainerView.getFloatingHeaderView().setFloatingRowsCollapsed(true);
mAllAppsContainerView.getFloatingHeaderView().setVisibility(VISIBLE);
+ mAllAppsContainerView.getFloatingHeaderView().maybeSetTabVisibility(VISIBLE);
mAllAppsContainerView.getAppsRecyclerViewContainer().setVisibility(VISIBLE);
getSearchRecyclerView().setVisibility(VISIBLE);
getSearchRecyclerView().setChildAttachedConsumer(this::onSearchChildAttached);
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 228b02b..2174936 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -65,7 +65,7 @@
* sets highlight result's title
*/
default void setFocusedResultTitle(
- @Nullable CharSequence title, @Nullable CharSequence subtitle) {}
+ @Nullable CharSequence title, @Nullable CharSequence subtitle, boolean showArrow) {}
/** Refresh the currently displayed list of results. */
default void refreshResults() {}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2972489..f25d26e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -16,6 +16,9 @@
package com.android.launcher3.config;
+import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
+import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
+import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
@@ -66,346 +69,320 @@
/**
* Feature flag to handle define config changes dynamically instead of killing the process.
- *
+ * <p>
*
* To add a new flag that can be toggled through the flags UI:
- *
+ * <p>
* Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
* and set a default value for the flag. This will be the default value on Debug builds.
*/
- public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag(270390028,
- "ENABLE_INPUT_CONSUMER_REASON_LOGGING",
- true,
- "Log the reason why an Input Consumer was selected for a gesture.");
-
public static final BooleanFlag ENABLE_GESTURE_ERROR_DETECTION = getDebugFlag(270389990,
- "ENABLE_GESTURE_ERROR_DETECTION",
- true,
+ "ENABLE_GESTURE_ERROR_DETECTION", ENABLED,
"Analyze gesture events and log detected errors");
// When enabled the promise icon is visible in all apps while installation an app.
public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
- "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
+ "PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps");
public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904,
- "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper");
+ "KEYGUARD_ANIMATION", DISABLED,
+ "Enable animation for keyguard going away on wallpaper");
public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907,
- "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
+ "ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps");
public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
- getReleaseFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", false,
- "Keep All Apps search bar at the bottom (but above keyboard if open)");
+ getReleaseFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", DISABLED,
+ "Keep All Apps search bar at the bottom (but above keyboard if open)");
public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930,
- "ENABLE_HIDE_HEADER", true, "Hide header on keyboard before typing in all apps");
+ "ENABLE_HIDE_HEADER", ENABLED, "Hide header on keyboard before typing in all apps");
public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getDebugFlag(270390779,
- "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false,
+ "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED,
"Expand and collapse pause work button while scrolling");
public static final BooleanFlag COLLECT_SEARCH_HISTORY = getReleaseFlag(270391455,
- "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
+ "COLLECT_SEARCH_HISTORY", DISABLED, "Allow launcher to collect search history for log");
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
- "ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
+ "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
- "ENABLE_TWOLINE_DEVICESEARCH", false,
+ "ENABLE_TWOLINE_DEVICESEARCH", TEAMFOOD,
"Enable two line label for icons with labels on device search.");
public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = getReleaseFlag(
- 270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", false,
+ 270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", DISABLED,
"Allows on device search in all apps logging");
public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
- "IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps");
+ "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653,
- "ENABLE_PEOPLE_TILE_PREVIEW", false,
+ "ENABLE_PEOPLE_TILE_PREVIEW", DISABLED,
"Experimental: Shows conversation shortcuts on home screen as search results");
public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
- "FOLDER_NAME_MAJORITY_RANKING", true,
+ "FOLDER_NAME_MAJORITY_RANKING", ENABLED,
"Suggests folder names based on majority based ranking.");
public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706,
- "INJECT_FALLBACK_APP_CORPUS_RESULTS", false,
+ "INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED,
"Inject fallback app corpus result when AiAi fails to return it.");
public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(270391641,
- "ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
+ "ASSISTANT_GIVES_LAUNCHER_FOCUS", DISABLED,
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag(270392203,
- "ENABLE_BULK_WORKSPACE_ICON_LOADING",
- true,
+ "ENABLE_BULK_WORKSPACE_ICON_LOADING", ENABLED,
"Enable loading workspace icons in bulk.");
- public static final BooleanFlag ENABLE_BULK_ALL_APPS_ICON_LOADING = getDebugFlag(270392465,
- "ENABLE_BULK_ALL_APPS_ICON_LOADING",
- true,
- "Enable loading all apps icons in bulk.");
-
public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(270392706,
- "ENABLE_DATABASE_RESTORE", false,
+ "ENABLE_DATABASE_RESTORE", DISABLED,
"Enable database restore when new restore session is created");
- public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(270391664,
- "ENABLE_SMARTSPACE_DISMISS", true,
- "Adds a menu option to dismiss the current Enhanced Smartspace card.");
-
public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(270392629,
- "ENABLE_OVERLAY_CONNECTION_OPTIM",
- false,
+ "ENABLE_OVERLAY_CONNECTION_OPTIM", DISABLED,
"Enable optimizing overlay service connection");
/**
* Enables region sampling for text color: Needs system health assessment before turning on
*/
public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag(270391669,
- "ENABLE_REGION_SAMPLING", false,
+ "ENABLE_REGION_SAMPLING", DISABLED,
"Enable region sampling to determine color of text on screen.");
public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
- getDebugFlag(270393096,
- "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false,
- "Always use hardware optimization for folder animations.");
+ getDebugFlag(270393096, "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS",
+ DISABLED, "Always use hardware optimization for folder animations.");
public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(270392980,
- "SEPARATE_RECENTS_ACTIVITY", false,
+ "SEPARATE_RECENTS_ACTIVITY", DISABLED,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(270392984,
- "ENABLE_MINIMAL_DEVICE", false,
+ "ENABLE_MINIMAL_DEVICE", DISABLED,
"Allow user to toggle minimal device mode in launcher.");
- public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag(
- 270392477, "ENABLE_TASKBAR_POPUP_MENU", true,
- "Enables long pressing taskbar icons to show the popup menu.");
-
public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag(270392643,
- "ENABLE_TWO_PANEL_HOME", true,
+ "ENABLE_TWO_PANEL_HOME", ENABLED,
"Uses two panel on home screen. Only applicable on large screen devices.");
public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276,
- "ENABLE_SCRIM_FOR_APP_LAUNCH", false,
- "Enables scrim during app launch animation.");
+ "ENABLE_SCRIM_FOR_APP_LAUNCH", DISABLED, "Enables scrim during app launch animation.");
public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258,
- "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
+ "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
+ "Enforce rounded corners on all App Widgets");
- public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(
- 270393108, "NOTIFY_CRASHES", false,
- "Sends a notification whenever launcher encounters an uncaught exception.");
+ public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES",
+ DISABLED, "Sends a notification whenever launcher encounters an uncaught exception.");
public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(270393604,
- "ENABLE_WALLPAPER_SCRIM", false,
+ "ENABLE_WALLPAPER_SCRIM", DISABLED,
"Enables scrim over wallpaper for text protection.");
public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(270393268,
- "WIDGETS_IN_LAUNCHER_PREVIEW", true,
+ "WIDGETS_IN_LAUNCHER_PREVIEW", ENABLED,
"Enables widgets in Launcher preview for the Wallpaper app.");
- public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag(270393112,
- "QUICK_WALLPAPER_PICKER", true,
- "Shows quick wallpaper picker in long-press menu");
-
public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426,
- "ENABLE_BACK_SWIPE_HOME_ANIMATION", true,
+ "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED,
"Enables home animation to icon when user swipes back.");
public static final BooleanFlag ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION = getDebugFlag(270614790,
- "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", false,
+ "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED,
"Enables predictive back aniamtion from all apps and widgets to home");
public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(270393294,
- "ENABLE_ICON_LABEL_AUTO_SCALING", true,
+ "ENABLE_ICON_LABEL_AUTO_SCALING", ENABLED,
"Enables scaling/spacing for icon labels to make more characters visible");
public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
- "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", false,
+ "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED,
"Enables displaying the all apps button in the hotseat.");
- public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
- "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false,
- "Enables One Search box in Taskbar All Apps.");
+ public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
+ "ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", DISABLED,
+ "Enables Search box in Taskbar All Apps.");
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(270393906,
- "ENABLE_SPLIT_FROM_WORKSPACE", true,
+ "ENABLE_SPLIT_FROM_WORKSPACE", ENABLED,
"Enable initiating split screen from workspace.");
public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS =
- getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", true,
- "Enable splitting from fullscreen app with keyboard shortcuts");
+ getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", ENABLED,
+ "Enable splitting from fullscreen app with keyboard shortcuts");
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
- 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false,
+ 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
"Enable initiating split screen from workspace to workspace.");
public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
- "ENABLE_NEW_MIGRATION_LOGIC", true,
+ "ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
"Enable the new grid migration logic, keeping pages when src < dest");
public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384,
- "ENABLE_WIDGET_HOST_IN_BACKGROUND", true,
+ "ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED,
"Enable background widget updates listening for widget holder");
public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = getReleaseFlag(270394223,
- "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
+ "ENABLE_ONE_SEARCH_MOTION", ENABLED, "Enables animations in OneSearch.");
public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag(
- 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
+ 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", DISABLED,
"Enable option to replace decorator-based search result backgrounds with drawables");
public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag(
- 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false,
+ 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", DISABLED,
"Enable option to launch search results using the new view container transitions");
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
- 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
+ 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
- "USE_LOCAL_ICON_OVERRIDES", true,
+ "USE_LOCAL_ICON_OVERRIDES", ENABLED,
"Use inbuilt monochrome icons if app doesn't provide one");
public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
- "ENABLE_DISMISS_PREDICTION_UNDO", false,
+ "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(270395008,
- "ENABLE_CACHED_WIDGET", true,
+ "ENABLE_CACHED_WIDGET", ENABLED,
"Show previously cached widgets as opposed to deferred widget where available");
public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
- "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", false,
+ "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED,
"Use local overrides for search request timeout");
public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
- "CONTINUOUS_VIEW_TREE_CAPTURE", true, "Capture View tree every frame");
+ "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
- public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(
- 270395140, "SECONDARY_DRAG_N_DROP_TO_PIN", false,
+ public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140,
+ "SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
"Enable dragging and dropping to pin apps within secondary display");
public static final BooleanFlag FOLDABLE_WORKSPACE_REORDER = getDebugFlag(270395070,
- "FOLDABLE_WORKSPACE_REORDER", false,
+ "FOLDABLE_WORKSPACE_REORDER", DISABLED,
"In foldables, when reordering the icons and widgets, is now going to use both sides");
public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073,
- "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", false,
+ "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", DISABLED,
"Allow bottom sheet depth to be smaller than 1 for multi-display devices.");
- public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(
- 270395177, "SCROLL_TOP_TO_RESET", true,
+ public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(270395177,
+ "SCROLL_TOP_TO_RESET", ENABLED,
"Bring up IME and focus on input when scroll to top if 'Always show keyboard'"
+ " is enabled or in prefix state");
public static final BooleanFlag ENABLE_MATERIAL_U_POPUP = getDebugFlag(270395516,
- "ENABLE_MATERIAL_U_POPUP", true, "Switch popup UX to use material U");
+ "ENABLE_MATERIAL_U_POPUP", ENABLED, "Switch popup UX to use material U");
public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269,
- "ENABLE_SEARCH_UNINSTALLED_APPS", false, "Search uninstalled app results.");
+ "ENABLE_SEARCH_UNINSTALLED_APPS", DISABLED, "Search uninstalled app results.");
public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(270395183,
- "SHOW_HOME_GARDENING", false,
- "Show the new home gardening mode");
+ "SHOW_HOME_GARDENING", DISABLED, "Show the new home gardening mode");
public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(270395133,
- "HOME_GARDENING_WORKSPACE_BUTTONS", false,
+ "HOME_GARDENING_WORKSPACE_BUTTONS", DISABLED,
"Change workspace edit buttons to reflect home gardening");
public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getReleaseFlag(270395134,
- "ENABLE_DOWNLOAD_APP_UX_V2", true, "Updates the download app UX"
+ "ENABLE_DOWNLOAD_APP_UX_V2", ENABLED, "Updates the download app UX"
+ " to have better visuals");
public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(270395186,
- "ENABLE_DOWNLOAD_APP_UX_V3", false, "Updates the download app UX"
+ "ENABLE_DOWNLOAD_APP_UX_V3", DISABLED, "Updates the download app UX"
+ " to have better visuals, improve contrast, and color");
public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag(270395077,
- "FORCE_PERSISTENT_TASKBAR", false, "Forces taskbar to be persistent, even in gesture"
+ "FORCE_PERSISTENT_TASKBAR", DISABLED, "Forces taskbar to be persistent, even in gesture"
+ " nav mode and when transient taskbar is enabled.");
public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
- "FOLDABLE_SINGLE_PAGE", true,
- "Use a single page for the workspace");
+ "FOLDABLE_SINGLE_PAGE", ENABLED, "Use a single page for the workspace");
public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
- "ENABLE_TRANSIENT_TASKBAR", true, "Enables transient taskbar.");
+ "ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
- "ENABLE_TRACKPAD_GESTURE", true, "Enables trackpad gesture.");
+ "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
- "ENABLE_ICON_IN_TEXT_HEADER", false, "Show icon in textheader");
+ "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader");
public static final BooleanFlag ENABLE_APP_ICON_FOR_INLINE_SHORTCUTS = getDebugFlag(270395087,
- "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", false, "Show app icon for inline shortcut");
+ "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut");
public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(270395278,
- "SHOW_DOT_PAGINATION", true, "Enable showing dot pagination in workspace");
+ "SHOW_DOT_PAGINATION", ENABLED, "Enable showing dot pagination in workspace");
public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(270395809,
- "LARGE_SCREEN_WIDGET_PICKER", true, "Enable new widget picker that takes "
+ "LARGE_SCREEN_WIDGET_PICKER", ENABLED, "Enable new widget picker that takes "
+ "advantage of large screen format");
+ public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
+ "MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
+ + "for home screen");
+
public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
- "ENABLE_NEW_GESTURE_NAV_TUTORIAL", true,
+ "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
"Enable the redesigned gesture navigation tutorial");
public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(270395567,
- "ENABLE_LAUNCH_FROM_STAGED_APP", true,
- "Enable the ability to tap a staged app during split select to launch it in full screen"
- );
+ "ENABLE_LAUNCH_FROM_STAGED_APP", ENABLED,
+ "Enable the ability to tap a staged app during split select to launch it in full "
+ + "screen");
public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358,
- "ENABLE_PREMIUM_HAPTICS_ALL_APPS", false,
+ "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED,
"Enables haptics opening/closing All apps");
public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(270396209,
- "ENABLE_FORCED_MONO_ICON", false,
- "Enable the ability to generate monochromatic icons, if it is not provided by the app"
- );
+ "ENABLE_FORCED_MONO_ICON", DISABLED,
+ "Enable the ability to generate monochromatic icons, if it is not provided by the app");
public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(270396268,
- "ENABLE_TASKBAR_EDU_TOOLTIP", true,
+ "ENABLE_TASKBAR_EDU_TOOLTIP", ENABLED,
"Enable the tooltip version of the Taskbar education flow.");
public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
- "ENABLE_MULTI_INSTANCE", false,
+ "ENABLE_MULTI_INSTANCE", DISABLED,
"Enables creation and filtering of multiple task instances in overview");
public static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583,
- "ENABLE_TASKBAR_PINNING", false,
+ "ENABLE_TASKBAR_PINNING", DISABLED,
"Enables taskbar pinning to allow user to switch between transient and persistent "
+ "taskbar flavors");
public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
- "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", false, "load the current workspace screen "
- + "visible to the user before the rest rather than loading all of them at once."
- );
+ "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
+ "load the current workspace screen visible to the user before the rest rather than "
+ + "loading all of them at once.");
public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206,
- "ENABLE_GRID_ONLY_OVERVIEW", false,
+ "ENABLE_GRID_ONLY_OVERVIEW", DISABLED,
"Enable a grid-only overview without a focused task.");
public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag(270397209,
- "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", true,
+ "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", ENABLED,
"Enables receiving unfold animation events from sysui instead of calculating "
+ "them in launcher process using hinge sensor values.");
public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
- "ENABLE_KEYBOARD_QUICK_SWITCH", true,
- "Enables keyboard quick switching");
+ "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching");
public static final BooleanFlag ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER = getDebugFlag(266177840,
- "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", false,
+ "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", DISABLED,
"Removes clone apps from the work profile tab.");
public static final BooleanFlag ENABLE_APP_PAIRS = getDebugFlag(274189428,
- "ENABLE_APP_PAIRS", false,
+ "ENABLE_APP_PAIRS", DISABLED,
"Enables the ability to create and save app pairs on the Home screen for easy"
+ " split screen launching.");
@@ -437,4 +414,13 @@
return sIntReader.applyAsInt(this);
}
}
+
+ /**
+ * Enabled state for a flag
+ */
+ public enum FlagState {
+ ENABLED,
+ DISABLED,
+ TEAMFOOD // Enabled in team food
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index d43731b..9fe3c0b 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -45,7 +45,7 @@
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.pageindicators.LauncherDotsPageIndicator;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
import com.android.launcher3.util.Thunk;
@@ -60,7 +60,7 @@
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
-public class FolderPagedView extends PagedView<PageIndicatorDots> implements ClipPathView {
+public class FolderPagedView extends PagedView<LauncherDotsPageIndicator> implements ClipPathView {
private static final String TAG = "FolderPagedView";
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 5a50569..0fe79e7 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -27,16 +27,11 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
-import android.os.SystemClock;
import android.util.Property;
import com.android.launcher3.R;
@@ -47,10 +42,6 @@
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.window.RefreshRateTracker;
-
-import java.util.WeakHashMap;
-import java.util.function.Function;
/**
* Extension of {@link FastBitmapDrawable} which shows a progress bar around the icon.
@@ -91,14 +82,6 @@
private static final int PRELOAD_ACCENT_COLOR_INDEX = 0;
private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1;
- private static final int ALPHA_DURATION_MILLIS = 3000;
- private static final int OVERLAY_ALPHA_RANGE = 191;
- private static final long WAVE_MOTION_DELAY_FACTOR_MILLIS = 100;
- private static final WeakHashMap<Integer, PorterDuffColorFilter> COLOR_FILTER_MAP =
- new WeakHashMap<>();
- public static final Function<Integer, PorterDuffColorFilter> FILTER_FACTORY =
- currArgb -> new PorterDuffColorFilter(currArgb, PorterDuff.Mode.SRC_ATOP);
-
private final Matrix mTmpMatrix = new Matrix();
private final PathMeasure mPathMeasure = new PathMeasure();
@@ -119,7 +102,6 @@
private float mTrackLength;
private boolean mRanFinishAnimation;
- private final int mRefreshRateMillis;
// Progress of the internal state. [0, 1] indicates the fraction of completed progress,
// [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation.
@@ -138,7 +120,6 @@
IconPalette.getPreloadProgressColor(context, info.bitmap.color),
getPreloadColors(context),
Utilities.isDarkTheme(context),
- getRefreshRateMillis(context),
GraphicsUtils.getShapePath(context, DEFAULT_PATH_SIZE));
}
@@ -147,7 +128,6 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis,
Path shapePath) {
super(info.bitmap);
mItem = info;
@@ -162,13 +142,14 @@
mSystemAccentColor = preloadColors[PRELOAD_ACCENT_COLOR_INDEX];
mSystemBackgroundColor = preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX];
mIsDarkMode = isDarkMode;
- mRefreshRateMillis = refreshRateMillis;
// If it's a pending app we will animate scale and alpha when it's no longer pending.
mIconScaleMultiplier.updateValue(info.getProgressLevel() == 0 ? 0 : 1);
setLevel(info.getProgressLevel());
- setIsStartable(info.isAppStartable());
+ if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
+ setIsStartable(info.isAppStartable());
+ }
}
@Override
@@ -223,20 +204,16 @@
: SMALL_SCALE;
canvas.scale(scale, scale, bounds.exactCenterX(), bounds.exactCenterY());
- ColorFilter filter = getOverlayFilter();
- mPaint.setColorFilter(filter);
super.drawInternal(canvas, bounds);
canvas.restoreToCount(saveCount);
-
- if (ENABLE_DOWNLOAD_APP_UX_V2.get() && filter != null) {
- reschedule();
- }
}
@Override
protected void updateFilter() {
if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA);
+ } else {
+ super.updateFilter();
}
}
@@ -317,7 +294,7 @@
/**
* Sets the internal progress and updates the UI accordingly
* for progress <= 0:
- * - icon with pending motion
+ * - icon is pending
* - progress track is not visible
* - progress bar is not visible
* for progress < 1:
@@ -367,11 +344,6 @@
return preloadColors;
}
-
- private static int getRefreshRateMillis(Context context) {
- return RefreshRateTracker.getSingleFrameMs(context);
- }
-
/**
* Returns a FastBitmapDrawable with the icon.
*/
@@ -388,55 +360,9 @@
mIndicatorColor,
new int[] {mSystemAccentColor, mSystemBackgroundColor},
mIsDarkMode,
- mRefreshRateMillis,
mShapePath);
}
- @Override
- public boolean setVisible(boolean visible, boolean restart) {
- if (!visible) {
- unscheduleSelf(mInvalidateRunnable);
- }
- return super.setVisible(visible, restart);
- }
-
- private void reschedule() {
- unscheduleSelf(mInvalidateRunnable);
- if (!isVisible()) {
- return;
- }
- final long upTime = SystemClock.uptimeMillis();
- scheduleSelf(mInvalidateRunnable,
- upTime - ((upTime % mRefreshRateMillis)) + mRefreshRateMillis);
- }
-
- /**
- * Returns a color filter to be used as an overlay on the pending icon with cascading motion
- * based on its position.
- */
- private ColorFilter getOverlayFilter() {
- if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) {
- // If the download has started, we do no need to animate
- return null;
- }
- long waveMotionDelay = (mItem.cellX * WAVE_MOTION_DELAY_FACTOR_MILLIS)
- + (mItem.cellY * WAVE_MOTION_DELAY_FACTOR_MILLIS);
- long time = SystemClock.uptimeMillis();
- int alpha = (int) Utilities.mapBoundToRange(
- (int) ((time + waveMotionDelay) % ALPHA_DURATION_MILLIS),
- 0,
- ALPHA_DURATION_MILLIS,
- 0,
- OVERLAY_ALPHA_RANGE * 2,
- LINEAR);
- if (alpha > OVERLAY_ALPHA_RANGE) {
- alpha = (OVERLAY_ALPHA_RANGE - (alpha % OVERLAY_ALPHA_RANGE));
- }
- int overlayColor = mIsDarkMode ? 0 : 255;
- int currArgb = Color.argb(alpha, overlayColor, overlayColor, overlayColor);
- return COLOR_FILTER_MAP.computeIfAbsent(currArgb, FILTER_FACTORY);
- }
-
protected static class PreloadIconConstantState extends FastBitmapConstantState {
protected final ItemInfoWithIcon mInfo;
@@ -444,7 +370,6 @@
protected final int[] mPreloadColors;
protected final boolean mIsDarkMode;
protected final int mLevel;
- protected final int mRefreshRateMillis;
private final Path mShapePath;
public PreloadIconConstantState(
@@ -454,7 +379,6 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis,
Path shapePath) {
super(bitmap, iconColor);
mInfo = info;
@@ -462,7 +386,6 @@
mPreloadColors = preloadColors;
mIsDarkMode = isDarkMode;
mLevel = info.getProgressLevel();
- mRefreshRateMillis = refreshRateMillis;
mShapePath = shapePath;
}
@@ -473,7 +396,6 @@
mIndicatorColor,
mPreloadColors,
mIsDarkMode,
- mRefreshRateMillis,
mShapePath);
}
}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 3c63f26..1e3b003 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -46,10 +46,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.core.util.Pair;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherFiles;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
import com.android.launcher3.icons.cache.BaseIconCache;
@@ -105,10 +105,6 @@
private int mPendingIconRequestCount = 0;
- public IconCache(Context context, InvariantDeviceProfile idp) {
- this(context, idp, LauncherFiles.APP_ICONS_DB, new IconProvider(context));
- }
-
public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName,
IconProvider iconProvider) {
super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
@@ -254,30 +250,37 @@
* Returns the badging info for the shortcut
*/
public BitmapInfo getShortcutInfoBadge(ShortcutInfo shortcutInfo) {
- ComponentName cn = shortcutInfo.getActivity();
- if (cn != null) {
- // Get the app info for the source activity.
- AppInfo appInfo = new AppInfo();
- appInfo.user = shortcutInfo.getUserHandle();
- appInfo.componentName = cn;
- appInfo.intent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .setComponent(cn);
- getTitleAndIcon(appInfo, false);
- return appInfo.bitmap;
+ return getShortcutInfoBadgeItem(shortcutInfo).bitmap;
+ }
+
+ @VisibleForTesting
+ protected ItemInfoWithIcon getShortcutInfoBadgeItem(ShortcutInfo shortcutInfo) {
+ // Check for badge override first.
+ String pkg = shortcutInfo.getPackage();
+ String override = shortcutInfo.getExtras() == null ? null
+ : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
+ if (!TextUtils.isEmpty(override)
+ && InstallSessionHelper.INSTANCE.get(mContext)
+ .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
+ pkg = override;
} else {
- String pkg = shortcutInfo.getPackage();
- String override = shortcutInfo.getExtras() == null ? null
- : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
- if (!TextUtils.isEmpty(override)
- && InstallSessionHelper.INSTANCE.get(mContext)
- .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
- pkg = override;
+ // Try component based badge before trying the normal package badge
+ ComponentName cn = shortcutInfo.getActivity();
+ if (cn != null) {
+ // Get the app info for the source activity.
+ AppInfo appInfo = new AppInfo();
+ appInfo.user = shortcutInfo.getUserHandle();
+ appInfo.componentName = cn;
+ appInfo.intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(cn);
+ getTitleAndIcon(appInfo, false);
+ return appInfo;
}
- PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
- getTitleAndIconForApp(pkgInfo, false);
- return pkgInfo.bitmap;
}
+ PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
+ getTitleAndIconForApp(pkgInfo, false);
+ return pkgInfo;
}
/**
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index da9be49..3e99772 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -960,7 +960,7 @@
iconRequestInfos.add(new IconRequestInfo<>(
appInfo, app, /* useLowResIcon= */ false));
mBgAllAppsList.add(
- appInfo, app, !FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get());
+ appInfo, app, false);
}
allActivityList.addAll(apps);
}
@@ -973,7 +973,7 @@
AppInfo promiseAppInfo = mBgAllAppsList.addPromiseApp(
mApp.getContext(),
PackageInstallInfo.fromInstallingState(info),
- !FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get());
+ false);
if (promiseAppInfo != null) {
iconRequestInfos.add(new IconRequestInfo<>(
@@ -984,15 +984,13 @@
}
}
- if (FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get()) {
- Trace.beginSection("LoadAllAppsIconsInBulk");
- try {
- mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
- iconRequestInfos.forEach(iconRequestInfo ->
- mBgAllAppsList.updateSectionName(iconRequestInfo.itemInfo));
- } finally {
- Trace.endSection();
- }
+ Trace.beginSection("LoadAllAppsIconsInBulk");
+ try {
+ mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
+ iconRequestInfos.forEach(iconRequestInfo ->
+ mBgAllAppsList.updateSectionName(iconRequestInfo.itemInfo));
+ } finally {
+ Trace.endSection();
}
mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED,
diff --git a/src/com/android/launcher3/pageindicators/LauncherDotsPageIndicator.java b/src/com/android/launcher3/pageindicators/LauncherDotsPageIndicator.java
new file mode 100644
index 0000000..8a21d13
--- /dev/null
+++ b/src/com/android/launcher3/pageindicators/LauncherDotsPageIndicator.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.pageindicators;
+
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
+
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Alarm;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.util.MultiValueAlpha;
+
+/**
+ * Extension of {@link PageIndicatorDots} with Launcher specific page-indicator functionality
+ */
+public class LauncherDotsPageIndicator extends PageIndicatorDots
+ implements Insettable, PageIndicator {
+
+ private static final int PAGINATION_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
+ private static final int PAGINATION_FADE_IN_DURATION = 83;
+ private static final int PAGINATION_FADE_OUT_DURATION = 167;
+
+ private static final int INDEX_VIEW_ALPHA = 0;
+ private static final int INDEX_AUTO_HIDE = 1;
+ private static final int ALPHA_CHANNEL_COUNT = 2;
+
+ private final Alarm mAutoHideAlarm;
+ private final MultiValueAlpha mMultiValueAlpha;
+
+ private @Nullable ObjectAnimator mAlphaAnimator;
+ private boolean mShouldAutoHide;
+ private float mTargetAutoHideAlpha;
+
+ private boolean mIsSettled = true;
+ private int mTotalScroll;
+
+ public LauncherDotsPageIndicator(Context context) {
+ this(context, null);
+ }
+
+ public LauncherDotsPageIndicator(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LauncherDotsPageIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mMultiValueAlpha = new MultiValueAlpha(this, ALPHA_CHANNEL_COUNT);
+ mMultiValueAlpha.setUpdateVisibility(true);
+
+ mTargetAutoHideAlpha = mMultiValueAlpha.get(INDEX_AUTO_HIDE).getValue();
+
+ mAutoHideAlarm = new Alarm();
+ mAutoHideAlarm.setOnAlarmListener(a -> animatePaginationToAlpha(0));
+ }
+
+ @Override
+ public void setScroll(int currentScroll, int totalScroll) {
+ mTotalScroll = totalScroll;
+ super.setScroll(currentScroll, totalScroll);
+ }
+
+ @Override
+ public void setShouldAutoHide(boolean shouldAutoHide) {
+ mShouldAutoHide = shouldAutoHide;
+ mAutoHideAlarm.cancelAlarm();
+ if (!mIsSettled || !mShouldAutoHide) {
+ animatePaginationToAlpha(1);
+ } else {
+ mAutoHideAlarm.setAlarm(PAGINATION_FADE_DELAY);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mShouldAutoHide && mTotalScroll == 0) {
+ return;
+ }
+ super.onDraw(canvas);
+ }
+
+ @Override
+ public void setActiveMarker(int activePage) {
+ super.setActiveMarker(activePage);
+ }
+
+ @Override
+ public void setMarkersCount(int numMarkers) {
+ super.setMarkersCount(numMarkers);
+ }
+
+ @Override
+ public void pauseAnimations() {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.pause();
+ }
+ }
+
+ @Override
+ public void skipAnimationsToEnd() {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.end();
+ }
+ }
+
+ @Override
+ protected void onAnimationStateChanged(boolean isSettled) {
+ mIsSettled = isSettled;
+ if (!mShouldAutoHide) {
+ return;
+ }
+ mAutoHideAlarm.cancelAlarm();
+ if (isSettled) {
+ mAutoHideAlarm.setAlarm(PAGINATION_FADE_DELAY);
+ } else {
+ animatePaginationToAlpha(1f);
+ }
+ }
+
+ private void animatePaginationToAlpha(float targetAlpha) {
+ if (mTargetAutoHideAlpha == targetAlpha) {
+ // Ignore the new animation if it is going to the same alpha as the current animation.
+ return;
+ }
+
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ mAlphaAnimator = ObjectAnimator.ofFloat(mMultiValueAlpha.get(INDEX_AUTO_HIDE),
+ MULTI_PROPERTY_VALUE, targetAlpha);
+ // If we are animating to decrease the alpha, then it's a fade out animation
+ // whereas if we are animating to increase the alpha, it's a fade in animation.
+ mAlphaAnimator.setDuration(targetAlpha == 0
+ ? PAGINATION_FADE_OUT_DURATION
+ : PAGINATION_FADE_IN_DURATION);
+ mAlphaAnimator.addListener(forEndCallback(() -> mAlphaAnimator = null));
+ mAlphaAnimator.start();
+ mTargetAutoHideAlpha = targetAlpha;
+ }
+
+
+ @Override
+ public void stopAllAnimations() {
+ super.stopAllAnimations();
+ }
+
+ @Override
+ public void prepareEntryAnimation() {
+ super.prepareEntryAnimation();
+ }
+
+ @Override
+ public void playEntryAnimation() {
+ super.playEntryAnimation();
+ }
+
+ /**
+ * We need to override setInsets to prevent InsettableFrameLayout from applying different
+ * margins on the pagination.
+ */
+ @Override
+ public void setInsets(Rect insets) {
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
+ public void setAlpha(PropertySetter setter, float alpha, TimeInterpolator interpolator) {
+ setter.setFloat(mMultiValueAlpha.get(INDEX_VIEW_ALPHA),
+ MULTI_PROPERTY_VALUE, alpha, interpolator);
+ }
+}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 570d6ff..193f50d 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.pageindicators;
+import android.animation.TimeInterpolator;
+import android.view.View;
+
+import com.android.launcher3.anim.PropertySetter;
+
/**
* Base class for a page indicator.
*/
@@ -48,9 +53,9 @@
}
/**
- * Sets the paint color.
+ * Sets the provided alpha on the pageIndicator
*/
- default void setPaintColor(int color) {
- // No-op by default
+ default void setAlpha(PropertySetter setter, float alpha, TimeInterpolator interpolator) {
+ setter.setViewAlpha((View) this, alpha, interpolator);
}
}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index b2c64b3..95452b9 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -25,42 +25,30 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Paint.Style;
-import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Handler;
-import android.os.Looper;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.util.IntProperty;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewOutlineProvider;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
/**
* {@link PageIndicator} which shows dots per page. The active page is shown with the current
* accent color.
*/
-public class PageIndicatorDots extends View implements Insettable, PageIndicator {
+public class PageIndicatorDots extends View {
private static final float SHIFT_PER_ANIMATION = 0.5f;
private static final float SHIFT_THRESHOLD = 0.1f;
private static final long ANIMATION_DURATION = 150;
- private static final int PAGINATION_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
- private static final int PAGINATION_FADE_IN_DURATION = 83;
- private static final int PAGINATION_FADE_OUT_DURATION = 167;
private static final int ENTER_ANIMATION_START_DELAY = 300;
private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
@@ -70,9 +58,6 @@
private static final int DOT_ALPHA = 128;
private static final float DOT_ALPHA_FRACTION = 0.5f;
private static final int DOT_GAP_FACTOR = SHOW_DOT_PAGINATION.get() ? 4 : 3;
- private static final int VISIBLE_ALPHA = 255;
- private static final int INVISIBLE_ALPHA = 0;
- private Paint mPaginationPaint;
// This value approximately overshoots to 1.5 times the original size.
private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
@@ -94,30 +79,14 @@
}
};
- private static final IntProperty<PageIndicatorDots> PAGINATION_ALPHA =
- new IntProperty<PageIndicatorDots>("pagination_alpha") {
- @Override
- public Integer get(PageIndicatorDots obj) {
- return obj.mPaginationPaint.getAlpha();
- }
-
- @Override
- public void setValue(PageIndicatorDots obj, int alpha) {
- obj.mPaginationPaint.setAlpha(alpha);
- obj.invalidate();
- }
- };
-
- private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper());
private final float mDotRadius;
private final float mCircleGap;
private final boolean mIsRtl;
+ private final Paint mPaginationPaint;
+
private int mNumPages;
private int mActivePage;
- private int mTotalScroll;
- private boolean mShouldAutoHide;
- private int mToAlpha;
/**
* The current position of the active dot including the animation progress.
@@ -131,13 +100,9 @@
private float mCurrentPosition;
private float mFinalPosition;
private ObjectAnimator mAnimator;
- private @Nullable ObjectAnimator mAlphaAnimator;
private float[] mEntryAnimationRadiusFactors;
- private final Runnable mHidePaginationRunnable =
- () -> animatePaginationToAlpha(INVISIBLE_ALPHA);
-
public PageIndicatorDots(Context context) {
this(context, null);
}
@@ -151,37 +116,34 @@
mPaginationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaginationPaint.setStyle(Style.FILL);
- mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PagedIndicator);
+ mPaginationPaint.setColor(ta.getColor(R.styleable.PagedIndicator_indicatorDotColor, 0));
+ ta.recycle();
+
mDotRadius = (SHOW_DOT_PAGINATION.get()
? getResources().getDimension(R.dimen.page_indicator_dot_size_v2)
: getResources().getDimension(R.dimen.page_indicator_dot_size))
/ 2;
mCircleGap = DOT_GAP_FACTOR * mDotRadius;
setOutlineProvider(new MyOutlineProver());
- mIsRtl = Utilities.isRtl(getResources());
+ mIsRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
- @Override
public void setScroll(int currentScroll, int totalScroll) {
if (SHOW_DOT_PAGINATION.get() && mActivePage != 0 && currentScroll == 0) {
CURRENT_POSITION.set(this, (float) mActivePage);
return;
}
- if (mNumPages <= 1) {
+ if (mNumPages <= 1 || totalScroll == 0) {
return;
}
- if (mShouldAutoHide) {
- animatePaginationToAlpha(VISIBLE_ALPHA);
- }
-
if (mIsRtl) {
currentScroll = totalScroll - currentScroll;
}
- mTotalScroll = totalScroll;
-
int scrollPerPage = totalScroll / (mNumPages - 1);
int pageToLeft = scrollPerPage == 0 ? 0 : currentScroll / scrollPerPage;
int pageToLeftScroll = pageToLeft * scrollPerPage;
@@ -191,87 +153,12 @@
if (currentScroll < pageToLeftScroll + scrollThreshold) {
// scroll is within the left page's threshold
animateToPosition(pageToLeft);
- if (mShouldAutoHide) {
- hideAfterDelay();
- }
} else if (currentScroll > pageToRightScroll - scrollThreshold) {
// scroll is far enough from left page to go to the right page
animateToPosition(pageToLeft + 1);
- if (mShouldAutoHide) {
- hideAfterDelay();
- }
} else {
// scroll is between left and right page
animateToPosition(pageToLeft + SHIFT_PER_ANIMATION);
- if (mShouldAutoHide) {
- mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null);
- }
- }
- }
-
- @Override
- public void setShouldAutoHide(boolean shouldAutoHide) {
- mShouldAutoHide = shouldAutoHide && SHOW_DOT_PAGINATION.get();
- if (shouldAutoHide && mPaginationPaint.getAlpha() > INVISIBLE_ALPHA) {
- hideAfterDelay();
- } else if (!shouldAutoHide) {
- mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null);
- }
- }
-
- @Override
- public void setPaintColor(int color) {
- mPaginationPaint.setColor(color);
- }
-
- private void hideAfterDelay() {
- mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null);
- mDelayedPaginationFadeHandler.postDelayed(mHidePaginationRunnable, PAGINATION_FADE_DELAY);
- }
-
- private void animatePaginationToAlpha(int alpha) {
- if (alpha == mToAlpha) {
- // Ignore the new animation if it is going to the same alpha as the current animation.
- return;
- }
-
- if (mAlphaAnimator != null) {
- mAlphaAnimator.cancel();
- }
- mAlphaAnimator = ObjectAnimator.ofInt(this, PAGINATION_ALPHA,
- alpha);
- // If we are animating to decrease the alpha, then it's a fade out animation
- // whereas if we are animating to increase the alpha, it's a fade in animation.
- mAlphaAnimator.setDuration(alpha < mToAlpha
- ? PAGINATION_FADE_OUT_DURATION
- : PAGINATION_FADE_IN_DURATION);
- mAlphaAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAlphaAnimator = null;
- }
- });
- mAlphaAnimator.start();
- mToAlpha = alpha;
- }
-
- /**
- * Pauses all currently running animations.
- */
- @Override
- public void pauseAnimations() {
- if (mAlphaAnimator != null) {
- mAlphaAnimator.pause();
- }
- }
-
- /**
- * Force-ends all currently running or paused animations.
- */
- @Override
- public void skipAnimationsToEnd() {
- if (mAlphaAnimator != null) {
- mAlphaAnimator.end();
}
}
@@ -281,15 +168,25 @@
mCurrentPosition = mFinalPosition;
}
if (mAnimator == null && Float.compare(mCurrentPosition, mFinalPosition) != 0) {
+ onAnimationStateChanged(false);
float positionForThisAnim = mCurrentPosition > mFinalPosition ?
mCurrentPosition - SHIFT_PER_ANIMATION : mCurrentPosition + SHIFT_PER_ANIMATION;
mAnimator = ObjectAnimator.ofFloat(this, CURRENT_POSITION, positionForThisAnim);
mAnimator.addListener(new AnimationCycleListener());
mAnimator.setDuration(ANIMATION_DURATION);
mAnimator.start();
+ } else if (mAnimator == null) {
+ // The state is only settled if the indicator lands on a int value
+ onAnimationStateChanged(Float.compare(Math.round(mFinalPosition), mFinalPosition) == 0);
}
}
+ /**
+ * Called when the animation state of the page indicator changes.
+ * @param isSettled true if the page indicator has settled at its final position
+ */
+ protected void onAnimationStateChanged(boolean isSettled) { }
+
public void stopAllAnimations() {
if (mAnimator != null) {
mAnimator.cancel();
@@ -345,14 +242,10 @@
animSet.start();
}
- @Override
public void setActiveMarker(int activePage) {
- if (mActivePage != activePage) {
- mActivePage = activePage;
- }
+ mActivePage = activePage;
}
- @Override
public void setMarkersCount(int numMarkers) {
mNumPages = numMarkers;
requestLayout();
@@ -374,11 +267,6 @@
return;
}
- if (mShouldAutoHide && mTotalScroll == 0) {
- mPaginationPaint.setAlpha(INVISIBLE_ALPHA);
- return;
- }
-
// Draw all page indicators;
float circleGap = mCircleGap;
float startX = (getWidth() - (mNumPages * circleGap) + mDotRadius) / 2;
@@ -480,20 +368,9 @@
@Override
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
- if (mShouldAutoHide && SHOW_DOT_PAGINATION.get()) {
- hideAfterDelay();
- }
mAnimator = null;
animateToPosition(mFinalPosition);
}
}
}
-
- /**
- * We need to override setInsets to prevent InsettableFrameLayout from applying different
- * margins on the pagination.
- */
- @Override
- public void setInsets(Rect insets) {
- }
}
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 7ca3b11..125b4ce 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -181,9 +181,10 @@
public boolean isTrustedPackage(String pkg, UserHandle user) {
synchronized (mSessionVerifiedMap) {
if (!mSessionVerifiedMap.containsKey(pkg)) {
- boolean hasSystemFlag = new PackageManagerHelper(mAppContext).getApplicationInfo(
- pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
- mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
+ boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg)
+ || new PackageManagerHelper(mAppContext)
+ .getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
+ mSessionVerifiedMap.put(pkg, hasSystemFlag);
}
}
return mSessionVerifiedMap.get(pkg);
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 0edf292..5b493c2 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -109,7 +109,7 @@
protected final int mArrowPointRadius;
protected final View mArrow;
- private final int mMargin;
+ protected final int mChildContainerMargin;
protected boolean mIsLeftAligned;
protected boolean mIsAboveIcon;
@@ -145,7 +145,7 @@
// Initialize arrow view
final Resources resources = getResources();
mArrowColor = getColorStateList(getContext(), R.color.popup_shade_first).getDefaultColor();
- mMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
+ mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
mArrow = new View(context);
@@ -249,7 +249,7 @@
if (view.getVisibility() == VISIBLE) {
if (lastView != null) {
MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams();
- mlp.bottomMargin = mMargin;
+ mlp.bottomMargin = mChildContainerMargin;
}
lastView = view;
MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams();
@@ -441,7 +441,7 @@
numVisibleChildren++;
}
}
- int childMargins = (numVisibleChildren - 1) * mMargin;
+ int childMargins = (numVisibleChildren - 1) * mChildContainerMargin;
int height = getMeasuredHeight() + extraVerticalSpace + childMargins;
int width = getMeasuredWidth() + getPaddingLeft() + getPaddingRight();
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 3f75ecc..9cca29a 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -95,6 +95,8 @@
private static final int SHORTCUT_COLLAPSE_THRESHOLD = 6;
+ private final float mShortcutHeight;
+
private BubbleTextView mOriginalIcon;
private int mNumNotifications;
private NotificationContainer mNotificationContainer;
@@ -112,6 +114,7 @@
mStartDragThreshold = getResources().getDimensionPixelSize(
R.dimen.deep_shortcuts_start_drag_threshold);
mContainerWidth = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_width);
+ mShortcutHeight = getResources().getDimension(R.dimen.system_shortcut_header_height);
}
public PopupContainerWithArrow(Context context, AttributeSet attrs) {
@@ -387,16 +390,18 @@
*/
private void addAllShortcutsMaterialU(int deepShortcutCount,
List<SystemShortcut> systemShortcuts) {
-
if (deepShortcutCount + systemShortcuts.size() <= SHORTCUT_COLLAPSE_THRESHOLD) {
// add all system shortcuts including widgets shortcut to same container
addSystemShortcutsMaterialU(systemShortcuts,
R.layout.system_shortcut_rows_container_material_u,
R.layout.system_shortcut);
- addDeepShortcutsMaterialU(deepShortcutCount);
+ float currentHeight = (mShortcutHeight * systemShortcuts.size())
+ + mChildContainerMargin;
+ addDeepShortcutsMaterialU(deepShortcutCount, currentHeight);
return;
}
+ float currentHeight = mShortcutHeight + mChildContainerMargin;
List<SystemShortcut> nonWidgetSystemShortcuts =
getNonWidgetSystemShortcuts(systemShortcuts);
// If total shortcuts over threshold, collapse system shortcuts to single row
@@ -411,8 +416,9 @@
mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container_material_u,
this);
initializeWidgetShortcut(mWidgetContainer, widgetShortcutOpt.get());
+ currentHeight += mShortcutHeight + mChildContainerMargin;
}
- addDeepShortcutsMaterialU(deepShortcutCount);
+ addDeepShortcutsMaterialU(deepShortcutCount, currentHeight);
}
/**
@@ -497,10 +503,14 @@
/**
* Inflates and adds [deepShortcutCount] number of DeepShortcutView for the to a new container
* @param deepShortcutCount number of DeepShortcutView instances to add
+ * @param currentHeight height of popup before adding deep shortcuts
*/
- private void addDeepShortcutsMaterialU(int deepShortcutCount) {
+ private void addDeepShortcutsMaterialU(int deepShortcutCount, float currentHeight) {
mDeepShortcutContainer = inflateAndAdd(R.layout.deep_shortcut_container, this);
for (int i = deepShortcutCount; i > 0; i--) {
+ currentHeight += mShortcutHeight;
+ // when there is limited vertical screen space, limit total popup rows to fit
+ if (currentHeight >= mActivityContext.getDeviceProfile().availableHeightPx) break;
DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut_material_u,
mDeepShortcutContainer);
v.getLayoutParams().width = mContainerWidth;
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 3d455d8..02ebb15 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR;
import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import android.annotation.SuppressLint;
@@ -55,6 +56,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.StringJoiner;
/**
* Utility class to cache properties of default display to avoid a system RPC on every call.
@@ -66,6 +68,9 @@
private static final boolean DEBUG = false;
private static boolean sTransientTaskbarStatusForTests;
+ // TODO(b/254119092) remove all logs with this tag
+ public static final String TASKBAR_NOT_DESTROYED_TAG = "b/254119092";
+
public static final MainThreadInitializedObject<DisplayController> INSTANCE =
new MainThreadInitializedObject<>(DisplayController::new);
@@ -206,6 +211,7 @@
@Override
@TargetApi(Build.VERSION_CODES.S)
public final void onConfigurationChanged(Configuration config) {
+ Log.d(TASKBAR_NOT_DESTROYED_TAG, "DisplayController#onConfigurationChanged: " + config);
Display display = mWindowContext.getDisplay();
if (config.densityDpi != mInfo.densityDpi
|| config.fontScale != mInfo.fontScale
@@ -272,7 +278,7 @@
change |= CHANGE_SUPPORTED_BOUNDS;
}
if (DEBUG) {
- Log.d(TAG, "handleInfoChange - change: 0b" + Integer.toBinaryString(change));
+ Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change));
}
if (change != 0) {
@@ -386,12 +392,33 @@
return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()), densityDpi);
}
+ /**
+ * Returns all displays for the device
+ */
+ public Set<CachedDisplayInfo> getAllDisplays() {
+ return Collections.unmodifiableSet(mPerDisplayBounds.keySet());
+ }
+
public int getDensityDpi() {
return densityDpi;
}
}
/**
+ * Returns the given binary flags as a human-readable string.
+ * @see #CHANGE_ALL
+ */
+ public String getChangeFlagsString(int change) {
+ StringJoiner result = new StringJoiner("|");
+ appendFlag(result, change, CHANGE_ACTIVE_SCREEN, "CHANGE_ACTIVE_SCREEN");
+ appendFlag(result, change, CHANGE_ROTATION, "CHANGE_ROTATION");
+ appendFlag(result, change, CHANGE_DENSITY, "CHANGE_DENSITY");
+ appendFlag(result, change, CHANGE_SUPPORTED_BOUNDS, "CHANGE_SUPPORTED_BOUNDS");
+ appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE");
+ return result.toString();
+ }
+
+ /**
* Dumps the current state information
*/
public void dump(PrintWriter pw) {
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 8c5e782..1ae43d0 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -200,8 +200,8 @@
/** Keep in sync w/ ActivityTaskManager#INVALID_TASK_ID (unreference-able) */
private static final int INVALID_TASK_ID = -1;
- public final View view;
- public final Drawable drawable;
+ private View view;
+ private Drawable drawable;
public final Intent intent;
public final SplitPositionOption position;
public final ItemInfo itemInfo;
@@ -224,5 +224,13 @@
this.itemInfo = itemInfo;
this.splitEvent = splitEvent;
}
+
+ public Drawable getDrawable() {
+ return drawable;
+ }
+
+ public View getView() {
+ return view;
+ }
}
}
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 5526839..a5c663f 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -32,10 +32,13 @@
import android.util.SparseArray;
import android.util.TypedValue;
+import androidx.annotation.ColorInt;
+
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.GraphicsUtils;
+import com.android.launcher3.views.ActivityContext;
/**
* Various utility methods associated with theming.
@@ -198,4 +201,12 @@
return result;
}
+
+ /** Returns the desired navigation bar scrim color depending on the {@code DeviceProfile}. */
+ @ColorInt
+ public static <T extends Context & ActivityContext> int getNavBarScrimColor(T context) {
+ return context.getDeviceProfile().isTaskbarPresent
+ ? context.getColor(R.color.taskbar_background)
+ : Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor);
+ }
}
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 5d90291..3fa5799 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -16,11 +16,13 @@
package com.android.launcher3.util;
+import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewTreeObserver.OnDrawListener;
import com.android.launcher3.Launcher;
+import com.android.launcher3.testing.shared.TestProtocol;
import java.util.function.Consumer;
@@ -42,12 +44,21 @@
private boolean mCancelled;
public ViewOnDrawExecutor(RunnableList tasks) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "Initialize ViewOnDrawExecutor");
+ }
mTasks = tasks;
}
public void attachTo(Launcher launcher) {
mOnClearCallback = launcher::clearPendingExecutor;
mAttachedView = launcher.getWorkspace();
+
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.attachTo: launcher=" + launcher
+ + ", isAttachedToWindow=" + mAttachedView.isAttachedToWindow());
+ }
+
mAttachedView.addOnAttachStateChangeListener(this);
if (mAttachedView.isAttachedToWindow()) {
@@ -56,6 +67,10 @@
}
private void attachObserver() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING,
+ "ViewOnDrawExecutor.attachObserver: mCompleted=" + mCompleted);
+ }
if (!mCompleted) {
mAttachedView.getViewTreeObserver().addOnDrawListener(this);
}
@@ -63,6 +78,9 @@
@Override
public void onViewAttachedToWindow(View v) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.onViewAttachedToWindow");
+ }
attachObserver();
}
@@ -71,11 +89,19 @@
@Override
public void onDraw() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.onDraw");
+ }
mFirstDrawCompleted = true;
mAttachedView.post(this);
}
public void onLoadAnimationCompleted() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING,
+ "ViewOnDrawExecutor.onLoadAnimationCompleted: mAttachedView != null="
+ + (mAttachedView != null));
+ }
mLoadAnimationCompleted = true;
if (mAttachedView != null) {
mAttachedView.post(this);
@@ -84,6 +110,12 @@
@Override
public void run() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING,
+ "ViewOnDrawExecutor.run: mLoadAnimationCompleted=" + mLoadAnimationCompleted
+ + ", mFirstDrawCompleted=" + mFirstDrawCompleted
+ + ", mCompleted=" + mCompleted);
+ }
// Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
markCompleted();
@@ -94,6 +126,12 @@
* Executes all tasks immediately
*/
public void markCompleted() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING,
+ "ViewOnDrawExecutor.markCompleted: mCancelled=" + mCancelled
+ + ", mOnClearCallback != null=" + (mOnClearCallback != null)
+ + ", mAttachedView != null=" + (mAttachedView != null));
+ }
if (!mCancelled) {
mTasks.executeAllAndDestroy();
}
@@ -108,6 +146,9 @@
}
public void cancel() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.cancel");
+ }
mCancelled = true;
markCompleted();
}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index a941833..c0b24fa 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -333,6 +333,7 @@
}
}
+ @Override
public void onDraw(Canvas canvas) {
if (mThumbOffsetY < 0 || mRv == null) {
return;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 07c6ba4..c3f26fa 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -37,6 +37,7 @@
import androidx.core.view.ViewCompat;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Insettable;
@@ -60,7 +61,7 @@
*/
public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
implements OnClickListener, OnLongClickListener, DragSource,
- PopupDataProvider.PopupDataChangeListener, Insettable {
+ PopupDataProvider.PopupDataChangeListener, Insettable, OnDeviceProfileChangeListener {
/** The default number of cells that can fit horizontally in a widget sheet. */
public static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
@@ -84,7 +85,7 @@
mWidgetCellHorizontalPadding = getResources().getDimensionPixelSize(
R.dimen.widget_cell_horizontal_padding);
mNavBarScrimPaint = new Paint();
- mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
+ mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
}
protected int getScrimColor(Context context) {
@@ -98,12 +99,23 @@
.normalizeWindowInsets(getContext(), getRootWindowInsets(), new Rect());
mNavBarScrimHeight = getNavBarScrimHeight(windowInsets);
mActivityContext.getPopupDataProvider().setChangeListener(this);
+ mActivityContext.addOnDeviceProfileChangeListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mActivityContext.getPopupDataProvider().setChangeListener(null);
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ int navBarScrimColor = Themes.getNavBarScrimColor(mActivityContext);
+ if (mNavBarScrimPaint.getColor() != navBarScrimColor) {
+ mNavBarScrimPaint.setColor(navBarScrimColor);
+ invalidate();
+ }
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 5293c3d..5e165df 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -110,6 +110,7 @@
entry -> !mCurrentUser.equals(entry.mPkgItem.user)
&& !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
protected final boolean mHasWorkProfile;
+ protected boolean mHasRecommendedWidgets;
protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
@Nullable private ArrowTipView mLatestEducationalTip;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
@@ -537,7 +538,6 @@
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
- mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
}
protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
@@ -574,7 +574,8 @@
}
List<WidgetItem> recommendedWidgets =
mActivityContext.getPopupDataProvider().getRecommendedWidgets();
- if (recommendedWidgets.size() > 0) {
+ mHasRecommendedWidgets = recommendedWidgets.size() > 0;
+ if (mHasRecommendedWidgets) {
float noWidgetsViewHeight = 0;
if (mIsNoWidgetsViewNeeded) {
// Make sure recommended section leaves enough space for noWidgetsView.
@@ -603,14 +604,10 @@
mRecommendedWidgetsTable.setRecommendedWidgets(
recommendedWidgetsInTable, maxTableHeight);
} else {
- hideRecommendations();
+ mRecommendedWidgetsTable.setVisibility(GONE);
}
}
- protected void hideRecommendations() {
- mRecommendedWidgetsTable.setVisibility(GONE);
- }
-
protected float getMaxTableHeight(float noWidgetsViewHeight) {
return (mContent.getMeasuredHeight()
- mTabsHeight - getHeaderViewHeight()
@@ -686,12 +683,13 @@
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
boolean isTwoPane = LARGE_SCREEN_WIDGET_PICKER.get()
&& launcher.getDeviceProfile().isTablet
- && launcher.getDeviceProfile().isLandscape;
+ && launcher.getDeviceProfile().isLandscape
+ && !launcher.getDeviceProfile().isTwoPanels;
WidgetsFullSheet sheet;
if (isTwoPane) {
sheet = (WidgetsTwoPaneSheet) launcher.getLayoutInflater().inflate(
- R.layout.widgets_full_sheet_large_screen,
+ R.layout.widgets_two_pane_sheet,
launcher.getDragLayer(),
false);
} else {
@@ -896,7 +894,7 @@
final WidgetsListAdapter mWidgetsListAdapter;
private final DefaultItemAnimator mWidgetsListItemAnimator;
- private WidgetsRecyclerView mWidgetsRecyclerView;
+ WidgetsRecyclerView mWidgetsRecyclerView;
AdapterHolder(int adapterType) {
mAdapterType = adapterType;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 2199473..d85737b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -54,6 +54,7 @@
private ScrollView mRightPaneScrollView;
private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
+ private int mActivePage = -1;
private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
@Override
@@ -63,7 +64,7 @@
0,
view.getMeasuredWidth(),
view.getMeasuredHeight() - getResources().getDimensionPixelSize(
- R.dimen.widget_list_horizontal_margin_large_screen),
+ R.dimen.widget_list_horizontal_margin_two_pane),
view.getResources().getDimensionPixelSize(
R.dimen.widget_list_top_bottom_corner_radius)
);
@@ -90,8 +91,8 @@
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view_large_screen
- : R.layout.widgets_full_sheet_recyclerview_large_screen;
+ int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_two_pane_sheet_paged_view
+ : R.layout.widgets_two_pane_sheet_recyclerview;
layoutInflater.inflate(contentLayoutRes, findViewById(R.id.recycler_view_container), true);
setupViews();
@@ -107,7 +108,6 @@
mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- setupSuggestedWidgets(layoutInflater);
onRecommendedWidgetsBound();
onWidgetsBound();
setUpEducationViewsIfNeeded();
@@ -117,9 +117,13 @@
}
@Override
- protected void hideRecommendations() {
- super.hideRecommendations();
- mSuggestedWidgetsContainer.setVisibility(GONE);
+ public void onRecommendedWidgetsBound() {
+ super.onRecommendedWidgetsBound();
+
+ if (mSuggestedWidgetsContainer == null && mHasRecommendedWidgets) {
+ setupSuggestedWidgets(LayoutInflater.from(getContext()));
+ mSuggestedWidgetsHeader.callOnClick();
+ }
}
private void setupSuggestedWidgets(LayoutInflater layoutInflater) {
@@ -168,13 +172,21 @@
@Override
public void onActivePageChanged(int currentActivePage) {
- // if the current active page changes to personal or work we set suggestions
- // to be the selected widget
- if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) {
- mSuggestedWidgetsHeader.callOnClick();
+ super.onActivePageChanged(currentActivePage);
+
+ // If active page didn't change then we don't want to update the header.
+ if (mActivePage == currentActivePage) {
+ return;
}
- super.onActivePageChanged(currentActivePage);
+ mActivePage = currentActivePage;
+
+ if (mSuggestedWidgetsHeader == null) {
+ mAdapters.get(currentActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
+ mAdapters.get(currentActivePage).mWidgetsRecyclerView.scrollToTop();
+ } else if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) {
+ mSuggestedWidgetsHeader.callOnClick();
+ }
}
@Override
@@ -188,15 +200,10 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mSuggestedWidgetsContainer.setVisibility(VISIBLE);
- }
-
- @Override
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
super.onSearchResults(entries);
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
}
@Override
@@ -208,13 +215,19 @@
@Override
protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
- if (isInSearchMode) {
- mSuggestedWidgetsContainer.setVisibility(GONE);
- } else {
- mSuggestedWidgetsContainer.setVisibility(VISIBLE);
- mSuggestedWidgetsHeader.callOnClick();
- }
super.setViewVisibilityBasedOnSearch(isInSearchMode);
+
+ if (mSuggestedWidgetsHeader != null && mSuggestedWidgetsContainer != null) {
+ if (!isInSearchMode) {
+ mSuggestedWidgetsContainer.setVisibility(VISIBLE);
+ mSuggestedWidgetsHeader.callOnClick();
+ } else {
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ }
+ } else if (!isInSearchMode) {
+ mAdapters.get(mActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
+ }
+
}
@Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index 4463adc..eb0494e 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -16,7 +16,10 @@
package com.android.launcher3.uioverrides.flags;
+import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
+
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+import com.android.launcher3.config.FeatureFlags.FlagState;
import com.android.launcher3.config.FeatureFlags.IntFlag;
import java.io.PrintWriter;
@@ -31,16 +34,16 @@
* Creates a new debug flag
*/
public static BooleanFlag getDebugFlag(
- int bugId, String key, boolean defaultValue, String description) {
- return new BooleanFlag(defaultValue);
+ int bugId, String key, FlagState flagState, String description) {
+ return new BooleanFlag(flagState == ENABLED);
}
/**
* Creates a new debug flag
*/
public static BooleanFlag getReleaseFlag(
- int bugId, String key, boolean defaultValueInCode, String description) {
- return new BooleanFlag(defaultValueInCode);
+ int bugId, String key, FlagState flagState, String description) {
+ return new BooleanFlag(flagState == ENABLED);
}
/**
diff --git a/tests/res/raw/devices.json b/tests/res/raw/devices.json
deleted file mode 100644
index a78dd86..0000000
--- a/tests/res/raw/devices.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "pixel6pro": {
- "width": 1440,
- "height": 3120,
- "density": 560,
- "name": "pixel6pro",
- "cutout": "0, 130, 0, 0",
- "grids": [
- "normal",
- "reasonable",
- "practical",
- "big",
- "crazy_big"
- ],
- "resourceOverrides": {
- "status_bar_height": 98,
- "navigation_bar_height_landscape": 56,
- "navigation_bar_height": 56,
- "navigation_bar_width": 56
- }
- },
- "test": {
- "data needs updating": 0
- },
- "pixel5": {
- "width": 1080,
- "height": 2340,
- "density": 440,
- "name": "pixel5",
- "cutout": "0, 136, 0, 0",
- "grids": [
- "normal",
- "reasonable",
- "practical",
- "big",
- "crazy_big"
- ],
- "resourceOverrides": {
- "status_bar_height": 66,
- "navigation_bar_height_landscape": 44,
- "navigation_bar_height": 44,
- "navigation_bar_width": 44
- }
- }
-}
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index a5f33c0..c22cf40 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -153,6 +153,9 @@
isScalable = true
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = BooleanArray(4) { false }
+
inlineQsb = BooleanArray(4) { false }
devicePaddingId = R.xml.paddings_handhelds
@@ -233,6 +236,9 @@
isScalable = true
devicePaddingId = R.xml.paddings_6x5
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = booleanArrayOf(true, false, true, true)
+
inlineQsb = booleanArrayOf(false, true, false, false)
devicePaddingId = R.xml.paddings_handhelds
@@ -308,6 +314,9 @@
isScalable = true
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = BooleanArray(4) { true }
+
inlineQsb = booleanArrayOf(false, false, false, false)
devicePaddingId = R.xml.paddings_handhelds
diff --git a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
deleted file mode 100644
index e2ed65f..0000000
--- a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.deviceemulator;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
-
-import androidx.test.uiautomator.UiDevice;
-
-import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
-import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.util.window.WindowManagerProxy;
-
-import java.util.concurrent.Callable;
-
-
-public class DisplayEmulator {
- Context mContext;
- LauncherInstrumentation mLauncher;
- DisplayEmulator(Context context, LauncherInstrumentation launcher) {
- mContext = context;
- mLauncher = launcher;
- }
-
- /**
- * By changing the WindowManagerProxy we can override the window insets information
- **/
- private IWindowManager changeWindowManagerInstance(DeviceEmulationData deviceData) {
- WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(deviceData));
- return WindowManagerGlobal.getWindowManagerService();
- }
-
- public <T> T emulate(DeviceEmulationData device, String grid, Callable<T> runInEmulation)
- throws Exception {
- WindowManagerProxy original = WindowManagerProxy.INSTANCE.get(mContext);
- // Set up emulation
- final int userId = UserHandle.myUserId();
- WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(device));
- IWindowManager wm = changeWindowManagerInstance(device);
- // Change density twice to force display controller to reset its state
- wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density / 2, userId);
- wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density, userId);
- wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, device.width, device.height);
- wm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
-
- // Set up grid
- setGrid(grid);
- try {
- return runInEmulation.call();
- } finally {
- // Clear emulation
- WindowManagerProxy.INSTANCE.initializeForTesting(original);
- UiDevice.getInstance(getInstrumentation()).executeShellCommand("cmd window reset");
- }
- }
-
- private void setGrid(String gridType) {
- // When the grid changes, the desktop arrangement get stored in SQL and we need to wait to
- // make sure there is no SQL operations running and get SQL_BUSY error, that's why we need
- // to call mLauncher.waitForLauncherInitialized();
- mLauncher.waitForLauncherInitialized();
- String testProviderAuthority = mContext.getPackageName() + ".grid_control";
- Uri gridUri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority(testProviderAuthority)
- .appendPath("default_grid")
- .build();
- ContentValues values = new ContentValues();
- values.put("name", gridType);
- mContext.getContentResolver().update(gridUri, values, null, null);
- }
-}
diff --git a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
deleted file mode 100644
index 2d6bbcc..0000000
--- a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.deviceemulator;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.view.WindowInsets;
-
-import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
-import com.android.launcher3.util.RotationUtils;
-import com.android.launcher3.util.WindowBounds;
-import com.android.launcher3.util.window.CachedDisplayInfo;
-import com.android.launcher3.util.window.WindowManagerProxy;
-
-public class TestWindowManagerProxy extends WindowManagerProxy {
-
- private final DeviceEmulationData mDevice;
-
- public TestWindowManagerProxy(DeviceEmulationData device) {
- super(true);
- mDevice = device;
- }
-
- @Override
- protected int getDimenByName(Resources res, String resName) {
- Integer mock = mDevice.resourceOverrides.get(resName);
- return mock != null ? mock : super.getDimenByName(res, resName);
- }
-
- @Override
- protected int getDimenByName(Resources res, String resName, String fallback) {
- return getDimenByName(res, resName);
- }
-
- @Override
- public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
- int rotation = getRotation(displayInfoContext);
- Point size = new Point(mDevice.width, mDevice.height);
- RotationUtils.rotateSize(size, rotation);
- Rect cutout = new Rect(mDevice.cutout);
- RotationUtils.rotateRect(cutout, rotation);
- return new CachedDisplayInfo(size, rotation, cutout);
- }
-
- @Override
- public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
- return estimateInternalDisplayBounds(displayInfoContext).get(
- getDisplayInfo(displayInfoContext))[getDisplay(displayInfoContext).getRotation()];
- }
-
- @Override
- public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
- Rect outInsets) {
- outInsets.set(getRealBounds(context, getDisplayInfo(context)).insets);
- return oldInsets;
- }
-}
diff --git a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
deleted file mode 100644
index 55b7bf1..0000000
--- a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.deviceemulator.models;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT;
-import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
-import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
-import static com.android.launcher3.testing.shared.ResourceUtils.getDimenByName;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.os.Build;
-import android.util.ArrayMap;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.IOUtils;
-import com.android.launcher3.util.IntArray;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Map;
-
-public class DeviceEmulationData {
-
- public final int width;
- public final int height;
- public final int density;
- public final String name;
- public final String[] grids;
- public final Rect cutout;
- public final Map<String, Integer> resourceOverrides;
-
- private static final String[] EMULATED_SYSTEM_RESOURCES = new String[]{
- NAVBAR_HEIGHT,
- NAVBAR_HEIGHT_LANDSCAPE,
- NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE,
- "status_bar_height",
- };
-
- public DeviceEmulationData(int width, int height, int density, Rect cutout, String name,
- String[] grid,
- Map<String, Integer> resourceOverrides) {
- this.width = width;
- this.height = height;
- this.density = density;
- this.name = name;
- this.grids = grid;
- this.cutout = cutout;
- this.resourceOverrides = resourceOverrides;
- }
-
- public static DeviceEmulationData deviceFromJSON(JSONObject json) throws JSONException {
- int width = json.getInt("width");
- int height = json.getInt("height");
- int density = json.getInt("density");
- String name = json.getString("name");
-
- JSONArray gridArray = json.getJSONArray("grids");
- String[] grids = new String[gridArray.length()];
- for (int i = 0, count = grids.length; i < count; i++) {
- grids[i] = gridArray.getString(i);
- }
-
- IntArray deviceCutout = IntArray.fromConcatString(json.getString("cutout"));
- Rect cutout = new Rect(deviceCutout.get(0), deviceCutout.get(1), deviceCutout.get(2),
- deviceCutout.get(3));
-
-
- JSONObject resourceOverridesJson = json.getJSONObject("resourceOverrides");
- Map<String, Integer> resourceOverrides = new ArrayMap<>();
- for (String key : resourceOverridesJson.keySet()) {
- resourceOverrides.put(key, resourceOverridesJson.getInt(key));
- }
- return new DeviceEmulationData(width, height, density, cutout, name, grids,
- resourceOverrides);
- }
-
- @Override
- public String toString() {
- JSONObject json = new JSONObject();
- try {
- json.put("width", width);
- json.put("height", height);
- json.put("density", density);
- json.put("name", name);
- json.put("cutout", IntArray.wrap(
- cutout.left, cutout.top, cutout.right, cutout.bottom).toConcatString());
-
- JSONArray gridArray = new JSONArray();
- Arrays.stream(grids).forEach(gridArray::put);
- json.put("grids", gridArray);
-
-
- JSONObject resourceOverrides = new JSONObject();
- for (Map.Entry<String, Integer> e : this.resourceOverrides.entrySet()) {
- resourceOverrides.put(e.getKey(), e.getValue());
- }
- json.put("resourceOverrides", resourceOverrides);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return json.toString();
- }
-
- public static DeviceEmulationData getCurrentDeviceData(Context context) {
- DisplayController.Info info = DisplayController.INSTANCE.get(context).getInfo();
- String[] grids = InvariantDeviceProfile.INSTANCE.get(context)
- .parseAllGridOptions(context).stream()
- .map(go -> go.name).toArray(String[]::new);
- String code = Build.MODEL.replaceAll("\\s", "").toLowerCase();
-
- Map<String, Integer> resourceOverrides = new ArrayMap<>();
- for (String s : EMULATED_SYSTEM_RESOURCES) {
- resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0));
- }
- return new DeviceEmulationData(info.currentSize.x, info.currentSize.y,
- info.getDensityDpi(), info.cutout, code, grids, resourceOverrides);
- }
-
- public static DeviceEmulationData getDevice(String deviceCode) throws Exception {
- return DeviceEmulationData.deviceFromJSON(readJSON().getJSONObject(deviceCode));
- }
-
- private static JSONObject readJSON() throws Exception {
- Context context = getInstrumentation().getContext();
- Resources myRes = context.getResources();
- int resId = myRes.getIdentifier("devices", "raw", context.getPackageName());
- try (InputStream is = myRes.openRawResource(resId)) {
- return new JSONObject(new String(IOUtils.toByteArray(is)));
- }
- }
-
-}
diff --git a/tests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/src/com/android/launcher3/icons/IconCacheTest.java
new file mode 100644
index 0000000..08d6df3
--- /dev/null
+++ b/tests/src/com/android/launcher3/icons/IconCacheTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutInfo.Builder;
+import android.os.PersistableBundle;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.settings.SettingsActivity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IconCacheTest {
+
+ private Context mContext;
+ private IconCache mIconCache;
+
+ private ComponentName mMyComponent;
+
+ @Before
+ public void setup() {
+ mContext = getInstrumentation().getTargetContext();
+ mMyComponent = new ComponentName(mContext, SettingsActivity.class);
+
+ // In memory icon cache
+ mIconCache = new IconCache(mContext,
+ InvariantDeviceProfile.INSTANCE.get(mContext), null,
+ new LauncherIconProvider(mContext));
+ }
+
+ @Test
+ public void getShortcutInfoBadge_nullComponent_overrideAllowed() throws Exception {
+ String overridePackage = "com.android.settings";
+ ItemInfoWithIcon item = getBadgingInfo(mContext, null, overridePackage);
+ assertTrue(item instanceof PackageItemInfo);
+ assertEquals(((PackageItemInfo) item).packageName, overridePackage);
+ }
+
+ @Test
+ public void getShortcutInfoBadge_withComponent_overrideAllowed() throws Exception {
+ String overridePackage = "com.android.settings";
+ ItemInfoWithIcon item = getBadgingInfo(mContext, mMyComponent, overridePackage);
+ assertTrue(item instanceof PackageItemInfo);
+ assertEquals(((PackageItemInfo) item).packageName, overridePackage);
+ }
+
+ @Test
+ public void getShortcutInfoBadge_nullComponent() throws Exception {
+ ItemInfoWithIcon item = getBadgingInfo(mContext, null, null);
+ assertTrue(item instanceof PackageItemInfo);
+ assertEquals(((PackageItemInfo) item).packageName, mContext.getPackageName());
+ }
+
+ @Test
+ public void getShortcutInfoBadge_withComponent() throws Exception {
+ ItemInfoWithIcon item = getBadgingInfo(mContext, mMyComponent, null);
+ assertTrue(item instanceof AppInfo);
+ assertEquals(((AppInfo) item).componentName, mMyComponent);
+ }
+
+ @Test
+ public void getShortcutInfoBadge_overrideNotAllowed() throws Exception {
+ String overridePackage = "com.android.settings";
+ String otherPackage = mContext.getPackageName() + ".does.not.exist";
+ Context otherContext = new ContextWrapper(mContext) {
+ @Override
+ public String getPackageName() {
+ return otherPackage;
+ }
+ };
+ ItemInfoWithIcon item = getBadgingInfo(otherContext, null, overridePackage);
+ assertTrue(item instanceof PackageItemInfo);
+ // Badge is set to the original package, and not the override package
+ assertEquals(((PackageItemInfo) item).packageName, otherPackage);
+ }
+
+ private ItemInfoWithIcon getBadgingInfo(Context context,
+ @Nullable ComponentName cn, @Nullable String badgeOverride) throws Exception {
+ Builder builder = new Builder(context, "test-shortcut")
+ .setIntent(new Intent(Intent.ACTION_VIEW))
+ .setTitle("Test");
+ if (cn != null) {
+ builder.setActivity(cn);
+ }
+ if (!TextUtils.isEmpty(badgeOverride)) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, badgeOverride);
+ builder.setExtras(extras);
+ }
+ ShortcutInfo info = builder.build();
+ return MODEL_EXECUTOR.submit(() -> mIconCache.getShortcutInfoBadgeItem(info)).get();
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 004ed06..2b89321 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -20,8 +20,10 @@
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
@@ -127,6 +129,38 @@
assertEquals(2, info.spanY);
}
+ @Test
+ public void testCustomProfileLoaded_with_shortcut_on_hotseat() throws Exception {
+ assumeTrue(mTargetContext.getSystemService(LauncherApps.class).hasShortcutHostPermission());
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0)
+ .putShortcut(TEST_PACKAGE, "shortcut2"));
+
+ // Verify one item in hotseat
+ assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
+ ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
+ assertEquals(LauncherSettings.Favorites.CONTAINER_HOTSEAT, info.container);
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT, info.itemType);
+ }
+
+ @Test
+ public void testCustomProfileLoaded_with_shortcut_in_folder() throws Exception {
+ assumeTrue(mTargetContext.getSystemService(LauncherApps.class).hasShortcutHostPermission());
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
+ .addApp(TEST_PACKAGE, TEST_ACTIVITY)
+ .addApp(TEST_PACKAGE, TEST_ACTIVITY)
+ .addShortcut(TEST_PACKAGE, "shortcut2")
+ .build());
+
+ // Verify folder
+ assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
+ FolderInfo info = (FolderInfo) mModelHelper.getBgDataModel().workspaceItems.get(0);
+ assertEquals(3, info.contents.size());
+
+ // Verify last icon
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
+ info.contents.get(info.contents.size() - 1).itemType);
+ }
+
private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
mModelHelper.setupDefaultLayoutProvider(builder).loadModelSync();
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index ae12861..217bec3 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -51,7 +51,6 @@
import com.android.launcher3.tapl.FolderIcon;
import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.tapl.HomeAppIcon;
-import com.android.launcher3.tapl.HomeAppIconMenu;
import com.android.launcher3.tapl.HomeAppIconMenuItem;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
@@ -391,23 +390,14 @@
.switchToAllApps();
allApps.freeze();
try {
- final HomeAppIconMenu menu = allApps
+ final HomeAppIconMenuItem menuItem = allApps
.getAppIcon(APP_NAME)
- .openDeepShortcutMenu();
- final HomeAppIconMenuItem menuItem0 = menu.getMenuItem(0);
- final HomeAppIconMenuItem menuItem2 = menu.getMenuItem(2);
+ .openDeepShortcutMenu()
+ .getMenuItem(0);
+ final String actualShortcutName = menuItem.getText();
+ final String expectedShortcutName = "Shortcut 1";
- final HomeAppIconMenuItem menuItem;
-
- final String expectedShortcutName = "Shortcut 3";
- if (menuItem0.getText().equals(expectedShortcutName)) {
- menuItem = menuItem0;
- } else {
- final String shortcutName2 = menuItem2.getText();
- assertEquals("Wrong menu item", expectedShortcutName, shortcutName2);
- menuItem = menuItem2;
- }
-
+ assertEquals(expectedShortcutName, actualShortcutName);
menuItem.dragToWorkspace(false, false);
mLauncher.getWorkspace().getWorkspaceAppIcon(expectedShortcutName)
.launch(getAppPackageName());
@@ -525,14 +515,8 @@
try {
Workspace workspace = mLauncher.getWorkspace();
final HomeAllApps allApps = workspace.switchToAllApps();
- allApps.freeze();
- try {
- workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
- // After the toast clears, then the model tries to commit the uninstall transaction
- mLauncher.waitForModelQueueCleared();
- } finally {
- allApps.unfreeze();
- }
+ workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
+ waitForLauncherUIUpdate();
verifyAppUninstalledFromAllApps(workspace, DUMMY_APP_NAME);
} finally {
TestUtil.uninstallDummyApp();
@@ -633,6 +617,10 @@
private void installDummyAppAndWaitForUIUpdate() throws IOException {
TestUtil.installDummyApp();
+ waitForLauncherUIUpdate();
+ }
+
+ private void waitForLauncherUIUpdate() {
// Wait for model thread completion as it may be processing
// the install event from the SystemService
mLauncher.waitForModelQueueCleared();
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index b783d91..54da7de 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -177,6 +177,7 @@
}
@Test
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/243688989
public void testEdu() {
assumeTrue(mWorkProfileSetupSuccessful);
waitForWorkTabSetup();
diff --git a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
index 4e21dce..ba01b04 100644
--- a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
+++ b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
@@ -39,6 +39,7 @@
private static final String TAG_AUTO_INSTALL = "autoinstall";
private static final String TAG_FOLDER = "folder";
private static final String TAG_APPWIDGET = "appwidget";
+ private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_EXTRA = "extra";
private static final String ATTR_CONTAINER = "container";
@@ -49,6 +50,7 @@
private static final String ATTR_TITLE = "title";
private static final String ATTR_TITLE_TEXT = "titleText";
private static final String ATTR_SCREEN = "screen";
+ private static final String ATTR_SHORTCUT_ID = "shortcutId";
// x and y can be specified as negative integers, in which case -1 represents the
// last row / column, -2 represents the second last, and so on.
@@ -135,6 +137,13 @@
return LauncherLayoutBuilder.this;
}
+ public LauncherLayoutBuilder putShortcut(String packageName, String shortcutId) {
+ items.put(ATTR_PACKAGE_NAME, packageName);
+ items.put(ATTR_SHORTCUT_ID, shortcutId);
+ mNodes.add(Pair.create(TAG_SHORTCUT, items));
+ return LauncherLayoutBuilder.this;
+ }
+
public LauncherLayoutBuilder putWidget(String packageName, String className,
int spanX, int spanY) {
items.put(ATTR_PACKAGE_NAME, packageName);
@@ -175,6 +184,14 @@
return this;
}
+ public FolderBuilder addShortcut(String packageName, String shortcutId) {
+ HashMap<String, Object> items = new HashMap<>();
+ items.put(ATTR_PACKAGE_NAME, packageName);
+ items.put(ATTR_SHORTCUT_ID, shortcutId);
+ mChildren.add(Pair.create(TAG_SHORTCUT, items));
+ return this;
+ }
+
public LauncherLayoutBuilder build() {
return LauncherLayoutBuilder.this;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 2d4d2cd..885707c 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -147,6 +147,9 @@
getAppsListRecyclerBottomPadding());
verifyActiveContainer();
final int newScroll = getAllAppsScroll();
+ LauncherInstrumentation.log(
+ String.format("tryGetAppIcon: scrolled from %d to %d", scroll,
+ newScroll));
mLauncher.assertTrue(
"Scrolled in a wrong direction in AllApps: from " + scroll + " to "
+ newScroll, newScroll >= scroll);
@@ -259,8 +262,7 @@
}
private int getAllAppsScroll() {
- return mLauncher.getTestInfo(
- TestProtocol.REQUEST_APPS_LIST_SCROLL_Y)
+ return mLauncher.getTestInfo(TestProtocol.REQUEST_APPS_LIST_SCROLL_Y)
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 8cdc8a0..54be3c3 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -49,4 +49,10 @@
}
}
}
+
+ /** Returns true if an item matching the given string is present in the menu. */
+ public boolean hasMenuItem(String expectedMenuItemText) {
+ UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText));
+ return menuItem != null;
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index c1c26ec..79b54ba 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -182,12 +182,6 @@
UiObject2 widgetListView = verifyActiveContainer();
UiObject2 header = mLauncher.waitForObjectInContainer(widgetListView,
headerSelector);
- // If we are in a tablet in landscape mode then we will have a two pane view and we use
- // the right pane to display the widgets table.
- UiObject2 rightPane = mLauncher.findObjectInContainer(
- widgetPicker,
- widgetsContainerSelector);
-
// If a header is barely visible in the bottom edge of the screen, its height could be
// too small for a scroll gesture. Since all header should have roughly the same height,
// let's pick the max height we have seen so far.
@@ -209,6 +203,12 @@
mLauncher.clickLauncherObject(headerTitle);
}
+ // If we are in a tablet in landscape mode then we will have a two pane view and we
+ // use the right pane to display the widgets table.
+ UiObject2 rightPane = mLauncher.findObjectInContainer(
+ widgetPicker,
+ widgetsContainerSelector);
+
// Look for a widgets list.
UiObject2 widgetsContainer = mLauncher.findObjectInContainer(
rightPane != null ? rightPane : widgetListView,
@@ -219,6 +219,13 @@
}
}
log("Finding test widget package - scroll with distance: " + scrollDistance);
+
+ // If we are in a tablet in landscape mode then we will have a two pane view and we use
+ // the right pane to display the widgets table.
+ UiObject2 rightPane = mLauncher.findObjectInContainer(
+ widgetPicker,
+ widgetsContainerSelector);
+
mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null
? rightPane
: widgetListView, scrollDistance);