Merge "Prevent workspace enter animation for predictive back" into tm-qpr-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9123959..a77791f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,4 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
+
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check ${PREUPLOAD_FILES}
\ No newline at end of file
diff --git a/go/quickstep/res/values-b+sr+Latn/strings.xml b/go/quickstep/res/values-b+sr+Latn/strings.xml
index 749fc0e..263f011 100644
--- a/go/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/go/quickstep/res/values-b+sr+Latn/strings.xml
@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_share_drop_target_label" msgid="5804774105974539508">"Дели апликацију"</string>
- <string name="action_listen" msgid="2370304050784689486">"Пусти"</string>
- <string name="action_translate" msgid="8028378961867277746">"Преведи"</string>
- <string name="action_search" msgid="6269564710943755464">"Објектив"</string>
- <string name="dialog_acknowledge" msgid="2804025517675853172">"ВАЖИ"</string>
- <string name="dialog_cancel" msgid="6464336969134856366">"ОТКАЖИ"</string>
- <string name="dialog_settings" msgid="6564397136021186148">"ПОДЕШАВАЊА"</string>
- <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Преводите или слушајте текст на екрану"</string>
- <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Информације попут текста на екрану, веб-адреса и снимака екрана могу да се деле са Google-ом.\n\nДа бисте променили информације које делите, идите у "<b>"Подешавања > Апликације > Подразумеване апликације > Апликација дигиталног помоћника"</b>"."</string>
- <string name="assistant_not_selected_title" msgid="5017072974603345228">"Одаберите помоћника да бисте користили ову функцију"</string>
- <string name="assistant_not_selected_text" msgid="3244613673884359276">"Да бисте чули текст са екрана или га превели, одаберите апликацију дигиталног помоћника у Подешавањима"</string>
- <string name="assistant_not_supported_title" msgid="1675788067597484142">"Промените помоћника да бисте користили ову функцију"</string>
- <string name="assistant_not_supported_text" msgid="1708031078549268884">"Да бисте чули текст са екрана или га превели, промените апликацију дигиталног помоћника у Подешавањима"</string>
- <string name="tooltip_listen" msgid="7634466447860989102">"Додирните овде да бисте чули текст са овог екрана"</string>
- <string name="tooltip_translate" msgid="4184845868901542567">"Додирните овде да бисте превели текст са овог екрана"</string>
- <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Ова апликација не може да се дели"</string>
+ <string name="app_share_drop_target_label" msgid="5804774105974539508">"Deli aplikaciju"</string>
+ <string name="action_listen" msgid="2370304050784689486">"Pusti"</string>
+ <string name="action_translate" msgid="8028378961867277746">"Prevedi"</string>
+ <string name="action_search" msgid="6269564710943755464">"Objektiv"</string>
+ <string name="dialog_acknowledge" msgid="2804025517675853172">"VAŽI"</string>
+ <string name="dialog_cancel" msgid="6464336969134856366">"OTKAŽI"</string>
+ <string name="dialog_settings" msgid="6564397136021186148">"PODEŠAVANJA"</string>
+ <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Prevodite ili slušajte tekst na ekranu"</string>
+ <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Informacije poput teksta na ekranu, veb-adresa i snimaka ekrana mogu da se dele sa Google-om.\n\nDa biste promenili informacije koje delite, idite u "<b>"Podešavanja > Aplikacije > Podrazumevane aplikacije > Aplikacija digitalnog pomoćnika"</b>"."</string>
+ <string name="assistant_not_selected_title" msgid="5017072974603345228">"Odaberite pomoćnika da biste koristili ovu funkciju"</string>
+ <string name="assistant_not_selected_text" msgid="3244613673884359276">"Da biste čuli tekst sa ekrana ili ga preveli, odaberite aplikaciju digitalnog pomoćnika u Podešavanjima"</string>
+ <string name="assistant_not_supported_title" msgid="1675788067597484142">"Promenite pomoćnika da biste koristili ovu funkciju"</string>
+ <string name="assistant_not_supported_text" msgid="1708031078549268884">"Da biste čuli tekst sa ekrana ili ga preveli, promenite aplikaciju digitalnog pomoćnika u Podešavanjima"</string>
+ <string name="tooltip_listen" msgid="7634466447860989102">"Dodirnite ovde da biste čuli tekst sa ovog ekrana"</string>
+ <string name="tooltip_translate" msgid="4184845868901542567">"Dodirnite ovde da biste preveli tekst sa ovog ekrana"</string>
+ <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Ova aplikacija ne može da se deli"</string>
</resources>
diff --git a/go/src/com/android/launcher3/model/LoaderResults.java b/go/src/com/android/launcher3/model/LauncherBinder.java
similarity index 82%
rename from go/src/com/android/launcher3/model/LoaderResults.java
rename to go/src/com/android/launcher3/model/LauncherBinder.java
index 5f71061..437d8ca 100644
--- a/go/src/com/android/launcher3/model/LoaderResults.java
+++ b/go/src/com/android/launcher3/model/LauncherBinder.java
@@ -22,11 +22,11 @@
import com.android.launcher3.model.BgDataModel.Callbacks;
/**
- * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
*/
-public class LoaderResults extends BaseLoaderResults {
+public class LauncherBinder extends BaseLauncherBinder {
- public LoaderResults(LauncherAppState app, BgDataModel dataModel,
+ public LauncherBinder(LauncherAppState app, BgDataModel dataModel,
AllAppsList allAppsList, Callbacks[] callbacks) {
super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
}
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 7e5b85c..bd11c1e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,6 +28,19 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
+ <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+ separately through RecentsView#resetFromSplitSelectionState() -->
+ <ImageView
+ android:id="@+id/show_windows"
+ android:layout_height="@dimen/recents_filter_icon_size"
+ android:layout_width="@dimen/recents_filter_icon_size"
+ android:layout_gravity="end"
+ android:alpha="0"
+ android:tint="@color/recents_filter_icon"
+ android:contentDescription="@string/recents_filter_icon_desc"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_select_windows" />
+
<com.android.quickstep.views.IconView
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index cd5bcbd..ec03c69 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -38,6 +38,32 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
+ <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+ separately through RecentsView#resetFromSplitSelectionState() -->
+ <ImageView
+ android:id="@+id/show_windows"
+ android:layout_height="@dimen/recents_filter_icon_size"
+ android:layout_width="@dimen/recents_filter_icon_size"
+ android:layout_gravity="start"
+ android:alpha="0"
+ android:tint="@color/recents_filter_icon"
+ android:contentDescription="@string/recents_filter_icon_desc"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_select_windows" />
+
+ <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+ separately through RecentsView#resetFromSplitSelectionState() -->
+ <ImageView
+ android:id="@+id/show_windows_right"
+ android:layout_height="@dimen/recents_filter_icon_size"
+ android:layout_width="@dimen/recents_filter_icon_size"
+ android:layout_gravity="end"
+ android:alpha="0"
+ android:tint="@color/recents_filter_icon"
+ android:contentDescription="@string/recents_filter_icon_desc"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_select_windows" />
+
<com.android.quickstep.views.IconView
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index 79d087a..6b665e5 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -13,10 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
<com.android.launcher3.views.IconButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/taskbar_icon_touch_size"
- android:layout_height="@dimen/taskbar_icon_touch_size"
+ android:layout_width="@dimen/taskbar_icon_min_touch_size"
+ android:layout_height="@dimen/taskbar_icon_min_touch_size"
android:contentDescription="@string/all_apps_button_label"
android:backgroundTint="@android:color/transparent"
android:icon="@drawable/ic_all_apps_button"
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 047e05f..df9fe66 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -95,12 +95,9 @@
<string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"የተግባር አሞሌ ትምህርት"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string>
- <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
- <skip />
- <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
- <skip />
- <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
- <skip />
+ <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"በአንድ ጊዜ 2 መተግበሪያዎችን ለመጠቀም ወደ ጎን ይጎትቱ"</string>
+ <string name="taskbar_edu_stashing" msgid="2805035263048176462">"የተግባር አሞሌውን ለማሳየት አጭር ወደ ላይ ያንሸራትቱ"</string>
+ <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"የተግባር አሞሌው የዕለት ተዕለት ተግባርዎ ላይ በመመስረት መተግበሪያዎችን ይጠቁማል"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ተመለስ"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 6e819ab..2699c3e 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -19,98 +19,98 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
- <string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
- <string name="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="task_view_closed" msgid="9170038230110856166">"Задатак је затворен"</string>
+ <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
+ <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
+ <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
+ <string name="task_view_closed" msgid="9170038230110856166">"Zadatak je zatvoren"</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>
- <string name="time_left_for_app" msgid="3111996412933644358">"Још <xliff:g id="TIME">%1$s</xliff:g> данас"</string>
- <string name="title_app_suggestions" msgid="4185902664111965088">"Предлози апликација"</string>
- <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Предвиђене апликације"</string>
- <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Добијајте предлоге апликација у доњем реду почетног екрана"</string>
- <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Добијајте предлоге апликација у реду са омиљеним ставкама на почетном екрану"</string>
- <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Лако приступајте апликацијама које најчешће користите директно са почетног екрана. Предлози се мењају на основу употребе. Апликације из доњег реда се премештају нагоре на почетни екран."</string>
- <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Лако приступајте апликацијама које најчешће користите директно са почетног екрана. Предлози се мењају на основу ваших рутина. Апликације из реда са омиљеним ставкама се премештају на почетни екран."</string>
- <string name="hotseat_edu_accept" msgid="1611544083278999837">"Приказуј предлоге апликација"</string>
- <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Не, хвала"</string>
- <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Подешавања"</string>
- <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Овде се приказују најчешће коришћене апликације и мењају се у зависности од употребе"</string>
- <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Превуците апликације из доњег реда да бисте добили предлоге"</string>
- <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Предлози апликација се додају на празно место"</string>
- <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Предлози апликација су омогућени"</string>
- <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Предлози апликација су онемогућени"</string>
- <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Предвиђамо апликацију: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Обавезно превуците од саме десне или леве ивице."</string>
- <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Обавезно превуците од десне или леве ивице до средине екрана и отпустите."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Довршили сте покрет за повратак."</string>
- <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Никако не превлачите превише близу дна екрана."</string>
- <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Осетљивост пок. за назад можете да промените у Подешавањима"</string>
- <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>
- <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>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Довршили сте покрет за повратак на почетну страницу. Сада сазнајте како да се вратите."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Довршили сте покрет за повратак на почетну страницу."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Превуците да бисте отишли на почетну страницу"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Превуците нагоре од дна екрана. Овај покрет вас увек води на почетни екран."</string>
- <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Превуците помоћу два прста нагоре од дна екрана. Овим покретом увек отварате почетни екран."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Обавезно превуците нагоре од доње ивице екрана."</string>
- <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Пробајте да држите прозор дуже пре отпуштања."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Обавезно превуците право нагоре, па застаните."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Научили сте како да користите покрете. Да бисте искључили покрете, идите на подешавања."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Довршили сте покрет за промену апликација."</string>
- <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>
- <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>
- <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Пробајте поново"</string>
- <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Свака част!"</string>
- <string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Превуците нагоре да бисте отворили почетни екран"</string>
- <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
- <string name="default_device_name" msgid="6660656727127422487">"уређај"</string>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string>
- <string name="action_share" msgid="2648470652637092375">"Дели"</string>
- <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
- <string name="action_split" msgid="2098009717623550676">"Подели"</string>
- <string name="toast_split_select_app" msgid="5453865907322018352">"Додирните другу апликацију за подељени екран"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
- <string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
- <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Можете да пронађете ово касније у апликацији <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
- <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескочи"</string>
- <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string>
- <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Упутства на траци задатака"</string>
- <string name="taskbar_edu_opened" msgid="3950252793551919129">"Едукативно окно из траке задатака се појавило"</string>
- <string name="taskbar_edu_closed" msgid="126643734478892862">"Едукативно окно из траке задатака је затворено"</string>
- <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Превуците на страну да бисте користили 2 апликације одједном"</string>
- <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Накратко превуците нагоре да бисте приказали траку задатака"</string>
- <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Трака задатака предлаже апликације на основу рутине"</string>
- <string name="taskbar_edu_next" msgid="4007618274426775841">"Даље"</string>
- <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
- <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
- <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
- <string name="taskbar_button_home" msgid="2151398979630664652">"Почетна"</string>
- <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>
- <string name="taskbar_button_notifications" msgid="7471740351507357318">"Обавештења"</string>
- <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брза подешавања"</string>
- <string name="taskbar_a11y_title" msgid="6432169809852243110">"Трака задатака"</string>
- <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</string>
- <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
- <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
+ <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
+ <string name="time_left_for_app" msgid="3111996412933644358">"Još <xliff:g id="TIME">%1$s</xliff:g> danas"</string>
+ <string name="title_app_suggestions" msgid="4185902664111965088">"Predlozi aplikacija"</string>
+ <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Predviđene aplikacije"</string>
+ <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Dobijajte predloge aplikacija u donjem redu početnog ekrana"</string>
+ <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Dobijajte predloge aplikacija u redu sa omiljenim stavkama na početnom ekranu"</string>
+ <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Lako pristupajte aplikacijama koje najčešće koristite direktno sa početnog ekrana. Predlozi se menjaju na osnovu upotrebe. Aplikacije iz donjeg reda se premeštaju nagore na početni ekran."</string>
+ <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Lako pristupajte aplikacijama koje najčešće koristite direktno sa početnog ekrana. Predlozi se menjaju na osnovu vaših rutina. Aplikacije iz reda sa omiljenim stavkama se premeštaju na početni ekran."</string>
+ <string name="hotseat_edu_accept" msgid="1611544083278999837">"Prikazuj predloge aplikacija"</string>
+ <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Ne, hvala"</string>
+ <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Podešavanja"</string>
+ <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Ovde se prikazuju najčešće korišćene aplikacije i menjaju se u zavisnosti od upotrebe"</string>
+ <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Prevucite aplikacije iz donjeg reda da biste dobili predloge"</string>
+ <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Predlozi aplikacija se dodaju na prazno mesto"</string>
+ <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Predlozi aplikacija su omogućeni"</string>
+ <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Predlozi aplikacija su onemogućeni"</string>
+ <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđamo aplikaciju: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Obavezno prevucite od same desne ili leve ivice."</string>
+ <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Dovršili ste pokret za povratak."</string>
+ <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Nikako ne prevlačite previše blizu dna ekrana."</string>
+ <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osetljivost pok. za nazad možete da promenite u Podešavanjima"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Prevucite da biste se vratili unazad"</string>
+ <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Da biste se vratili na poslednji ekran, prevucite od leve ili desne ivice do sredine ekrana."</string>
+ <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Da biste se vratili na poslednji ekran, prevucite pomoću dva prsta od leve ili desne ivice do sredine ekrana."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Obavezno prevucite nagore od donje ivice ekrana."</string>
+ <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Nikako ne stajte pre otpuštanja."</string>
+ <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Obavezno prevucite pravo nagore."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Dovršili ste pokret za povratak na početnu stranicu. Sada saznajte kako da se vratite."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Dovršili ste pokret za povratak na početnu stranicu."</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Prevucite da biste otišli na početnu stranicu"</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite nagore od dna ekrana. Ovaj pokret vas uvek vodi na početni ekran."</string>
+ <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prevucite pomoću dva prsta nagore od dna ekrana. Ovim pokretom uvek otvarate početni ekran."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Obavezno prevucite nagore od donje ivice ekrana."</string>
+ <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Probajte da držite prozor duže pre otpuštanja."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Obavezno prevucite pravo nagore, pa zastanite."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako da koristite pokrete. Da biste isključili pokrete, idite na podešavanja."</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Dovršili ste pokret za promenu aplikacija."</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da biste zamenili aplikacije"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Za prelazak sa jedne aplikacije na drugu prevucite nagore od dna ekrana, zadržite, pa pustite."</string>
+ <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Za prelazak između aplikacija prevucite pomoću dva prsta nagore od dna ekrana, zadržite, pa pustite."</string>
+ <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"To je to"</string>
+ <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gotovo"</string>
+ <string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Podešavanja"</string>
+ <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Probajte ponovo"</string>
+ <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Svaka čast!"</string>
+ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string>
+ <string name="allset_hint" msgid="2384632994739392447">"Prevucite nagore da biste otvorili početni ekran"</string>
+ <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+ <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string>
+ <string name="action_share" msgid="2648470652637092375">"Deli"</string>
+ <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
+ <string name="action_split" msgid="2098009717623550676">"Podeli"</string>
+ <string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string>
+ <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
+ <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete da pronađete ovo kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
+ <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string>
+ <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Uputstva na traci zadataka"</string>
+ <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukativno okno iz trake zadataka se pojavilo"</string>
+ <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukativno okno iz trake zadataka je zatvoreno"</string>
+ <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Prevucite na stranu da biste koristili 2 aplikacije odjednom"</string>
+ <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Nakratko prevucite nagore da biste prikazali traku zadataka"</string>
+ <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka zadataka predlaže aplikacije na osnovu rutine"</string>
+ <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
+ <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string>
+ <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
+ <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
+ <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"Pristupačnost"</string>
+ <string name="taskbar_button_back" msgid="8558862226461164514">"Nazad"</string>
+ <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME prebacivač"</string>
+ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedavno"</string>
+ <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obaveštenja"</string>
+ <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brza podešavanja"</string>
+ <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
+ <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string>
+ <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
+ <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 86ea264..c7664be 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -78,7 +78,7 @@
<string name="allset_title" msgid="5021126669778966707">"Fertig!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Nach oben wischen, um den Startbildschirm aufzurufen"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Startbildschirmtaste drücken, um zum Startbildschirm zu gehen"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) jetzt verwenden"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein <xliff:g id="DEVICE">%1$s</xliff:g> jetzt verwenden"</string>
<string name="default_device_name" msgid="6660656727127422487">"Gerät"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 6e01d06..8722476 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -95,12 +95,9 @@
<string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"הסבר על סרגל האפליקציות"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string>
- <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
- <skip />
- <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
- <skip />
- <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
- <skip />
+ <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור לצד"</string>
+ <string name="taskbar_edu_stashing" msgid="2805035263048176462">"צריך להחליק מעט כדי להציג את סרגל האפליקציות"</string>
+ <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"האפליקציות מוצעות בסרגל האפליקציות על סמך השימוש השגרתי שלך"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"הבא"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"חזרה"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
index 28f7c5d..d27561a 100644
--- a/quickstep/res/values-sw720dp/dimens.xml
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -40,4 +40,5 @@
<!-- Transient taskbar -->
<dimen name="transient_taskbar_size">76dp</dimen>
+ <dimen name="transient_taskbar_icon_size">52dp</dimen>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 8213a8b..5a9e0a1 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -96,8 +96,8 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string>
<string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"拖曳到一邊即可同時使用 2 個應用程式"</string>
- <string name="taskbar_edu_stashing" msgid="2805035263048176462">"稍微向上滑動即可讓工作列顯示在畫面上"</string>
- <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據你的日常習慣提供應用程式建議"</string>
+ <string name="taskbar_edu_stashing" msgid="2805035263048176462">"輕輕向上滑動即可顯示工作列"</string>
+ <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據您的日常安排提供應用程式建議"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 185c815..f63997b 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -76,4 +76,7 @@
<color name="all_set_page_background">#FFFFFFFF</color>
+ <!-- Recents overview -->
+ <color name="recents_filter_icon">#333333</color>
+
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index ad77768..2eb4abc 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -255,7 +255,10 @@
<!-- Taskbar -->
<dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
<dimen name="taskbar_ime_size">48dp</dimen>
- <dimen name="taskbar_icon_touch_size">48dp</dimen>
+ <dimen name="taskbar_icon_size">44dp</dimen>
+ <dimen name="taskbar_icon_min_touch_size">48dp</dimen>
+ <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
+ <dimen name="taskbar_icon_spacing">12dp</dimen>
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
<dimen name="taskbar_folder_margin">16dp</dimen>
<dimen name="taskbar_contextual_button_padding">16dp</dimen>
@@ -282,11 +285,11 @@
<!-- Transient taskbar -->
<dimen name="transient_taskbar_size">72dp</dimen>
+ <dimen name="transient_taskbar_icon_size">48dp</dimen>
<dimen name="transient_taskbar_margin">24dp</dimen>
<dimen name="transient_taskbar_shadow_blur">40dp</dimen>
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
<dimen name="transient_taskbar_stashed_size">32dp</dimen>
- <dimen name="transient_taskbar_icon_spacing">10dp</dimen>
<!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
<dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
<!-- Taskbar swipe up thresholds -->
@@ -306,6 +309,9 @@
<dimen name="taskbar_button_margin_6_5">75dp</dimen>
<dimen name="taskbar_button_margin_default">48dp</dimen>
+ <!-- Recents overview -->
+ <dimen name="recents_filter_icon_size">30dp</dimen>
+
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
<!-- starting_surface_exit_animation_window_shift_length -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 801ba26..e691522 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -36,6 +36,13 @@
<!-- Recents: Title of a button that clears the task list, i.e. closes all tasks. [CHAR LIMIT=30] -->
<string name="recents_clear_all">Clear all</string>
+ <!-- Recents: Title of a button that goes back from displaying tasks filtered by package name to displaying all tasks [CHAR LIMIT=30] -->
+ <string name="recents_back" translatable="false">Back</string>
+
+ <!-- TODO: b/260610444. Content description of filtering icons needs to be updated -->
+ <!-- Recents: Content description for the icon on top of taskviews to initiate filtering -->
+ <string name="recents_filter_icon_desc" translatable="false">Click to show only this app\'s tasks</string>
+
<!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] -->
<string name="accessibility_recent_apps">Recent apps</string>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 95a94ec..9f9f2c8 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -28,12 +28,15 @@
import android.content.Context;
import android.os.Build;
import android.os.Handler;
+import android.os.RemoteException;
+import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.systemui.animation.RemoteAnimationDelegate;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import java.lang.ref.WeakReference;
@@ -89,7 +92,7 @@
Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
- getFactory().onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
+ getFactory().onAnimationStart(transit, appTargets, wallpaperTargets, nonAppTargets,
mAnimationResult);
};
if (mStartAtFrontOfQueue) {
@@ -124,7 +127,11 @@
});
}
- public static final class AnimationResult {
+ /**
+ * Used by RemoteAnimationFactory implementations to run the actual animation and its lifecycle
+ * callbacks.
+ */
+ public static final class AnimationResult extends IRemoteAnimationFinishedCallback.Stub {
private final Runnable mSyncFinishRunnable;
private final Runnable mASyncFinishRunnable;
@@ -199,25 +206,41 @@
}
}
}
+
+ /**
+ * When used as a simple IRemoteAnimationFinishedCallback, this method is used to run the
+ * animation finished runnable.
+ */
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ mASyncFinishRunnable.run();
+ }
}
/**
* Used with LauncherAnimationRunner as an interface for the runner to call back to the
* implementation.
*/
- @FunctionalInterface
- public interface RemoteAnimationFactory {
+ public interface RemoteAnimationFactory extends RemoteAnimationDelegate<AnimationResult> {
/**
* Called on the UI thread when the animation targets are received. The implementation must
* call {@link AnimationResult#setAnimation} with the target animation to be run.
*/
- void onCreateAnimation(int transit,
+ @Override
+ @UiThread
+ void onAnimationStart(int transit,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
RemoteAnimationTarget[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result);
+ @Override
+ @UiThread
+ default void onAnimationCancelled(boolean isKeyguardOccluded) {
+ onAnimationCancelled();
+ }
+
/**
* Called when the animation is cancelled. This can happen with or without
* the create being called.
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 71d1296..aa9e272 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1666,7 +1666,7 @@
}
@Override
- public void onCreateAnimation(int transit,
+ public void onAnimationStart(int transit,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
RemoteAnimationTarget[] nonAppTargets,
@@ -1709,7 +1709,7 @@
}
@Override
- public void onCreateAnimation(int transit,
+ public void onAnimationStart(int transit,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
RemoteAnimationTarget[] nonAppTargets,
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index bbc0627..ae121e2 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -33,6 +33,7 @@
private boolean mFreeformTasksVisible;
private boolean mInOverviewState;
+ private boolean mGestureInProgress;
public DesktopVisibilityController(Launcher launcher) {
mLauncher = launcher;
@@ -57,9 +58,24 @@
* Sets whether freeform windows are visible and updates launcher visibility based on that.
*/
public void setFreeformTasksVisible(boolean freeformTasksVisible) {
+ if (!isDesktopModeSupported()) {
+ return;
+ }
if (freeformTasksVisible != mFreeformTasksVisible) {
mFreeformTasksVisible = freeformTasksVisible;
- updateLauncherVisibility();
+ if (mFreeformTasksVisible) {
+ setLauncherViewsVisibility(View.INVISIBLE);
+ if (!mInOverviewState) {
+ // When freeform is visible & we're not in overview, we want launcher to appear
+ // paused, this ensures that taskbar displays.
+ markLauncherPaused();
+ }
+ } else {
+ setLauncherViewsVisibility(View.VISIBLE);
+ // If freeform isn't visible ensure that launcher appears resumed to behave
+ // normally.
+ markLauncherResumed();
+ }
}
}
@@ -67,40 +83,67 @@
* Sets whether the overview is visible and updates launcher visibility based on that.
*/
public void setOverviewStateEnabled(boolean overviewStateEnabled) {
+ if (!isDesktopModeSupported()) {
+ return;
+ }
if (overviewStateEnabled != mInOverviewState) {
mInOverviewState = overviewStateEnabled;
- updateLauncherVisibility();
+ if (mInOverviewState) {
+ setLauncherViewsVisibility(View.VISIBLE);
+ markLauncherResumed();
+ } else if (mFreeformTasksVisible) {
+ setLauncherViewsVisibility(View.INVISIBLE);
+ markLauncherPaused();
+ }
}
}
/**
- * Updates launcher visibility and state to look like it is paused or resumed depending on
- * whether freeform windows are showing in desktop mode.
+ * Whether recents gesture is currently in progress.
*/
- private void updateLauncherVisibility() {
- StatefulActivity<LauncherState> activity =
- QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
- View workspaceView = mLauncher.getWorkspace();
- if (activity == null || workspaceView == null || !isDesktopModeSupported()) {
+ public boolean isGestureInProgress() {
+ return mGestureInProgress;
+ }
+
+ /**
+ * Sets whether recents gesture is in progress.
+ */
+ public void setGestureInProgress(boolean gestureInProgress) {
+ if (!isDesktopModeSupported()) {
return;
}
+ if (gestureInProgress != mGestureInProgress) {
+ mGestureInProgress = gestureInProgress;
+ }
+ }
- if (mFreeformTasksVisible) {
- workspaceView.setVisibility(View.INVISIBLE);
- if (!mInOverviewState) {
- // When freeform is visible & we're not in overview, we want launcher to appear
- // paused, this ensures that taskbar displays.
- activity.setPaused();
- }
- } else {
- workspaceView.setVisibility(View.VISIBLE);
- // If freeform isn't visible ensure that launcher appears resumed to behave normally.
- // Check activity state before calling setResumed(). Launcher may have been actually
- // paused (eg fullscreen task moved to front).
- // In this case we should not mark the activity as resumed.
- if (activity.isResumed()) {
- activity.setResumed();
- }
+ private void setLauncherViewsVisibility(int visibility) {
+ View workspaceView = mLauncher.getWorkspace();
+ if (workspaceView != null) {
+ workspaceView.setVisibility(visibility);
+ }
+ View dragLayer = mLauncher.getDragLayer();
+ if (dragLayer != null) {
+ dragLayer.setVisibility(visibility);
+ }
+ }
+
+ private void markLauncherPaused() {
+ StatefulActivity<LauncherState> activity =
+ QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
+ if (activity != null) {
+ activity.setPaused();
+ }
+ }
+
+ private void markLauncherResumed() {
+ StatefulActivity<LauncherState> activity =
+ QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
+ // Check activity state before calling setResumed(). Launcher may have been actually
+ // paused (eg fullscreen task moved to front).
+ // In this case we should not mark the activity as resumed.
+ if (activity != null && activity.isResumed()) {
+ activity.setResumed();
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 22f7f13..a18aabe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -310,7 +310,7 @@
return;
}
mTaskbarInAppDisplayProgress.put(progressIndex, progress);
- if (!mControllers.taskbarStashController.isInApp()
+ if (mControllers.uiController.isIconAlignedWithHotseat()
&& !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
// Only animate the nav buttons while home and not animating home, otherwise let
// the TaskbarViewController handle it.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 731eea7..4e795d9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -598,9 +598,6 @@
}
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
- if (!isUserSetupComplete()) {
- return;
- }
mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
.updateValue(darkIntensity);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ff7e8e9..cf3af08 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -16,20 +16,17 @@
package com.android.launcher3.taskbar
-import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.launcher3.Utilities.mapToRange
-
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import com.android.launcher3.R
+import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.anim.Interpolators
+import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
import com.android.launcher3.util.DisplayController
-/**
- * Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners.
- */
+/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
val paint: Paint = Paint()
@@ -39,7 +36,7 @@
private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
- private val isTransientTaskbar = DisplayController.isTransientTaskbar(context);
+ private val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
private var shadowBlur = 0f
private var keyShadowDistance = 0f
@@ -98,9 +95,7 @@
invertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE)
}
- /**
- * Draws the background with the given paint and height, on the provided canvas.
- */
+ /** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
canvas.save()
canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
@@ -124,21 +119,26 @@
canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
// Draw shadow.
- val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
- Interpolators.LINEAR)
- paint.setShadowLayer(shadowBlur, 0f, keyShadowDistance,
+ val shadowAlpha =
+ mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f, Interpolators.LINEAR)
+ paint.setShadowLayer(
+ shadowBlur,
+ 0f,
+ keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
)
// Draw background.
- val radius = backgroundHeight / 2f;
+ val radius = backgroundHeight / 2f
canvas.drawRoundRect(
transientBackgroundBounds.left + (delta / 2f),
translationYForSwipe,
transientBackgroundBounds.right - (delta / 2f),
backgroundHeight + translationYForSwipe,
- radius, radius, paint
+ radius,
+ radius,
+ paint
)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index a48b88f..9f24565 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -36,10 +36,8 @@
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import java.io.PrintWriter
-/**
- * Handles the insets that Taskbar provides to underlying apps and the IME.
- */
-class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController {
+/** Handles the insets that Taskbar provides to underlying apps and the IME. */
+class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
/** The bottom insets taskbar provides to the IME when IME is visible. */
val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
@@ -77,13 +75,19 @@
fun onTaskbarWindowHeightOrInsetsChanged() {
val touchableHeight = controllers.taskbarStashController.touchableHeight
- touchableRegion.set(0, windowLayoutParams.height - touchableHeight,
- context.deviceProfile.widthPx, windowLayoutParams.height)
+ touchableRegion.set(
+ 0,
+ windowLayoutParams.height - touchableHeight,
+ context.deviceProfile.widthPx,
+ windowLayoutParams.height
+ )
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
for (provider in windowLayoutParams.providedInsets) {
- if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR
- || provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) {
+ if (
+ provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
+ provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES
+ ) {
provider.insetsSize = getInsetsByNavMode(contentHeight)
} else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
provider.insetsSize = getInsetsByNavMode(tappableHeight)
@@ -91,24 +95,20 @@
}
val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
- val insetsSizeOverride = arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(
- TYPE_INPUT_METHOD,
- imeInsetsSize
- ),
- )
+ val insetsSizeOverride =
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ )
// Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0)
- val insetsSizeOverrideForGestureNavTappableElement = arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(
- TYPE_INPUT_METHOD,
- imeInsetsSize
- ),
- InsetsFrameProvider.InsetsSizeOverride(
- TYPE_VOICE_INTERACTION,
- visInsetsSizeForGestureNavTappableElement
- ),
- )
+ val insetsSizeOverrideForGestureNavTappableElement =
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ InsetsFrameProvider.InsetsSizeOverride(
+ TYPE_VOICE_INTERACTION,
+ visInsetsSizeForGestureNavTappableElement
+ ),
+ )
for (provider in windowLayoutParams.providedInsets) {
if (context.isGestureNav && provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
@@ -120,9 +120,11 @@
/**
* @return [Insets] where the [bottomInset] is either used as a bottom inset or
+ * ```
* right/left inset if using 3 button nav
+ * ```
*/
- private fun getInsetsByNavMode(bottomInset: Int) : Insets {
+ private fun getInsetsByNavMode(bottomInset: Int): Insets {
val devicePortrait = !context.deviceProfile.isLandscape
if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
// Taskbar or portrait phone mode
@@ -139,9 +141,9 @@
* @param providesInsetsTypes The inset types we would like this layout params to provide.
*/
fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
- params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size);
+ params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
for (i in providesInsetsTypes.indices) {
- params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i]);
+ params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
}
}
@@ -153,14 +155,17 @@
insetsInfo.touchableRegion.setEmpty()
// Always have nav buttons be touchable
controllers.navbarButtonsViewController.addVisibleButtonsRegion(
- context.dragLayer, insetsInfo.touchableRegion
+ context.dragLayer,
+ insetsInfo.touchableRegion
)
var insetsIsTouchableRegion = true
if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
- } else if (controllers.navbarButtonsViewController.isImeVisible
- && controllers.taskbarStashController.isStashed()) {
+ } else if (
+ controllers.navbarButtonsViewController.isImeVisible &&
+ controllers.taskbarStashController.isStashed()
+ ) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
} else if (!controllers.uiController.isTaskbarTouchable) {
// Let touches pass through us.
@@ -174,9 +179,10 @@
insetsInfo.touchableRegion.set(touchableRegion)
}
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
- } else if (controllers.taskbarViewController.areIconsVisible()
- || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
- || context.isNavBarKidsModeActive
+ } else if (
+ controllers.taskbarViewController.areIconsVisible() ||
+ AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) ||
+ context.isNavBarKidsModeActive
) {
// Taskbar has some touchable elements, take over the full taskbar area
insetsInfo.setTouchableInsets(
@@ -198,8 +204,12 @@
pw.println(prefix + "TaskbarInsetsController:")
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
for (provider in windowLayoutParams.providedInsets) {
- pw.print("$prefix\tprovidedInsets: (type=" + InsetsState.typeToString(provider.type)
- + " insetsSize=" + provider.insetsSize)
+ pw.print(
+ "$prefix\tprovidedInsets: (type=" +
+ InsetsState.typeToString(provider.type) +
+ " insetsSize=" +
+ provider.insetsSize
+ )
if (provider.insetsSizeOverrides != null) {
pw.print(" insetsSizeOverrides={")
for ((i, overrideSize) in provider.insetsSizeOverrides.withIndex()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 049c672..98c45d5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -32,7 +32,6 @@
import android.os.Handler;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -227,10 +226,6 @@
mActivity = activity;
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
getUnfoldTransitionProgressProviderForActivity(activity);
- if (unfoldTransitionProgressProvider == null) {
- Log.e("b/261320823", "UnfoldTransitionProgressProvider null in setActivity. "
- + "Unfold animation for launcher will not work.");
- }
mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider);
if (mTaskbarActivityContext != null) {
@@ -320,6 +315,12 @@
}
}
+ public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) {
+ if (mNavButtonController != null) {
+ mNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
+ }
+ }
+
/**
* Sets the flag indicating setup UI is visible
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index a395548..5bb958a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -67,6 +67,7 @@
private long mLastScreenPinLongPress;
private boolean mScreenPinned;
+ private boolean mAssistantLongPressEnabled;
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
@@ -251,6 +252,10 @@
mStatsLogManager = null;
}
+ public void setAssistantLongPressEnabled(boolean assistantLongPressEnabled) {
+ mAssistantLongPressEnabled = assistantLongPressEnabled;
+ }
+
private void logEvent(StatsLogManager.LauncherEvent event) {
if (mStatsLogManager == null) {
Log.w(TAG, "No stats log manager to log taskbar button event");
@@ -289,7 +294,7 @@
}
private void startAssistant() {
- if (mScreenPinned) {
+ if (mScreenPinned || !mAssistantLongPressEnabled) {
return;
}
Bundle args = new Bundle();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c269648..6031b49 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -364,7 +364,12 @@
* Returns the height that taskbar will be touchable.
*/
public int getTouchableHeight() {
- return mIsStashed ? mStashedHeight : mUnstashedHeight;
+ int bottomMargin = 0;
+ if (DisplayController.isTransientTaskbar(mActivity)) {
+ bottomMargin = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.transient_taskbar_margin);
+ }
+ return mIsStashed ? mStashedHeight : (mUnstashedHeight + bottomMargin);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 2433a34..2fcd64b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -101,16 +101,15 @@
super(context, attrs, defStyleAttr, defStyleRes);
mActivityContext = ActivityContext.lookupContext(context);
mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
- mIsRtl = Utilities.isRtl(getResources());
-
Resources resources = getResources();
- mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
+ mIsRtl = Utilities.isRtl(resources);
- int actualMargin = DisplayController.isTransientTaskbar(mActivityContext)
- ? resources.getDimensionPixelSize(R.dimen.transient_taskbar_icon_spacing)
- : resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
+ mIconTouchSize = Math.max(actualIconSize,
+ resources.getDimensionPixelSize(R.dimen.taskbar_icon_min_touch_size));
+
// We layout the icons to be of mIconTouchSize in width and height
mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2;
mItemPadding = (mIconTouchSize - actualIconSize) / 2;
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index a033507..be34fb1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -10,12 +10,9 @@
private const val TASKBAR_ICONS_FADE_DURATION = 300L
private const val STASHED_HANDLE_FADE_DURATION = 180L
-/**
- * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing.
- */
-class VoiceInteractionWindowController(val context: TaskbarActivityContext)
- : TaskbarControllers.LoggableTaskbarController,
- TaskbarControllers.BackgroundRendererController {
+/** Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. */
+class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
+ TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
@@ -37,8 +34,10 @@
override fun draw(canvas: Canvas) {
super.draw(canvas)
- if (this@VoiceInteractionWindowController.context.isGestureNav
- && controllers.taskbarStashController.isInAppAndNotStashed) {
+ if (
+ this@VoiceInteractionWindowController.context.isGestureNav &&
+ controllers.taskbarStashController.isInAppAndNotStashed
+ ) {
taskbarBackgroundRenderer.draw(canvas)
}
}
@@ -46,8 +45,8 @@
separateWindowForTaskbarBackground.recreateControllers()
separateWindowForTaskbarBackground.setWillNotDraw(false)
- separateWindowLayoutParams = context.createDefaultWindowLayoutParams(
- TYPE_APPLICATION_OVERLAY)
+ separateWindowLayoutParams =
+ context.createDefaultWindowLayoutParams(TYPE_APPLICATION_OVERLAY)
separateWindowLayoutParams.isSystemApplicationOverlay = true
}
@@ -63,14 +62,16 @@
// Fade out taskbar icons and stashed handle.
val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
- val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha
- .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
- .animateToValue(taskbarIconAlpha)
- .setDuration(TASKBAR_ICONS_FADE_DURATION)
- val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha
- .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
- .animateToValue(taskbarIconAlpha)
- .setDuration(STASHED_HANDLE_FADE_DURATION)
+ val fadeTaskbarIcons =
+ controllers.taskbarViewController.taskbarIconAlpha
+ .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+ .animateToValue(taskbarIconAlpha)
+ .setDuration(TASKBAR_ICONS_FADE_DURATION)
+ val fadeStashedHandle =
+ controllers.stashedHandleViewController.stashedHandleAlpha
+ .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+ .animateToValue(taskbarIconAlpha)
+ .setDuration(STASHED_HANDLE_FADE_DURATION)
fadeTaskbarIcons.start()
fadeStashedHandle.start()
if (skipAnim) {
@@ -83,23 +84,30 @@
/**
* Either:
+ *
* Hides the TaskbarDragLayer background and creates a new window to draw just that background.
+ *
* OR
+ *
* Removes the temporary window and show the TaskbarDragLayer background again.
*/
private fun moveTaskbarBackgroundToAppropriateLayer(skipAnim: Boolean) {
- val taskbarBackgroundOverride = controllers.taskbarDragLayerController
- .overrideBackgroundAlpha
+ val taskbarBackgroundOverride =
+ controllers.taskbarDragLayerController.overrideBackgroundAlpha
val moveToLowerLayer = isVoiceInteractionWindowVisible
- val onWindowsSynchronized = if (moveToLowerLayer) {
- // First add the temporary window, then hide the overlapping taskbar background.
- context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams);
- { taskbarBackgroundOverride.updateValue(0f) }
- } else {
- // First reapply the original taskbar background, then remove the temporary window.
- taskbarBackgroundOverride.updateValue(1f);
- { context.removeWindowView(separateWindowForTaskbarBackground) }
- }
+ val onWindowsSynchronized =
+ if (moveToLowerLayer) {
+ // First add the temporary window, then hide the overlapping taskbar background.
+ context.addWindowView(
+ separateWindowForTaskbarBackground,
+ separateWindowLayoutParams
+ );
+ { taskbarBackgroundOverride.updateValue(0f) }
+ } else {
+ // First reapply the original taskbar background, then remove the temporary window.
+ taskbarBackgroundOverride.updateValue(1f);
+ { context.removeWindowView(separateWindowForTaskbarBackground) }
+ }
if (skipAnim) {
onWindowsSynchronized()
@@ -121,4 +129,4 @@
pw.println(prefix + "VoiceInteractionWindowController:")
pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index 68ea27a..a82902f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -30,20 +30,17 @@
* [navButtonContainer]
*
* @property navButtonContainer ViewGroup that holds the 3 navigation buttons.
- * @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME dismiss).
+ * @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME
+ * dismiss).
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
*/
abstract class AbstractNavButtonLayoutter(
- val resources: Resources,
- val navButtonContainer: LinearLayout,
- protected val endContextualContainer: ViewGroup,
- protected val startContextualContainer: ViewGroup
+ val resources: Resources,
+ val navButtonContainer: LinearLayout,
+ protected val endContextualContainer: ViewGroup,
+ protected val startContextualContainer: ViewGroup
) : NavButtonLayoutter {
- protected val homeButton: ImageView = navButtonContainer
- .findViewById(R.id.home)
- protected val recentsButton: ImageView = navButtonContainer
- .findViewById(R.id.recent_apps)
- protected val backButton: ImageView = navButtonContainer
- .findViewById(R.id.back)
+ protected val homeButton: ImageView = navButtonContainer.findViewById(R.id.home)
+ protected val recentsButton: ImageView = navButtonContainer.findViewById(R.id.recent_apps)
+ protected val backButton: ImageView = navButtonContainer.findViewById(R.id.back)
}
-
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index c67ab79..c093c92 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -35,56 +35,47 @@
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_HOME_KIDS
class KidsNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
-) {
+ ) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
- val iconSize: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_ICON_SIZE_KIDS)
- val buttonWidth: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
- val buttonHeight: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
- val buttonRadius: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
+ val iconSize: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_ICON_SIZE_KIDS)
+ val buttonWidth: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
+ val buttonHeight: Int =
+ resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
+ val buttonRadius: Int =
+ resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
val paddingLeft = (buttonWidth - iconSize) / 2
val paddingTop = (buttonHeight - iconSize) / 2
// Update icons
- backButton.setImageDrawable(
- backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
+ backButton.setImageDrawable(backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
backButton.scaleType = ImageView.ScaleType.FIT_CENTER
backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
- homeButton.setImageDrawable(
- homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
+ homeButton.setImageDrawable(homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
homeButton.scaleType = ImageView.ScaleType.FIT_CENTER
homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
// Home button layout
- val homeLayoutparams = LinearLayout.LayoutParams(
- buttonWidth,
- buttonHeight
- )
- val homeButtonLeftMargin: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
+ val homeLayoutparams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
+ val homeButtonLeftMargin: Int =
+ resources.getDimensionPixelSize(DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0)
homeButton.layoutParams = homeLayoutparams
// Back button layout
- val backLayoutParams = LinearLayout.LayoutParams(
- buttonWidth,
- buttonHeight
- )
- val backButtonLeftMargin: Int = resources.getDimensionPixelSize(
- DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
+ val backLayoutParams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
+ val backButtonLeftMargin: Int =
+ resources.getDimensionPixelSize(DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0)
backButton.layoutParams = backLayoutParams
@@ -106,4 +97,4 @@
homeButton.onLongClickListener = null
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index db0a2d8..2092721 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -30,10 +30,9 @@
/**
* Select the correct layout for nav buttons
*
- * Since layouts are done dynamically for the nav buttons on Taskbar, this
- * class returns a corresponding [NavButtonLayoutter] via
- * [Companion.getUiLayoutter]
- * that can help position the buttons based on the current [DeviceProfile]
+ * Since layouts are done dynamically for the nav buttons on Taskbar, this class returns a
+ * corresponding [NavButtonLayoutter] via [Companion.getUiLayoutter] that can help position the
+ * buttons based on the current [DeviceProfile]
*/
class NavButtonLayoutFactory {
companion object {
@@ -41,11 +40,10 @@
* Get the correct instance of [NavButtonLayoutter]
*
* No layouts supported for configurations where:
- * * taskbar isn't showing AND
- * * the device is not in [phoneMode]
- * OR
- * * phone is showing
- * * device is using gesture navigation
+ * * taskbar isn't showing AND
+ * * the device is not in [phoneMode] OR
+ * * phone is showing
+ * * device is using gesture navigation
*
* @param navButtonsView ViewGroup that contains start, end, nav button ViewGroups
* @param isKidsMode no-op when taskbar is hidden/not showing
@@ -53,44 +51,64 @@
* @param phoneMode refers to the device using the taskbar window on phones
* @param isThreeButtonNav are no-ops when taskbar is present/showing
*/
- fun getUiLayoutter(deviceProfile: DeviceProfile,
- navButtonsView: FrameLayout,
- resources: Resources,
- isKidsMode: Boolean,
- isInSetup: Boolean,
- isThreeButtonNav: Boolean,
- phoneMode: Boolean):
- NavButtonLayoutter {
- val navButtonContainer =
- navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
+ fun getUiLayoutter(
+ deviceProfile: DeviceProfile,
+ navButtonsView: FrameLayout,
+ resources: Resources,
+ isKidsMode: Boolean,
+ isInSetup: Boolean,
+ isThreeButtonNav: Boolean,
+ phoneMode: Boolean
+ ): NavButtonLayoutter {
+ val navButtonContainer = navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
val endContextualContainer =
- navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
+ navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
val startContextualContainer =
- navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
+ navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
val isPhoneNavMode = phoneMode && isThreeButtonNav
return when {
isPhoneNavMode -> {
if (!deviceProfile.isLandscape) {
- PhonePortraitNavLayoutter(resources, navButtonContainer,
- endContextualContainer, startContextualContainer)
+ PhonePortraitNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
} else {
- PhoneLandscapeNavLayoutter(resources, navButtonContainer,
- endContextualContainer, startContextualContainer)
+ PhoneLandscapeNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
}
}
deviceProfile.isTaskbarPresent -> {
return when {
isInSetup -> {
- SetupNavLayoutter(resources, navButtonContainer, endContextualContainer,
- startContextualContainer)
+ SetupNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
}
isKidsMode -> {
- KidsNavLayoutter(resources, navButtonContainer, endContextualContainer,
- startContextualContainer)
+ KidsNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
}
else ->
- TaskbarNavLayoutter(resources, navButtonContainer, endContextualContainer,
- startContextualContainer)
+ TaskbarNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
}
}
else -> error("No layoutter found")
@@ -98,8 +116,8 @@
}
}
- /** Lays out and provides access to the home, recents, and back buttons for various mischief */
+ /** Lays out and provides access to the home, recents, and back buttons for various mischief */
interface NavButtonLayoutter {
fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean)
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index a89476e..201895f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -28,24 +28,24 @@
import com.android.launcher3.util.DimensionUtils
class PhoneLandscapeNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
-) {
+ ) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
- val endStartMargins =
- resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
- val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
- TaskbarManager.isPhoneMode(dp))
+ val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+ val taskbarDimensions =
+ DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
navButtonContainer.removeAllViews()
navButtonContainer.orientation = LinearLayout.VERTICAL
@@ -68,7 +68,7 @@
// Add the spaces in between the nav buttons
val spaceInBetween: Int =
- resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
+ resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
navButtonContainer.children.forEachIndexed { i, navButton ->
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
buttonLayoutParams.weight = 1f
@@ -86,4 +86,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index 275f59f..f7ac974 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -26,17 +26,24 @@
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
-class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup) :
- AbstractNavButtonLayoutter(resources, navBarContainer, endContextualContainer,
- startContextualContainer) {
+class PhonePortraitNavLayoutter(
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ AbstractNavButtonLayoutter(
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer
+ ) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
- val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
- TaskbarManager.isPhoneMode(dp))
+ val taskbarDimensions =
+ DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
navContainerParams.width = taskbarDimensions.x
navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
@@ -58,7 +65,7 @@
// Add the spaces in between the nav buttons
val spaceInBetween =
- resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
+ resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
for (i in 0 until navButtonContainer.childCount) {
val navButton = navButtonContainer.getChildAt(i)
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -80,4 +87,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index afe70d6..a24002c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -24,16 +24,17 @@
import com.android.launcher3.DeviceProfile
class SetupNavLayoutter(
- resources: Resources,
- navButtonContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+ resources: Resources,
+ navButtonContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ AbstractNavButtonLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
-) {
+ ) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// Since setup wizard only has back button enabled, it looks strange to be
@@ -46,4 +47,4 @@
}
navButtonContainer.requestLayout()
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index b2ca2af..5ec7ca0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -24,20 +24,19 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
-/**
- * Layoutter for showing 3 button navigation on large screen
- */
+/** Layoutter for showing 3 button navigation on large screen */
class TaskbarNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
-) {
+ ) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// Add spacing after the end of the last nav button
@@ -80,4 +79,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9be569e..a7651b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -43,7 +43,6 @@
import static com.android.launcher3.testing.shared.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -63,15 +62,18 @@
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.SystemProperties;
-import android.util.Log;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.RemoteAnimationTarget;
import android.view.View;
import android.view.WindowManagerGlobal;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
+import android.window.OnBackInvokedDispatcher;
import android.window.SplashScreen;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.app.viewcapture.ViewCapture;
@@ -105,6 +107,8 @@
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.uioverrides.QuickstepWidgetHolder.QuickstepHolderFactory;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
@@ -623,6 +627,29 @@
}
}
+ @Override
+ protected void registerBackDispatcher() {
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ new OnBackAnimationCallback() {
+ @Override
+ public void onBackInvoked() {
+ onBackPressed();
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
+ }
+
+ @Override
+ public void onBackProgressed(@NonNull BackEvent backEvent) {
+ QuickstepLauncher.this.onBackProgressed(backEvent.getProgress());
+ }
+
+ @Override
+ public void onBackCancelled() {
+ QuickstepLauncher.this.onBackCancelled();
+ }
+ });
+ }
+
private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) {
if (mTaskbarManager == null
|| mTaskbarManager.getCurrentActivityContext() == null
@@ -668,7 +695,8 @@
public void setResumed() {
if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
DesktopVisibilityController controller = mDesktopVisibilityController;
- if (controller != null && controller.areFreeformTasksVisible()) {
+ if (controller != null && controller.areFreeformTasksVisible()
+ && !controller.isGestureInProgress()) {
// Return early to skip setting activity to appear as resumed
// TODO(b/255649902): shouldn't be needed when we have a separate launcher state
// for desktop that we can use to control other parts of launcher
@@ -721,7 +749,7 @@
getSystemService(SensorManager.class),
getMainThreadHandler(),
getMainExecutor(),
- /* backgroundExecutor= */ THREAD_POOL_EXECUTOR,
+ /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
/* tracingTagPrefix= */ "launcher",
WindowManagerGlobal.getWindowManagerService()
);
@@ -738,7 +766,6 @@
mUnfoldTransitionProgressProvider,
mRotationChangeProvider
);
- Log.d("b/261320823", "initUnfoldTransitionProgressProvider completed");
}
}
@@ -1001,6 +1028,14 @@
mPendingSplitSelectInfo = null;
}
+ @Override
+ public boolean areFreeformTasksVisible() {
+ if (mDesktopVisibilityController != null) {
+ return mDesktopVisibilityController.areFreeformTasksVisible();
+ }
+ return false;
+ }
+
private static final class LauncherTaskViewController extends
TaskViewTouchController<Launcher> {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 733c6a8..95eb128 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -28,6 +28,7 @@
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
/**
@@ -91,6 +92,12 @@
@Override
protected float getDepthUnchecked(Context context) {
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ if (Launcher.getLauncher(context).areFreeformTasksVisible()) {
+ // Don't blur the background while freeform tasks are visible
+ return 0;
+ }
+ }
return 1;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index 969abc2..7392469 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -17,10 +17,13 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
+import android.graphics.Color;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
+import com.android.quickstep.views.DesktopTaskView;
/**
* State to indicate we are about to launch a recent task. Note that this state is only used when
@@ -43,6 +46,12 @@
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ if (launcher.areFreeformTasksVisible()) {
+ // No scrim while freeform tasks are visible
+ return Color.TRANSPARENT;
+ }
+ }
DeviceProfile dp = launcher.getDeviceProfile();
if (dp.isTaskbarPresentInApps) {
return launcher.getColor(R.color.taskbar_background);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 857ace2..a2adbd7 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -323,6 +323,10 @@
private final boolean mIsTransientTaskbar;
// May be set to false when mIsTransientTaskbar is true.
private boolean mCanSlowSwipeGoHome = true;
+ private boolean mHasReachedOverviewThreshold = false;
+
+ @Nullable
+ private RemoteAnimationTargets.ReleaseCheck mSwipePipToHomeReleaseCheck = null;
public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
@@ -762,6 +766,10 @@
private void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask, boolean animate) {
if (mIsLikelyToStartNewTask != isLikelyToStartNewTask) {
+ if (isLikelyToStartNewTask && mIsTransientTaskbar) {
+ setDividerShown(false /* shown */, true /* immediate */);
+ }
+
mIsLikelyToStartNewTask = isLikelyToStartNewTask;
maybeUpdateRecentsAttachedState(animate);
}
@@ -869,6 +877,9 @@
mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets);
mRecentsAnimationController = controller;
mRecentsAnimationTargets = targets;
+ mSwipePipToHomeReleaseCheck = new RemoteAnimationTargets.ReleaseCheck();
+ mSwipePipToHomeReleaseCheck.setCanRelease(true);
+ mRecentsAnimationTargets.addReleaseCheck(mSwipePipToHomeReleaseCheck);
// Only initialize the device profile, if it has not been initialized before, as in some
// configurations targets.homeContentInsets may not be correct.
@@ -1430,9 +1441,16 @@
mSwipePipToHomeAnimator = createWindowAnimationToPip(
homeAnimFactory, runningTaskTarget, start);
mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator;
+ if (mSwipePipToHomeReleaseCheck != null) {
+ mSwipePipToHomeReleaseCheck.setCanRelease(false);
+ }
windowAnim = mSwipePipToHomeAnimators;
} else {
mSwipePipToHomeAnimator = null;
+ if (mSwipePipToHomeReleaseCheck != null) {
+ mSwipePipToHomeReleaseCheck.setCanRelease(true);
+ mSwipePipToHomeReleaseCheck = null;
+ }
windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
windowAnim[0].addAnimatorListener(new AnimationSuccessListener() {
@@ -1656,7 +1674,9 @@
mRecentsAnimationController.enableInputConsumer();
// Start hiding the divider
- setDividerShown(false /* shown */, true /* immediate */);
+ if (!mIsTransientTaskbar || mTaskbarAlreadyOpen || mIsTaskbarAllAppsOpen) {
+ setDividerShown(false /* shown */, true /* immediate */);
+ }
}
private void computeRecentsScrollIfInvisible() {
@@ -1954,6 +1974,10 @@
finishRecentsControllerToHome(
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
+ if (mSwipePipToHomeReleaseCheck != null) {
+ mSwipePipToHomeReleaseCheck.setCanRelease(true);
+ mSwipePipToHomeReleaseCheck = null;
+ }
doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
}
@@ -2288,6 +2312,10 @@
// "Catch up" with the displacement at mTaskbarCatchUpThreshold.
if (displacement < mTaskbarCatchUpThreshold) {
+ if (!mHasReachedOverviewThreshold) {
+ setDividerShown(false /* shown */, true /* immediate */);
+ mHasReachedOverviewThreshold = true;
+ }
return Utilities.mapToRange(displacement, mTaskbarAppWindowThreshold,
mTaskbarCatchUpThreshold, 0, mTaskbarCatchUpThreshold, ACCEL_DEACCEL);
}
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index b3e1878..03042c9 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -36,6 +36,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.window.BackEvent;
+import android.window.BackMotionEvent;
import android.window.BackProgressAnimator;
import android.window.IOnBackInvokedCallback;
@@ -134,14 +135,14 @@
}
@Override
- public void onBackProgressed(BackEvent backEvent) {
+ public void onBackProgressed(BackMotionEvent backEvent) {
handler.post(() -> {
mProgressAnimator.onBackProgressed(backEvent);
});
}
@Override
- public void onBackStarted(BackEvent backEvent) {
+ public void onBackStarted(BackMotionEvent backEvent) {
handler.post(() -> {
startBack(backEvent);
mProgressAnimator.onBackStarted(backEvent, event -> {
@@ -185,7 +186,7 @@
mBackCallback = null;
}
- private void startBack(BackEvent backEvent) {
+ private void startBack(BackMotionEvent backEvent) {
mBackInProgress = true;
RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index d46565b..b33ceca 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -45,6 +45,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Manages the recent task list from the system, caching it as necessary.
@@ -129,14 +131,18 @@
* @return The change id of the current task list
*/
public synchronized int getTasks(boolean loadKeysOnly,
- Consumer<ArrayList<GroupTask>> callback) {
+ Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
// so that requestID can be returned first.
if (callback != null) {
// Copy synchronously as the changeId might change by next frame
- ArrayList<GroupTask> result = copyOf(mResultsUi);
+ // and filter GroupTasks
+ ArrayList<GroupTask> result = mResultsUi.stream().filter(filter)
+ .map(GroupTask::copy)
+ .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
+
mMainThreadExecutor.post(() -> {
callback.accept(result);
});
@@ -156,7 +162,11 @@
mLoadingTasksInBackground = false;
mResultsUi = loadResult;
if (callback != null) {
- ArrayList<GroupTask> result = copyOf(mResultsUi);
+ // filter the tasks if needed before passing them into the callback
+ ArrayList<GroupTask> result = mResultsUi.stream().filter(filter)
+ .map(GroupTask::copy)
+ .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
+
callback.accept(result);
}
});
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index dc405ff..6f86bf5 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -240,7 +240,7 @@
mActivityLaunchAnimationRunner = new RemoteAnimationFactory() {
@Override
- public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets,
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
RemoteAnimationTarget[] nonAppTargets, AnimationResult result) {
mHandler.removeCallbacks(mAnimationStartTimeoutRunnable);
@@ -407,28 +407,24 @@
}
private final RemoteAnimationFactory mAnimationToHomeFactory =
- new RemoteAnimationFactory() {
- @Override
- public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets,
- RemoteAnimationTarget[] nonAppTargets, AnimationResult result) {
- AnimatorPlaybackController controller = getStateManager()
- .createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
- controller.dispatchOnStart();
+ (transit, appTargets, wallpaperTargets, nonAppTargets, result) -> {
+ AnimatorPlaybackController controller =
+ getStateManager().createAnimationToNewWorkspace(
+ RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
+ controller.dispatchOnStart();
- RemoteAnimationTargets targets = new RemoteAnimationTargets(
- appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
- for (RemoteAnimationTarget app : targets.apps) {
- new Transaction().setAlpha(app.leash, 1).apply();
- }
- AnimatorSet anim = new AnimatorSet();
- anim.play(controller.getAnimationPlayer());
- anim.setDuration(HOME_APPEAR_DURATION);
- result.setAnimation(anim, RecentsActivity.this,
- () -> getStateManager().goToState(RecentsState.HOME, false),
- true /* skipFirstFrame */);
- }
- };
+ RemoteAnimationTargets targets = new RemoteAnimationTargets(
+ appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
+ for (RemoteAnimationTarget app : targets.apps) {
+ new Transaction().setAlpha(app.leash, 1).apply();
+ }
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(controller.getAnimationPlayer());
+ anim.setDuration(HOME_APPEAR_DURATION);
+ result.setAnimation(anim, RecentsActivity.this,
+ () -> getStateManager().goToState(RecentsState.HOME, false),
+ true /* skipFirstFrame */);
+ };
@Override
protected void collectStateHandlers(List<StateHandler> out) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 9e25555..f1c0f3e 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,7 +17,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
@@ -50,10 +49,8 @@
import android.graphics.Region;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.os.UserManager;
import android.provider.Settings;
import android.view.MotionEvent;
@@ -63,9 +60,9 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SettingsCache;
-import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -109,15 +106,6 @@
private final boolean mIsOneHandedModeSupported;
private boolean mPipIsActive;
- private boolean mIsUserUnlocked;
- private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
- private final SimpleBroadcastReceiver mUserUnlockedReceiver = new SimpleBroadcastReceiver(i -> {
- if (ACTION_USER_UNLOCKED.equals(i.getAction())) {
- mIsUserUnlocked = true;
- notifyUserUnlocked();
- }
- });
-
private int mGestureBlockingTaskId = -1;
private @NonNull Region mExclusionRegion = new Region();
private SystemGestureExclusionListenerCompat mExclusionListener;
@@ -143,14 +131,6 @@
runOnDestroy(mRotationTouchHelper::destroy);
}
- // Register for user unlocked if necessary
- mIsUserUnlocked = context.getSystemService(UserManager.class)
- .isUserUnlocked(Process.myUserHandle());
- if (!mIsUserUnlocked) {
- mUserUnlockedReceiver.register(mContext, ACTION_USER_UNLOCKED);
- }
- runOnDestroy(() -> mUserUnlockedReceiver.unregisterReceiverSafely(mContext));
-
// Register for exclusion updates
mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
@Override
@@ -310,39 +290,12 @@
}
/**
- * Adds a callback for when a user is unlocked. If the user is already unlocked, this listener
- * will be called back immediately.
- */
- public void runOnUserUnlocked(Runnable action) {
- if (mIsUserUnlocked) {
- action.run();
- } else {
- mUserUnlockedActions.add(action);
- }
- }
-
- /**
- * @return whether the user is unlocked.
- */
- public boolean isUserUnlocked() {
- return mIsUserUnlocked;
- }
-
- /**
* @return whether the user has completed setup wizard
*/
public boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
- private void notifyUserUnlocked() {
- for (Runnable action : mUserUnlockedActions) {
- action.run();
- }
- mUserUnlockedActions.clear();
- mUserUnlockedReceiver.unregisterReceiverSafely(mContext);
- }
-
/**
* Sets the task id where gestures should be blocked
*/
@@ -585,7 +538,7 @@
pw.println(" assistantAvailable=" + mAssistantAvailable);
pw.println(" assistantDisabled="
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
- pw.println(" isUserUnlocked=" + mIsUserUnlocked);
+ pw.println(" isUserUnlocked=" + LockedUserState.get(mContext).isUserUnlocked());
pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
pw.println(" deferredGestureRegion=" + mDeferredGestureRegion.getBounds());
diff --git a/quickstep/src/com/android/quickstep/RecentsFilterState.java b/quickstep/src/com/android/quickstep/RecentsFilterState.java
new file mode 100644
index 0000000..ff6951d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsFilterState.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import androidx.annotation.Nullable;
+
+import com.android.quickstep.util.GroupTask;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * Keeps track of the state of {@code RecentsView}.
+ *
+ * <p> More specifically, used for keeping track of the state of filters applied on tasks
+ * in {@code RecentsView} for multi-instance management.
+ */
+public class RecentsFilterState {
+ // the minimum number of tasks per package present to allow filtering
+ public static final int MIN_FILTERING_TASK_COUNT = 2;
+
+ // default filter that returns true for any input
+ public static final Predicate<GroupTask> DEFAULT_FILTER = (groupTask -> true);
+
+ // the package name to filter recent tasks by
+ @Nullable
+ private String mPackageNameToFilter = null;
+
+ // the callback that gets executed upon filter change
+ @Nullable
+ private Runnable mOnFilterUpdatedListener = null;
+
+ // map maintaining the count for each unique base activity package name currently in the recents
+ @Nullable
+ private Map<String, Integer> mInstanceCountMap;
+
+ /**
+ * Returns {@code true} if {@code RecentsView} filters tasks by some package name.
+ */
+ public boolean isFiltered() {
+ return mPackageNameToFilter != null;
+ }
+
+ /**
+ * Returns the package name that tasks are filtered by.
+ */
+ @Nullable
+ public String getPackageNameToFilter() {
+ return mPackageNameToFilter;
+ }
+
+
+ /**
+ * Sets a listener on any changes to the filter.
+ *
+ * @param callback listener to be executed upon filter updates
+ */
+ public void setOnFilterUpdatedListener(@Nullable Runnable callback) {
+ mOnFilterUpdatedListener = callback;
+ }
+
+ /**
+ * Updates the filter such that tasks are filtered by a certain package name.
+ *
+ * @param packageName package name of the base activity to filter tasks by;
+ * if null, filter is turned off
+ */
+ public void setFilterBy(@Nullable String packageName) {
+ if (Objects.equals(packageName, mPackageNameToFilter)) {
+ return;
+ }
+
+ mPackageNameToFilter = packageName;
+
+ if (mOnFilterUpdatedListener != null) {
+ mOnFilterUpdatedListener.run();
+ }
+ }
+
+ /**
+ * Updates the map of package names to their count in the most recent list of tasks.
+ *
+ * @param groupTaskList the list of tasks that map update is be based on
+ */
+ public void updateInstanceCountMap(List<GroupTask> groupTaskList) {
+ mInstanceCountMap = getInstanceCountMap(groupTaskList);
+ }
+
+ /**
+ * Returns the map of package names to their count in the most recent list of tasks.
+ */
+ @Nullable
+ public Map<String, Integer> getInstanceCountMap() {
+ return mInstanceCountMap;
+ }
+
+ /**
+ * Returns a predicate for filtering out GroupTasks by package name.
+ *
+ * @param packageName package name to filter GroupTasks by
+ * if null, Predicate always returns true.
+ */
+ public static Predicate<GroupTask> getFilter(@Nullable String packageName) {
+ if (packageName == null) {
+ return DEFAULT_FILTER;
+ }
+
+ return (groupTask) -> (groupTask.task2 != null
+ && groupTask.task2.key.getPackageName().equals(packageName))
+ || groupTask.task1.key.getPackageName().equals(packageName);
+ }
+
+ /**
+ * Returns a map of package names to their frequencies in a list of GroupTasks.
+ *
+ * @param groupTasks the list to go through to create the map
+ */
+ public static Map<String, Integer> getInstanceCountMap(List<GroupTask> groupTasks) {
+ Map<String, Integer> instanceCountMap = new HashMap<>();
+
+ for (GroupTask groupTask : groupTasks) {
+ final String firstTaskPkgName = groupTask.task1.key.getPackageName();
+ final String secondTaskPkgName =
+ groupTask.task2 == null ? null : groupTask.task2.key.getPackageName();
+
+ // increment the instance count for the first task's base activity package name
+ incrementOrAddIfNotExists(instanceCountMap, firstTaskPkgName);
+
+ // check if second task is non existent
+ if (secondTaskPkgName != null) {
+ // increment the instance count for the second task's base activity package name
+ incrementOrAddIfNotExists(instanceCountMap, secondTaskPkgName);
+ }
+ }
+
+ return instanceCountMap;
+ }
+
+ /**
+ * Returns true if tasks of provided package name should show filter UI.
+ *
+ * @param taskPackageName package name of the task in question
+ */
+ public boolean shouldShowFilterUI(String taskPackageName) {
+ // number of occurrences in recents overview with the package name of this task
+ int instanceCount = getInstanceCountMap().get(taskPackageName);
+
+ // if the number of occurrences isn't enough make sure tasks can't be filtered by
+ // the package name of this task
+ return !(isFiltered() || instanceCount < MIN_FILTERING_TASK_COUNT);
+ }
+
+ private static void incrementOrAddIfNotExists(Map<String, Integer> map, String pkgName) {
+ if (!map.containsKey(pkgName)) {
+ map.put(pkgName, 0);
+ }
+ map.put(pkgName, map.get(pkgName) + 1);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 3d6da8e..913f08f 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -50,6 +50,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Singleton class to load and manage recents model.
@@ -104,7 +105,22 @@
* @return the request id associated with this call.
*/
public int getTasks(Consumer<ArrayList<GroupTask>> callback) {
- return mTaskList.getTasks(false /* loadKeysOnly */, callback);
+ return mTaskList.getTasks(false /* loadKeysOnly */, callback,
+ RecentsFilterState.DEFAULT_FILTER);
+ }
+
+
+ /**
+ * Fetches the list of recent tasks, based on a filter
+ *
+ * @param callback The callback to receive the task plan once its complete or null. This is
+ * always called on the UI thread.
+ * @param filter Returns true if a GroupTask should be included into the list passed into
+ * callback.
+ * @return the request id associated with this call.
+ */
+ public int getTasks(Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+ return mTaskList.getTasks(false /* loadKeysOnly */, callback, filter);
}
/**
@@ -126,8 +142,9 @@
* Checks if a task has been removed or not.
*
* @param callback Receives true if task is removed, false otherwise
+ * @param filter Returns true if GroupTask should be in the list of considerations
*/
- public void isTaskRemoved(int taskId, Consumer<Boolean> callback) {
+ public void isTaskRemoved(int taskId, Consumer<Boolean> callback, Predicate<GroupTask> filter) {
mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> {
for (GroupTask group : taskGroups) {
if (group.containsTask(taskId)) {
@@ -136,7 +153,7 @@
}
}
callback.accept(true);
- });
+ }, filter);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index b7252bc..67de4b1 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -22,6 +22,8 @@
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_DELAY_NAV_FADE_IN;
@@ -330,6 +332,17 @@
Matrix localMti = new Matrix();
localMt.invert(localMti);
mti[i] = localMti;
+
+ // Translations for child thumbnails also get scaled as the parent taskView scales
+ // Add inverse scaling to keep translations the same
+ float translationY = ttv.getTranslationY();
+ float translationX = ttv.getTranslationX();
+ float fullScreenScale =
+ topMostSimulators[i].getTaskViewSimulator().getFullScreenScale();
+ out.addFloat(ttv, VIEW_TRANSLATE_Y, translationY,
+ translationY / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR);
+ out.addFloat(ttv, VIEW_TRANSLATE_X, translationX,
+ translationX / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR);
}
Matrix[] k0i = new Matrix[matrixSize];
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 2565697..d19f124 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -87,6 +87,7 @@
import com.android.launcher3.tracing.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
@@ -216,10 +217,12 @@
@BinderThread
@Override
- public void onAssistantAvailable(boolean available) {
+ public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) {
MAIN_EXECUTOR.execute(() -> {
mDeviceState.setAssistantAvailable(available);
TouchInteractionService.this.onAssistantVisibilityChanged();
+ executeForTaskbarManager(() -> mTaskbarManager
+ .onLongPressHomeEnabled(longPressHomeEnabled));
});
}
@@ -404,8 +407,8 @@
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
- mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
- mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
+ LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
+ LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
ProtoTracer.INSTANCE.get(this).add(this);
@@ -475,7 +478,7 @@
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
- if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
+ if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) {
// Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
// mode doesn't have gestures
return;
@@ -518,7 +521,7 @@
@UiThread
private void onSystemUiFlagsChanged(int lastSysUIFlags) {
- if (mDeviceState.isUserUnlocked()) {
+ if (LockedUserState.get(this).isUserUnlocked()) {
int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
@@ -563,7 +566,7 @@
@UiThread
private void onAssistantVisibilityChanged() {
- if (mDeviceState.isUserUnlocked()) {
+ if (LockedUserState.get(this).isUserUnlocked()) {
mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
mDeviceState.getAssistantVisibility());
}
@@ -573,7 +576,7 @@
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
sIsInitialized = false;
- if (mDeviceState.isUserUnlocked()) {
+ if (LockedUserState.get(this).isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
mOverviewComponentObserver.onDestroy();
}
@@ -607,7 +610,7 @@
TestLogging.recordMotionEvent(
TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
- if (!mDeviceState.isUserUnlocked()) {
+ if (!LockedUserState.get(this).isUserUnlocked()) {
return;
}
@@ -629,7 +632,8 @@
mGestureState = newGestureState;
mConsumer = newConsumer(prevGestureState, mGestureState, event);
mUncheckedConsumer = mConsumer;
- } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
+ } else if (LockedUserState.get(this).isUserUnlocked()
+ && mDeviceState.isFullyGesturalNavMode()
&& mDeviceState.canTriggerAssistantAction(event)) {
mGestureState = createGestureState(mGestureState);
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
@@ -749,7 +753,7 @@
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
- if (!mDeviceState.isUserUnlocked()) {
+ if (!LockedUserState.get(this).isUserUnlocked()) {
CompoundString reasonString = newCompoundString("device locked");
InputConsumer consumer;
if (canStartSystemGesture) {
@@ -798,7 +802,7 @@
// If Taskbar is present, we listen for long press to unstash it.
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
- if (tac != null) {
+ if (tac != null && canStartSystemGesture) {
reasonString.append(NEWLINE_PREFIX)
.append(reasonPrefix)
.append(SUBSTRING_PREFIX)
@@ -1096,7 +1100,7 @@
}
private void preloadOverview(boolean fromInit, boolean forSUWAllSet) {
- if (!mDeviceState.isUserUnlocked()) {
+ if (!LockedUserState.get(this).isUserUnlocked()) {
return;
}
@@ -1128,7 +1132,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
- if (!mDeviceState.isUserUnlocked()) {
+ if (!LockedUserState.get(this).isUserUnlocked()) {
return;
}
final BaseActivityInterface activityInterface =
@@ -1169,7 +1173,7 @@
} else {
// Dump everything
FeatureFlags.dump(pw);
- if (mDeviceState.isUserUnlocked()) {
+ if (LockedUserState.get(this).isUserUnlocked()) {
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
}
mDeviceState.dump(pw);
diff --git a/quickstep/src/com/android/quickstep/util/LogUtils.kt b/quickstep/src/com/android/quickstep/util/LogUtils.kt
index bad8506..300c4a1 100644
--- a/quickstep/src/com/android/quickstep/util/LogUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/LogUtils.kt
@@ -20,15 +20,14 @@
import com.android.launcher3.logging.InstanceId
object LogUtils {
- /**
- * @return a [Pair] of two InstanceIds but with different types, one that can be used by framework
- * (if needing to pass through an intent or such) and one used in Launcher
- */
- @JvmStatic
- fun getShellShareableInstanceId():
- Pair<com.android.internal.logging.InstanceId, InstanceId> {
- val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
- val launcherInstanceId = InstanceId(internalInstanceId.id)
- return Pair(internalInstanceId, launcherInstanceId)
- }
+ /**
+ * @return a [Pair] of two InstanceIds but with different types, one that can be used by
+ * framework (if needing to pass through an intent or such) and one used in Launcher
+ */
+ @JvmStatic
+ fun getShellShareableInstanceId(): Pair<com.android.internal.logging.InstanceId, InstanceId> {
+ val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
+ val launcherInstanceId = InstanceId(internalInstanceId.id)
+ return Pair(internalInstanceId, launcherInstanceId)
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index c878278..858f6ab 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -81,6 +81,8 @@
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
+ private ShapeDrawable mBackground;
+
public DesktopTaskView(Context context) {
this(context, null);
}
@@ -99,10 +101,11 @@
float[] outerRadii = new float[8];
Arrays.fill(outerRadii, getTaskCornerRadius());
RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
- ShapeDrawable background = new ShapeDrawable(shape);
- background.setTint(getResources().getColor(android.R.color.system_neutral2_300));
+ mBackground = new ShapeDrawable(shape);
+ mBackground.setTint(getResources().getColor(android.R.color.system_neutral2_300,
+ getContext().getTheme()));
// TODO(b/244348395): this should be wallpaper
- setBackground(background);
+ setBackground(mBackground);
mSnapshotViews.add(mSnapshotView);
}
@@ -427,6 +430,12 @@
// TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
progress = Utilities.boundToRange(progress, 0, 1);
mFullscreenProgress = progress;
+ if (mFullscreenProgress > 0) {
+ // Don't show background while we are transitioning to/from fullscreen
+ setBackground(null);
+ } else {
+ setBackground(mBackground);
+ }
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 2cada0a..3f7d677 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -2,7 +2,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import android.content.Context;
import android.graphics.PointF;
@@ -102,6 +101,22 @@
PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT);
}
+ /**
+ * Sets up an on-click listener and the visibility for show_windows icon on top of each task.
+ */
+ @Override
+ public void setUpShowAllInstancesListener() {
+ // sets up the listener for the left/top task
+ super.setUpShowAllInstancesListener();
+
+ // right/bottom task's base package name
+ String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName();
+
+ // icon of the right/bottom task
+ View showWindowsView = findViewById(R.id.show_windows_right);
+ updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName));
+ }
+
@Override
public void onTaskListVisibilityChanged(boolean visible, int changes) {
super.onTaskListVisibilityChanged(visible, changes);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 6c27587..cf033a6 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -36,12 +36,15 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.popup.QuickstepSystemShortcut;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.RotationTouchHelper;
import com.android.quickstep.util.SplitSelectStateController;
+import com.android.systemui.shared.recents.model.Task;
/**
* {@link RecentsView} used in Launcher activity
@@ -205,4 +208,25 @@
protected boolean canLaunchFullscreenTask() {
return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
}
+
+ @Override
+ public void onGestureAnimationStart(Task[] runningTasks,
+ RotationTouchHelper rotationTouchHelper) {
+ super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
+ DesktopVisibilityController desktopVisibilityController =
+ mActivity.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.setGestureInProgress(true);
+ }
+ }
+
+ @Override
+ public void onGestureAnimationEnd() {
+ super.onGestureAnimationEnd();
+ DesktopVisibilityController desktopVisibilityController =
+ mActivity.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.setGestureInProgress(false);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 63aea45..c11f7ed 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -165,6 +165,7 @@
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationTargets;
+import com.android.quickstep.RecentsFilterState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.RemoteTargetGluer;
@@ -581,7 +582,7 @@
if (taskRemoved) {
dismissTask(taskId);
}
- });
+ }, RecentsFilterState.getFilter(mFilterState.getPackageNameToFilter()));
}
}));
}
@@ -722,6 +723,9 @@
@Nullable
private TaskLaunchListener mTaskLaunchListener;
+ // keeps track of the state of the filter for tasks in recents view
+ private final RecentsFilterState mFilterState = new RecentsFilterState();
+
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
@@ -785,6 +789,55 @@
mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
mTintingColor = getForegroundScrimDimColor(context);
+
+ // 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);
+ }
+ // make sure filter is turned off by default
+ mFilterState.setFilterBy(null);
+ }
+
+ /** Get the state of the filter */
+ public RecentsFilterState getFilterState() {
+ return mFilterState;
+ }
+
+ /**
+ * Toggles the filter and reloads the recents view if needed.
+ *
+ * @param packageName package name to filter by if the filter is being turned on;
+ * should be null if filter is being turned off
+ */
+ public void setAndApplyFilter(@Nullable String packageName) {
+ mFilterState.setFilterBy(packageName);
+ updateClearAllFunction();
+ reloadIfNeeded();
+ }
+
+ /**
+ * Updates the "Clear All" button and its function depending on the recents view state.
+ *
+ * TODO: add a different button for going back to overview. Present solution is for demo only.
+ */
+ public void updateClearAllFunction() {
+ if (mFilterState.isFiltered()) {
+ mClearAllButton.setText(R.string.recents_back);
+ mClearAllButton.setOnClickListener((view) -> {
+ this.setAndApplyFilter(null);
+ });
+ } else {
+ mClearAllButton.setText(R.string.recents_clear_all);
+ mClearAllButton.setOnClickListener(this::dismissAllTasks);
+ }
+ }
+
+ /**
+ * Invalidates the list of tasks so that an update occurs to the list of tasks if requested.
+ */
+ private void invalidateTaskList() {
+ mTaskListChangeId = -1;
}
public OverScroller getScroller() {
@@ -1504,6 +1557,11 @@
ActiveGestureErrorDetector.GestureEvent.SCROLLER_ANIMATION_ABORTED);
}
+ @Override
+ protected boolean isPageScrollsInitialized() {
+ return super.isPageScrollsInitialized() && mLoadPlanEverApplied;
+ }
+
protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
@@ -1517,6 +1575,9 @@
// With all tasks removed, touch handling in PagedView is disabled and we need to reset
// touch state or otherwise values will be obsolete.
resetTouchState();
+ if (isPageScrollsInitialized()) {
+ onPageScrollsInitialized();
+ }
return;
}
@@ -1547,6 +1608,9 @@
Task stagedTaskToBeRemovedFromGrid =
mSplitSelectSource != null ? mSplitSelectSource.alreadyRunningTask : null;
+ // update the map of instance counts
+ mFilterState.updateInstanceCountMap(taskGroups);
+
// Add views as children based on whether it's grouped or single task. Looping through
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -1581,6 +1645,7 @@
groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
+
((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
groupTask.mSplitBounds);
} else if (taskView instanceof DesktopTaskView) {
@@ -1589,6 +1654,11 @@
} else {
taskView.bind(groupTask.task1, mOrientationState);
}
+
+ // enables instance filtering if the feature flag for it is on
+ if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
+ taskView.setUpShowAllInstancesListener();
+ }
}
if (!taskGroups.isEmpty()) {
@@ -1661,6 +1731,9 @@
resetTaskVisuals();
onTaskStackUpdated();
updateEnabledOverlays();
+ if (isPageScrollsInitialized()) {
+ onPageScrollsInitialized();
+ }
}
private boolean isModal() {
@@ -2004,7 +2077,7 @@
if (!mActivity.getDeviceProfile().isTablet) {
return super.getDestinationPage(scaledScroll);
}
- if (!pageScrollsInitialized()) {
+ if (!isPageScrollsInitialized()) {
Log.e(TAG,
"Cannot get destination page: RecentsView not properly initialized",
new IllegalStateException());
@@ -2258,7 +2331,8 @@
*/
public void reloadIfNeeded() {
if (!mModel.isTaskListValid(mTaskListChangeId)) {
- mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
+ mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
+ .getFilter(mFilterState.getPackageNameToFilter()));
}
}
@@ -2966,7 +3040,7 @@
false /* fadeWithThumbnail */, true /* isStagedTask */);
}
- // TODO (b/257513449): Launch animation not fully complete. OK to remove flag once it is.
+ // Allow user to click staged app to launch into fullscreen
if (ENABLE_LAUNCH_FROM_STAGED_APP.get()) {
mFirstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
}
@@ -3037,7 +3111,9 @@
false /* fadeWithThumbnail */,
true /* isStagedTask */);
- pendingAnimation.addEndListener(success -> launchStagedTask());
+ pendingAnimation.addEndListener(animationSuccess ->
+ mSplitSelectStateController.launchSplitTasks(launchSuccess ->
+ resetFromSplitSelectionState()));
pendingAnimation.buildAnim().start();
}
@@ -3115,8 +3191,6 @@
}
}
- announceForAccessibility(getResources().getString(R.string.task_view_closed));
-
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
@@ -3443,6 +3517,8 @@
} else {
removeTaskInternal(dismissedTaskViewId);
}
+ announceForAccessibility(
+ getResources().getString(R.string.task_view_closed));
mActivity.getStatsLogManager().logger()
.withItemInfo(dismissedTaskView.getItemInfo())
.log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
@@ -4744,16 +4820,6 @@
return mPendingAnimation;
}
- protected void launchStagedTask() {
- if (mSplitHiddenTaskView != null) {
- // Split staging was started from an existing running task (in Overview)
- mSplitHiddenTaskView.launchTask(success -> resetFromSplitSelectionState());
- } else {
- // Split staging was started from a new intent (from app menu in Home/AllApps)
- mActivity.startActivity(mSplitSelectSource.intent);
- }
- }
-
protected void onTaskLaunchAnimationEnd(boolean success) {
if (success) {
resetTaskVisuals();
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index bdc0585..54b58b9 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -48,13 +48,15 @@
taskContainer: TaskIdAttributeContainer,
alignSecondRow: Boolean = false
): Boolean {
- val activity = BaseDraggingActivity
- .fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
- val taskMenuViewWithArrow = activity.layoutInflater
- .inflate(
- R.layout.task_menu_with_arrow,
- activity.dragLayer,
- false
+ val activity =
+ BaseDraggingActivity.fromContext<BaseDraggingActivity>(
+ taskContainer.taskView.context
+ )
+ val taskMenuViewWithArrow =
+ activity.layoutInflater.inflate(
+ R.layout.task_menu_with_arrow,
+ activity.dragLayer,
+ false
) as TaskMenuViewWithArrow<*>
return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
@@ -63,11 +65,11 @@
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
- context,
- attrs,
- defStyleAttr
- )
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
init {
clipToOutline = true
@@ -91,10 +93,10 @@
private var optionMeasuredHeight = 0
private val arrowHorizontalPadding: Int
- get() = if (taskView.isFocusedTask)
- resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
- else
- 0
+ get() =
+ if (taskView.isFocusedTask)
+ resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
+ else 0
private var iconView: IconView? = null
private var scrim: View? = null
@@ -139,19 +141,20 @@
}
private fun addScrim() {
- scrim = View(context).apply {
- layoutParams = FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT
- )
- setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
- alpha = 0f
- }
+ scrim =
+ View(context).apply {
+ layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ )
+ setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
+ alpha = 0f
+ }
popupContainer.addView(scrim)
}
- /** @return true if successfully able to populate task view menu, false otherwise
- */
+ /** @return true if successfully able to populate task view menu, false otherwise */
private fun populateMenu(): Boolean {
// Icon may not be loaded
if (taskContainer.task.icon == null) return false
@@ -162,9 +165,9 @@
private fun addMenuOptions() {
// Add the options
- TaskOverlayFactory
- .getEnabledShortcuts(taskView, taskContainer)
- .forEach { this.addMenuOption(it) }
+ TaskOverlayFactory.getEnabledShortcuts(taskView, taskContainer).forEach {
+ this.addMenuOption(it)
+ }
// Add the spaces between items
val divider = ShapeDrawable(RectShape())
@@ -185,9 +188,9 @@
}
private fun addMenuOption(menuOption: SystemShortcut<*>) {
- val menuOptionView = mActivityContext.layoutInflater.inflate(
- R.layout.task_view_menu_option, this, false
- ) as LinearLayout
+ val menuOptionView =
+ mActivityContext.layoutInflater.inflate(R.layout.task_view_menu_option, this, false)
+ as LinearLayout
menuOption.setIconAndLabelFor(
menuOptionView.findViewById(R.id.icon),
menuOptionView.findViewById(R.id.text)
@@ -230,24 +233,25 @@
}
/**
- * Copy the iconView from taskView to dragLayer so it can stay on top of the scrim.
- * It needs to be called after [getTargetObjectLocation] because [mTempRect] needs to be
- * populated.
+ * Copy the iconView from taskView to dragLayer so it can stay on top of the scrim. It needs to
+ * be called after [getTargetObjectLocation] because [mTempRect] needs to be populated.
*/
private fun copyIconToDragLayer(insets: Rect) {
- iconView = IconView(context).apply {
- layoutParams = FrameLayout.LayoutParams(
- taskContainer.iconView.width,
- taskContainer.iconView.height
- )
- x = mTempRect.left.toFloat() - insets.left
- y = mTempRect.top.toFloat() - insets.top
- drawable = taskContainer.iconView.drawable
- setDrawableSize(
- taskContainer.iconView.drawableWidth,
- taskContainer.iconView.drawableHeight
- )
- }
+ iconView =
+ IconView(context).apply {
+ layoutParams =
+ FrameLayout.LayoutParams(
+ taskContainer.iconView.width,
+ taskContainer.iconView.height
+ )
+ x = mTempRect.left.toFloat() - insets.left
+ y = mTempRect.top.toFloat() - insets.top
+ drawable = taskContainer.iconView.drawable
+ setDrawableSize(
+ taskContainer.iconView.drawableWidth,
+ taskContainer.iconView.drawableHeight
+ )
+ }
popupContainer.addView(iconView)
}
@@ -281,12 +285,13 @@
// which means the arrow is left aligned with the menu
val rightAlignedMenuStartX = mTempRect.left - widthWithArrow
val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace
- mIsLeftAligned = if (mIsRtl) {
- rightAlignedMenuStartX + insets.left < 0
- } else {
- leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
+ mIsLeftAligned =
+ if (mIsRtl) {
+ rightAlignedMenuStartX + insets.left < 0
+ } else {
+ leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
dragLayer.width - insets.right
- }
+ }
var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX
@@ -311,8 +316,8 @@
override fun addArrow() {
popupContainer.addView(mArrow)
mArrow.x = getArrowX()
- mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) +
- extraSpaceForSecondRowAlignment
+ mArrow.y =
+ y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) + extraSpaceForSecondRowAlignment
updateArrowColor()
@@ -322,22 +327,19 @@
}
private fun getArrowX(): Float {
- return if (mIsLeftAligned)
- x - mArrowHeight
- else
- x + measuredWidth + mArrowOffsetVertical
+ return if (mIsLeftAligned) x - mArrowHeight else x + measuredWidth + mArrowOffsetVertical
}
override fun updateArrowColor() {
- mArrow.background = RoundedArrowDrawable(
- mArrowWidth.toFloat(),
- mArrowHeight.toFloat(),
- mArrowPointRadius.toFloat(),
- mIsLeftAligned,
- mArrowColor
- )
+ mArrow.background =
+ RoundedArrowDrawable(
+ mArrowWidth.toFloat(),
+ mArrowHeight.toFloat(),
+ mArrowPointRadius.toFloat(),
+ mIsLeftAligned,
+ mArrowColor
+ )
elevation = mElevation
mArrow.elevation = mElevation
}
-
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index bda30a5..aa37fdd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -526,6 +526,52 @@
setOrientationState(orientedState);
}
+ /**
+ * Sets up an on-click listener and the visibility for show_windows icon on top of the task.
+ */
+ public void setUpShowAllInstancesListener() {
+ String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName();
+
+ // icon of the top/left task
+ View showWindowsView = findViewById(R.id.show_windows);
+ updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName));
+ }
+
+ /**
+ * Returns a callback that updates the state of the filter and the recents overview
+ *
+ * @param taskPackageName package name of the task to filter by
+ */
+ @Nullable
+ protected View.OnClickListener getFilterUpdateCallback(String taskPackageName) {
+ View.OnClickListener cb = (view) -> {
+ // update and apply a new filter
+ getRecentsView().setAndApplyFilter(taskPackageName);
+ };
+
+ if (!getRecentsView().getFilterState().shouldShowFilterUI(taskPackageName)) {
+ cb = null;
+ }
+ return cb;
+ }
+
+ /**
+ * Sets the correct visibility and callback on the provided filterView based on whether
+ * the callback is null or not
+ */
+ protected void updateFilterCallback(@NonNull View filterView,
+ @Nullable View.OnClickListener callback) {
+ // Filtering changes alpha instead of the visibility since visibility
+ // can be altered separately through RecentsView#resetFromSplitSelectionState()
+ if (callback == null) {
+ filterView.setAlpha(0);
+ } else {
+ filterView.setAlpha(1);
+ }
+
+ filterView.setOnClickListener(callback);
+ }
+
public TaskIdAttributeContainer[] getTaskIdAttributeContainers() {
return mTaskIdAttributeContainer;
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 4eec319..9622619 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -103,12 +104,20 @@
}
@Test
- public void testLongPressHome() {
+ public void testLongPressHome_enabled() {
+ mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
verify(mockSystemUiProxy, times(1)).startAssistant(any());
}
@Test
+ public void testLongPressHome_disabled() {
+ mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
+ mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+ verify(mockSystemUiProxy, never()).startAssistant(any());
+ }
+
+ @Test
public void testPressHome() {
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 58f0949..236b5db 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -8,38 +8,29 @@
import android.widget.LinearLayout
import androidx.test.runner.AndroidJUnit4
import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
+import java.lang.IllegalStateException
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import com.android.launcher3.R
-import org.junit.Assume.assumeTrue
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-import java.lang.IllegalStateException
@RunWith(AndroidJUnit4::class)
class NavButtonLayoutFactoryTest {
- @Mock
- lateinit var mockDeviceProfile: DeviceProfile
- @Mock
- lateinit var mockParentButtonContainer: FrameLayout
- @Mock
- lateinit var mockNavLayout: LinearLayout
- @Mock
- lateinit var mockStartContextualLayout: ViewGroup
- @Mock
- lateinit var mockEndContextualLayout: ViewGroup
- @Mock
- lateinit var mockResources: Resources
- @Mock
- lateinit var mockBackButton: ImageView
- @Mock
- lateinit var mockRecentsButton: ImageView
- @Mock
- lateinit var mockHomeButton: ImageView
+ @Mock lateinit var mockDeviceProfile: DeviceProfile
+ @Mock lateinit var mockParentButtonContainer: FrameLayout
+ @Mock lateinit var mockNavLayout: LinearLayout
+ @Mock lateinit var mockStartContextualLayout: ViewGroup
+ @Mock lateinit var mockEndContextualLayout: ViewGroup
+ @Mock lateinit var mockResources: Resources
+ @Mock lateinit var mockBackButton: ImageView
+ @Mock lateinit var mockRecentsButton: ImageView
+ @Mock lateinit var mockHomeButton: ImageView
@Before
fun setup() {
@@ -53,11 +44,11 @@
// Init top level layout
whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
- .thenReturn(mockNavLayout)
+ .thenReturn(mockNavLayout)
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
- .thenReturn(mockEndContextualLayout)
+ .thenReturn(mockEndContextualLayout)
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
- .thenReturn(mockStartContextualLayout)
+ .thenReturn(mockStartContextualLayout)
}
@Test
@@ -65,8 +56,12 @@
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
- getLayoutter(isKidsMode = true, isInSetup = false, isThreeButtonNav = false,
- phoneMode = false)
+ getLayoutter(
+ isKidsMode = true,
+ isInSetup = false,
+ isThreeButtonNav = false,
+ phoneMode = false
+ )
assert(layoutter is KidsNavLayoutter)
}
@@ -75,8 +70,12 @@
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
- getLayoutter(isKidsMode = false, isInSetup = true, isThreeButtonNav = false,
- phoneMode = false)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = true,
+ isThreeButtonNav = false,
+ phoneMode = false
+ )
assert(layoutter is SetupNavLayoutter)
}
@@ -85,8 +84,12 @@
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
- getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
- phoneMode = false)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = false,
+ phoneMode = false
+ )
assert(layoutter is TaskbarNavLayoutter)
}
@@ -94,8 +97,12 @@
fun noValidLayoutForLargeScreenTaskbarNotPresent() {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
- getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
- phoneMode = false)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = false,
+ phoneMode = false
+ )
}
@Test
@@ -103,8 +110,12 @@
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
- getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
- phoneMode = true)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = true,
+ phoneMode = true
+ )
assert(layoutter is PhonePortraitNavLayoutter)
}
@@ -114,8 +125,12 @@
mockDeviceProfile.isTaskbarPresent = false
setDeviceProfileLandscape()
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
- getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
- phoneMode = true)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = true,
+ phoneMode = true
+ )
assert(layoutter is PhoneLandscapeNavLayoutter)
}
@@ -123,8 +138,12 @@
fun noValidLayoutForPhoneGestureNav() {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
- getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
- phoneMode = true)
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = false,
+ phoneMode = true
+ )
}
private fun setDeviceProfileLandscape() {
@@ -134,15 +153,20 @@
landscapeField.set(mockDeviceProfile, true)
}
- private fun getLayoutter(isKidsMode: Boolean, isInSetup: Boolean,
- isThreeButtonNav: Boolean, phoneMode: Boolean):
- NavButtonLayoutFactory.NavButtonLayoutter {
+ private fun getLayoutter(
+ isKidsMode: Boolean,
+ isInSetup: Boolean,
+ isThreeButtonNav: Boolean,
+ phoneMode: Boolean
+ ): NavButtonLayoutFactory.NavButtonLayoutter {
return NavButtonLayoutFactory.getUiLayoutter(
- deviceProfile = mockDeviceProfile,
- navButtonsView = mockParentButtonContainer,
- resources = mockResources,
- isKidsMode = isKidsMode, isInSetup = isInSetup,
- isThreeButtonNav = isThreeButtonNav, phoneMode = phoneMode
+ deviceProfile = mockDeviceProfile,
+ navButtonsView = mockParentButtonContainer,
+ resources = mockResources,
+ isKidsMode = isKidsMode,
+ isInSetup = isInSetup,
+ isThreeButtonNav = isThreeButtonNav,
+ phoneMode = phoneMode
)
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 5c2e14f..1129a33 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -46,7 +46,8 @@
runWithShellPermission(() ->
usageStatsManager.registerAppUsageLimitObserver(observerId, packages,
Duration.ofSeconds(600), Duration.ofSeconds(300),
- PendingIntent.getActivity(mTargetContext, -1, new Intent(),
+ PendingIntent.getActivity(mTargetContext, -1, new Intent()
+ .setPackage(mTargetContext.getPackageName()),
PendingIntent.FLAG_MUTABLE)));
mLauncher.goHome();
diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index 5ec935f..9afd893 100644
--- a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -27,15 +27,13 @@
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
import com.android.wm.shell.util.SplitBounds
import com.google.common.truth.Truth.assertThat
+import kotlin.math.roundToInt
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
-import kotlin.math.roundToInt
-/**
- * Test for FullscreenDrawParams class.
- */
+/** Test for FullscreenDrawParams class. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
@@ -61,15 +59,29 @@
val currentRotation = 0
val isRtl = false
- mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
- isRtl)
- params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+ mPreviewPositionHelper.updateThumbnailMatrix(
+ previewRect,
+ mThumbnailData,
+ canvasWidth,
+ canvasHeight,
+ dp.widthPx,
+ dp.heightPx,
+ dp.taskbarSize,
+ dp.isTablet,
+ currentRotation,
+ isRtl
+ )
+ params.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* previewWidth= */ 0,
+ dp,
+ mPreviewPositionHelper
+ )
val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize * TASK_SCALE)
- assertThat(params.mCurrentDrawnInsets)
- .isEqualTo(expectedClippedInsets)
+ assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
}
@Test
@@ -83,25 +95,42 @@
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
- val splitBounds = SplitBounds(
+ val splitBounds =
+ SplitBounds(
Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
- 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+ 0 /*lefTopTaskId*/,
+ 0 /*rightBottomTaskId*/
+ )
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
- mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
- isRtl)
- params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+ mPreviewPositionHelper.updateThumbnailMatrix(
+ previewRect,
+ mThumbnailData,
+ canvasWidth,
+ canvasHeight,
+ dp.widthPx,
+ dp.heightPx,
+ dp.taskbarSize,
+ dp.isTablet,
+ currentRotation,
+ isRtl
+ )
+ params.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* previewWidth= */ 0,
+ dp,
+ mPreviewPositionHelper
+ )
// Probably unhelpful, but also unclear how to test otherwise ¯\_(ツ)_/¯
- val fullscreenTaskHeight = dp.heightPx *
- (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
+ val fullscreenTaskHeight =
+ dp.heightPx * (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
val canvasScreenRatio = canvasHeight / fullscreenTaskHeight
val expectedBottomHint = dp.taskbarSize * canvasScreenRatio
- assertThat(params.mCurrentDrawnInsets.bottom)
- .isWithin(1f).of(expectedBottomHint)
+ assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of(expectedBottomHint)
}
@Test
@@ -115,20 +144,37 @@
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
- val splitBounds = SplitBounds(
+ val splitBounds =
+ SplitBounds(
Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
- 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+ 0 /*lefTopTaskId*/,
+ 0 /*rightBottomTaskId*/
+ )
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_TOP_OR_LEFT)
- mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
- isRtl)
- params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+ mPreviewPositionHelper.updateThumbnailMatrix(
+ previewRect,
+ mThumbnailData,
+ canvasWidth,
+ canvasHeight,
+ dp.widthPx,
+ dp.heightPx,
+ dp.taskbarSize,
+ dp.isTablet,
+ currentRotation,
+ isRtl
+ )
+ params.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* previewWidth= */ 0,
+ dp,
+ mPreviewPositionHelper
+ )
- assertThat(params.mCurrentDrawnInsets.bottom)
- .isWithin(1f).of((0f))
+ assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((0f))
}
@Test
@@ -142,20 +188,37 @@
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
- val splitBounds = SplitBounds(
+ val splitBounds =
+ SplitBounds(
Rect(0, 0, (dp.widthPx - dividerSize) / 2, dp.heightPx),
Rect((dp.widthPx + dividerSize) / 2, 0, dp.widthPx, dp.heightPx),
- 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+ 0 /*lefTopTaskId*/,
+ 0 /*rightBottomTaskId*/
+ )
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
- mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
- isRtl)
- params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+ mPreviewPositionHelper.updateThumbnailMatrix(
+ previewRect,
+ mThumbnailData,
+ canvasWidth,
+ canvasHeight,
+ dp.widthPx,
+ dp.heightPx,
+ dp.taskbarSize,
+ dp.isTablet,
+ currentRotation,
+ isRtl
+ )
+ params.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* previewWidth= */ 0,
+ dp,
+ mPreviewPositionHelper
+ )
- assertThat(params.mCurrentDrawnInsets.bottom)
- .isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
+ assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
}
@Test
@@ -168,14 +231,28 @@
val currentRotation = 0
val isRtl = false
- mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
- isRtl)
- params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
- /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+ mPreviewPositionHelper.updateThumbnailMatrix(
+ previewRect,
+ mThumbnailData,
+ canvasWidth,
+ canvasHeight,
+ dp.widthPx,
+ dp.heightPx,
+ dp.taskbarSize,
+ dp.isTablet,
+ currentRotation,
+ isRtl
+ )
+ params.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* previewWidth= */ 0,
+ dp,
+ mPreviewPositionHelper
+ )
val expectedClippedInsets = RectF(0f, 0f, 0f, 0f)
- assertThat(params.mCurrentDrawnInsets)
- .isEqualTo(expectedClippedInsets)
+ assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
index 4837c6c..adbca32 100644
--- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
@@ -29,8 +29,8 @@
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
/**
- * This is a case when after setting the hotseat, the space needs to be recalculated
- * but it doesn't need to change QSB width or remove icons
+ * This is a case when after setting the hotseat, the space needs to be recalculated but it
+ * doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_portrait() {
@@ -51,8 +51,8 @@
}
/**
- * This is a case when after setting the hotseat, and recalculating spaces
- * it still needs to remove icons for everything to fit
+ * This is a case when after setting the hotseat, and recalculating spaces it still needs to
+ * remove icons for everything to fit
*/
@Test
fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -73,8 +73,8 @@
}
/**
- * This is a case when after setting the hotseat, the space needs to be recalculated
- * but it doesn't need to change QSB width or remove icons
+ * This is a case when after setting the hotseat, the space needs to be recalculated but it
+ * doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_landscape() {
@@ -94,8 +94,8 @@
}
/**
- * This is a case when the hotseat spans a certain amount of columns
- * and the nav buttons push the hotseat to the side, but not enough to change the border space.
+ * This is a case when the hotseat spans a certain amount of columns and the nav buttons push
+ * the hotseat to the side, but not enough to change the border space.
*/
@Test
fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -118,9 +118,7 @@
assertThat(dp.hotseatQsbWidth).isEqualTo(1233)
}
- /**
- * This is a case when after setting the hotseat, the QSB width needs to be changed to fit
- */
+ /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@Test
fun decrease_qsb_when_not_enough_space_landscape() {
initializeVarsForTablet(isGestureMode = false, isLandscape = true)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9a2fcc0..9f34775 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -262,6 +262,19 @@
return launchedAppState;
}
+ private void quickSwitchToPreviousAppAndAssert(boolean toRight) {
+ final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+ if (toRight) {
+ launchedAppState.quickSwitchToPreviousApp();
+ } else {
+ launchedAppState.quickSwitchToPreviousAppSwipeLeft();
+ }
+
+ // While enable shell transition, Launcher can be resumed due to transient launch.
+ waitForLauncherCondition("Launcher shouldn't stay in resume forever",
+ this::isInLaunchedApp, 3000 /* timeout */);
+ }
+
@Test
@PortraitLandscape
public void testAllAppsFromHome() throws Exception {
@@ -288,13 +301,11 @@
startTestActivity(3);
startTestActivity(4);
- LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
- launchedAppState.quickSwitchToPreviousApp();
+ quickSwitchToPreviousAppAndAssert(true /* toRight */);
assertTrue("The first app we should have quick switched to is not running",
isTestActivityRunning(3));
- launchedAppState = getAndAssertLaunchedApp();
- launchedAppState.quickSwitchToPreviousApp();
+ quickSwitchToPreviousAppAndAssert(true /* toRight */);
if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) {
// 3-button mode toggles between 2 apps, rather than going back further.
assertTrue("Second quick switch should have returned to the first app.",
@@ -303,12 +314,12 @@
assertTrue("The second app we should have quick switched to is not running",
isTestActivityRunning(2));
}
- launchedAppState = getAndAssertLaunchedApp();
- launchedAppState.quickSwitchToPreviousAppSwipeLeft();
+
+ quickSwitchToPreviousAppAndAssert(false /* toRight */);
assertTrue("The 2nd app we should have quick switched to is not running",
isTestActivityRunning(3));
- launchedAppState = getAndAssertLaunchedApp();
+ final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
launchedAppState.switchToOverview();
}
@@ -327,8 +338,10 @@
launchedAppState.assertTaskbarHidden();
// Quick-switch to the test app with swiping to right.
- launchedAppState.quickSwitchToPreviousApp();
+ quickSwitchToPreviousAppAndAssert(true /* toRight */);
+ assertTrue("The first app we should have quick switched to is not running",
+ isTestActivityRunning(2));
// Expect task bar visible when the launched app was the test activity.
launchedAppState = getAndAssertLaunchedApp();
launchedAppState.assertTaskbarVisible();
diff --git a/res/drawable/ic_select_windows.xml b/res/drawable/ic_select_windows.xml
new file mode 100644
index 0000000..cba0fde
--- /dev/null
+++ b/res/drawable/ic_select_windows.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,44Q5.8,44 4.9,43.1Q4,42.2 4,41V21.65Q4,20.45 4.9,19.55Q5.8,18.65 7,18.65H12.75V7Q12.75,5.8 13.65,4.9Q14.55,4 15.75,4H41Q42.2,4 43.1,4.9Q44,5.8 44,7V26.35Q44,27.55 43.1,28.45Q42.2,29.35 41,29.35H35.3V41Q35.3,42.2 34.4,43.1Q33.5,44 32.3,44ZM7,41H32.3Q32.3,41 32.3,41Q32.3,41 32.3,41V24.65H7V41Q7,41 7,41Q7,41 7,41ZM35.3,26.35H41Q41,26.35 41,26.35Q41,26.35 41,26.35V10H15.75V18.65H31.6Q33.2,18.65 34.25,19.7Q35.3,20.75 35.3,22.35Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 460a73e..cc6e908 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -21,156 +21,156 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
<string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Апликација није инсталирана."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Апликација није доступна"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преузета апликација је онемогућена у Безбедном режиму"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Виџети су онемогућени у Безбедном режиму"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Пречица није доступна"</string>
- <string name="home_screen" msgid="5629429142036709174">"Почетни екран"</string>
- <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
- <string name="split_screen_position_top" msgid="1504965011158689649">"Подели у врху"</string>
- <string name="split_screen_position_left" msgid="7537793098851830883">"Подели лево"</string>
- <string name="split_screen_position_right" msgid="1569377524925193369">"Подели десно"</string>
- <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
- <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
+ <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
+ <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
+ <string name="safemode_shortcut_error" msgid="9160126848219158407">"Preuzeta aplikacija je onemogućena u Bezbednom režimu"</string>
+ <string name="safemode_widget_error" msgid="4863470563535682004">"Vidžeti su onemogućeni u Bezbednom režimu"</string>
+ <string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
+ <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_screen_position_top" msgid="1504965011158689649">"Podeli u vrhu"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Podeli levo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Podeli desno"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
+ <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>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ширина од %1$d и висина од %2$d"</string>
- <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виџет"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Додирните и задржите виџет да бисте га померали по почетном екрану"</string>
- <string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
- <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
- <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}few{# виџета}other{# виџета}}"</string>
- <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
+ <string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
+ <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidžet"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da biste ga pomerali po početnom ekranu"</string>
+ <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
+ <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
+ <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
+ <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string>
- <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Претражите"</string>
- <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Обришите текст из оквира за претрагу"</string>
- <string name="no_widgets_available" msgid="4337693382501046170">"Виџети и пречице нису доступни"</string>
- <string name="no_search_results" msgid="3787956167293097509">"Није пронађен ниједан виџет ни пречица"</string>
- <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Лично"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Посао"</string>
- <string name="widget_category_conversations" msgid="8894438636213590446">"Конверзације"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Корисне информације надохват руке"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Да бисте пронашли информације без отварања апликација, можете да додате виџете на почетни екран"</string>
- <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Важи"</string>
- <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промените подешавања виџета"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Претражите апликације"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Апликације се учитавају…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
- <string name="label_application" msgid="8531721983832654978">"Апликација"</string>
- <string name="all_apps_label" msgid="5015784846527570951">"Све апликације"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Обавештења"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Додирните и задржите ради померања пречице."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Двапут додирните и задржите да бисте померали пречицу или користите прилагођене радње."</string>
- <string name="out_of_space" msgid="6455557115204099579">"Нема места на овом почетном екрану"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема више простора на траци Омиљено"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Листа апликација"</string>
- <string name="all_apps_search_results" msgid="5889367432531296759">"Резултати претраге"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Листа личних апликација"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Листа пословних апликација"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Уклони"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Инфор. о апликацији"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
- <string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
- <string name="permlab_read_settings" msgid="5136500343007704955">"читање подешавања и пречица на почетном екрану"</string>
- <string name="permdesc_read_settings" msgid="4208061150510996676">"Дозвољава апликацији да чита подешавања и пречице на почетном екрану."</string>
- <string name="permlab_write_settings" msgid="4820028712156303762">"уписивање подешавања и пречица на почетном екрану"</string>
- <string name="permdesc_write_settings" msgid="726859348127868466">"Дозвољава апликацији да мења подешавања и пречице на почетном екрану."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> нема дозволу за упућивање телефонских позива"</string>
- <string name="gadget_error_text" msgid="740356548025791839">"Учитавање виџета није успело"</string>
- <string name="gadget_setup_text" msgid="8348374825537681407">"Подешавања виџета"</string>
- <string name="gadget_complete_setup_text" msgid="309040266978007925">"Додирните да бисте довршили подешавање"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ово је системска апликација и не може да се деинсталира."</string>
- <string name="folder_hint_text" msgid="5174843001373488816">"Измените назив"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућена"</string>
- <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name}, има # обавештење}one{{app_name}, има # обавештење}few{{app_name}, има # обавештења}other{{app_name}, има # обавештења}}"</string>
- <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. страница од %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. почетни екран од %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Нова страница почетног екрана"</string>
- <string name="folder_opened" msgid="94695026776264709">"Фолдер је отворен, <xliff:g id="WIDTH">%1$d</xliff:g> пута <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Додирните да бисте затворили фолдер"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Додирните да бисте сачували преименовање"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Фолдер је затворен"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Фолдер је преименован у <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format_exact" msgid="8626242716117004803">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ставке"</string>
- <string name="folder_name_format_overflow" msgid="4270108890534995199">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> или више ставки"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Позадине"</string>
- <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Позадина и стил"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Подешавања почетног екрана"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администратор је онемогућио"</string>
- <string name="allow_rotation_title" msgid="7222049633713050106">"Дозволи ротацију почетног екрана"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Када се телефон ротира"</string>
- <string name="notification_dots_title" msgid="9062440428204120317">"Тачке за обавештења"</string>
- <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укључено"</string>
- <string name="notification_dots_desc_off" msgid="1760796511504341095">"Искључено"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребан је приступ за обавештења"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Промените подешавања"</string>
- <string name="notification_dots_service_title" msgid="4284221181793592871">"Приказуј тачке за обавештења"</string>
- <string name="developer_options_title" msgid="700788437593726194">"Опције за програмера"</string>
- <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Додај иконе апликација на почетни екран"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нове апликације"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Уклони"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Претражи"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Ова апликација није инсталирана"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликација за ову икону није инсталирана. Можете да је уклоните или да потражите апликацију и инсталирате је ручно."</string>
- <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> готово"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
- <string name="dialog_update_title" msgid="114234265740994042">"Треба да ажурирате апликацију"</string>
- <string name="dialog_update_message" msgid="4176784553982226114">"Апликација за ову икону није ажурирана. Можете да је ручно ажурирате да бисте поново омогућили ову пречицу или уклоните икону."</string>
- <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
- <string name="dialog_remove" msgid="6510806469849709407">"Уклони"</string>
- <string name="widgets_list" msgid="796804551140113767">"Листа виџета"</string>
- <string name="widgets_list_closed" msgid="6141506579418771922">"Листа виџета је затворена"</string>
- <string name="action_add_to_workspace" msgid="215894119683164916">"Додајте на почетни екран"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Премести ставку овде"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставка је додата на почетни екран"</string>
- <string name="item_removed" msgid="851119963877842327">"Ставка је уклоњена"</string>
- <string name="undo" msgid="4151576204245173321">"Опозови"</string>
- <string name="action_move" msgid="4339390619886385032">"Премести ставку"</string>
- <string name="move_to_empty_cell_description" msgid="5254852678218206889">"Преместите у ред <xliff:g id="NUMBER_0">%1$s</xliff:g> колону <xliff:g id="NUMBER_1">%2$s</xliff:g> на <xliff:g id="STRING">%3$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију у омиљеним"</string>
- <string name="item_moved" msgid="4606538322571412879">"Ставка је премештена"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Додај у фолдер: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додај у фолдер у коме је <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Ставка је додата у фолдер"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Направите фолдер са: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Фолдер је направљен"</string>
- <string name="action_move_to_workspace" msgid="39528912300293768">"Преместите на почетни екран"</string>
- <string name="action_resize" msgid="1802976324781771067">"Промени величину"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Повећај ширину"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Повећај висину"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Смањи ширину"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Смањи висину"</string>
- <string name="widget_resized" msgid="9130327887929620">"Величина виџета је промењена на ширину <xliff:g id="NUMBER_0">%1$s</xliff:g> и висину <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Пречице"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Пречице и обавештења"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Одбаци"</string>
- <string name="accessibility_close" msgid="2277148124685870734">"Затвори"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Обавештење је одбачено"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Личне"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Пословне"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Пословни профил"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Пословне апликације су означене значком и ИТ администратор може да их види"</string>
- <string name="work_profile_edu_accept" msgid="6069788082535149071">"Важи"</string>
- <string name="work_apps_paused_title" msgid="3040901117349444598">"Пословне апликације су паузиране"</string>
- <string name="work_apps_paused_body" msgid="261634750995824906">"Пословне апликације не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
- <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Пословне апликације су искључене. Пословне апликације не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
- <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Пословне апликације су означене значком и ИТ администратор може да их види"</string>
- <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Важи"</string>
- <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Паузирај пословне апликације"</string>
- <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Укључи пословне апликације"</string>
- <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
- <string name="search_pref_screen_title" msgid="3258959643336315962">"Претражите телефон"</string>
- <string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Претражите таблет"</string>
- <string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
+ <string name="widget_button_text" msgid="2880537293434387943">"Vidžeti"</string>
+ <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Pretražite"</string>
+ <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Obrišite tekst iz okvira za pretragu"</string>
+ <string name="no_widgets_available" msgid="4337693382501046170">"Vidžeti i prečice nisu dostupni"</string>
+ <string name="no_search_results" msgid="3787956167293097509">"Nije pronađen nijedan vidžet ni prečica"</string>
+ <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Lično"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
+ <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzacije"</string>
+ <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
+ <string name="widget_education_content" msgid="1731667670753497052">"Da biste pronašli informacije bez otvaranja aplikacija, možete da dodate vidžete na početni ekran"</string>
+ <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
+ <string name="widget_education_close_button" msgid="8676165703104836580">"Važi"</string>
+ <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promenite podešavanja vidžeta"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
+ <string name="label_application" msgid="8531721983832654978">"Aplikacija"</string>
+ <string name="all_apps_label" msgid="5015784846527570951">"Sve aplikacije"</string>
+ <string name="notifications_header" msgid="1404149926117359025">"Obaveštenja"</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Dodirnite i zadržite radi pomeranja prečice."</string>
+ <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Dvaput dodirnite i zadržite da biste pomerali prečicu ili koristite prilagođene radnje."</string>
+ <string name="out_of_space" msgid="6455557115204099579">"Nema mesta na ovom početnom ekranu"</string>
+ <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Omiljeno"</string>
+ <string name="all_apps_button_label" msgid="8130441508702294465">"Lista aplikacija"</string>
+ <string name="all_apps_search_results" msgid="5889367432531296759">"Rezultati pretrage"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista ličnih aplikacija"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
+ <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
+ <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"Infor. o aplikaciji"</string>
+ <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
+ <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
+ <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
+ <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
+ <string name="permlab_read_settings" msgid="5136500343007704955">"čitanje podešavanja i prečica na početnom ekranu"</string>
+ <string name="permdesc_read_settings" msgid="4208061150510996676">"Dozvoljava aplikaciji da čita podešavanja i prečice na početnom ekranu."</string>
+ <string name="permlab_write_settings" msgid="4820028712156303762">"upisivanje podešavanja i prečica na početnom ekranu"</string>
+ <string name="permdesc_write_settings" msgid="726859348127868466">"Dozvoljava aplikaciji da menja podešavanja i prečice na početnom ekranu."</string>
+ <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> nema dozvolu za upućivanje telefonskih poziva"</string>
+ <string name="gadget_error_text" msgid="740356548025791839">"Učitavanje vidžeta nije uspelo"</string>
+ <string name="gadget_setup_text" msgid="8348374825537681407">"Podešavanja vidžeta"</string>
+ <string name="gadget_complete_setup_text" msgid="309040266978007925">"Dodirnite da biste dovršili podešavanje"</string>
+ <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je sistemska aplikacija i ne može da se deinstalira."</string>
+ <string name="folder_hint_text" msgid="5174843001373488816">"Izmenite naziv"</string>
+ <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućena"</string>
+ <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name}, ima # obaveštenje}one{{app_name}, ima # obaveštenje}few{{app_name}, ima # obaveštenja}other{{app_name}, ima # obaveštenja}}"</string>
+ <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. stranica od %2$d"</string>
+ <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. početni ekran od %2$d"</string>
+ <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
+ <string name="folder_opened" msgid="94695026776264709">"Folder je otvoren, <xliff:g id="WIDTH">%1$d</xliff:g> puta <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
+ <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da biste zatvorili folder"</string>
+ <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da biste sačuvali preimenovanje"</string>
+ <string name="folder_closed" msgid="4100806530910930934">"Folder je zatvoren"</string>
+ <string name="folder_renamed" msgid="1794088362165669656">"Folder je preimenovan u <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> stavke"</string>
+ <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ili više stavki"</string>
+ <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadine"</string>
+ <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Pozadina i stil"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Podešavanja početnog ekrana"</string>
+ <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator je onemogućio"</string>
+ <string name="allow_rotation_title" msgid="7222049633713050106">"Dozvoli rotaciju početnog ekrana"</string>
+ <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon rotira"</string>
+ <string name="notification_dots_title" msgid="9062440428204120317">"Tačke za obaveštenja"</string>
+ <string name="notification_dots_desc_on" msgid="1679848116452218908">"Uključeno"</string>
+ <string name="notification_dots_desc_off" msgid="1760796511504341095">"Isključeno"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup za obaveštenja"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Promenite podešavanja"</string>
+ <string name="notification_dots_service_title" msgid="4284221181793592871">"Prikazuj tačke za obaveštenja"</string>
+ <string name="developer_options_title" msgid="700788437593726194">"Opcije za programera"</string>
+ <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Dodaj ikone aplikacija na početni ekran"</string>
+ <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
+ <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
+ <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
+ <string name="abandoned_search" msgid="891119232568284442">"Pretraži"</string>
+ <string name="abandoned_promises_title" msgid="7096178467971716750">"Ova aplikacija nije instalirana"</string>
+ <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za ovu ikonu nije instalirana. Možete da je uklonite ili da potražite aplikaciju i instalirate je ručno."</string>
+ <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalira, <xliff:g id="PROGRESS">%2$s</xliff:g> gotovo"</string>
+ <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
+ <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
+ <string name="dialog_update_title" msgid="114234265740994042">"Treba da ažurirate aplikaciju"</string>
+ <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete da je ručno ažurirate da biste ponovo omogućili ovu prečicu ili uklonite ikonu."</string>
+ <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
+ <string name="dialog_remove" msgid="6510806469849709407">"Ukloni"</string>
+ <string name="widgets_list" msgid="796804551140113767">"Lista vidžeta"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"Lista vidžeta je zatvorena"</string>
+ <string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni ekran"</string>
+ <string name="action_move_here" msgid="2170188780612570250">"Premesti stavku ovde"</string>
+ <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodata na početni ekran"</string>
+ <string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+ <string name="undo" msgid="4151576204245173321">"Opozovi"</string>
+ <string name="action_move" msgid="4339390619886385032">"Premesti stavku"</string>
+ <string name="move_to_empty_cell_description" msgid="5254852678218206889">"Premestite u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g> na <xliff:g id="STRING">%3$s</xliff:g>"</string>
+ <string name="move_to_position" msgid="6750008980455459790">"Premesti na <xliff:g id="NUMBER">%1$s</xliff:g>. poziciju"</string>
+ <string name="move_to_hotseat_position" msgid="6295412897075147808">"Premesti na <xliff:g id="NUMBER">%1$s</xliff:g>. poziciju u omiljenim"</string>
+ <string name="item_moved" msgid="4606538322571412879">"Stavka je premeštena"</string>
+ <string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder u kome je <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="added_to_folder" msgid="4793259502305558003">"Stavka je dodata u folder"</string>
+ <string name="create_folder_with" msgid="4050141361160214248">"Napravite folder sa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="folder_created" msgid="6409794597405184510">"Folder je napravljen"</string>
+ <string name="action_move_to_workspace" msgid="39528912300293768">"Premestite na početni ekran"</string>
+ <string name="action_resize" msgid="1802976324781771067">"Promeni veličinu"</string>
+ <string name="action_increase_width" msgid="8773715375078513326">"Povećaj širinu"</string>
+ <string name="action_increase_height" msgid="459390020612501122">"Povećaj visinu"</string>
+ <string name="action_decrease_width" msgid="1374549771083094654">"Smanji širinu"</string>
+ <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
+ <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> i visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+ <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
+ <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obaveštenja"</string>
+ <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
+ <string name="accessibility_close" msgid="2277148124685870734">"Zatvori"</string>
+ <string name="notification_dismissed" msgid="6002233469409822874">"Obaveštenje je odbačeno"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Poslovni profil"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Poslovne aplikacije su označene značkom i IT administrator može da ih vidi"</string>
+ <string name="work_profile_edu_accept" msgid="6069788082535149071">"Važi"</string>
+ <string name="work_apps_paused_title" msgid="3040901117349444598">"Poslovne aplikacije su pauzirane"</string>
+ <string name="work_apps_paused_body" msgid="261634750995824906">"Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
+ <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Poslovne aplikacije su isključene. Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
+ <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Poslovne aplikacije su označene značkom i IT administrator može da ih vidi"</string>
+ <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Važi"</string>
+ <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pauziraj poslovne aplikacije"</string>
+ <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Uključi poslovne aplikacije"</string>
+ <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
+ <string name="search_pref_screen_title" msgid="3258959643336315962">"Pretražite telefon"</string>
+ <string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pretražite tablet"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 40e49f1..09b2d6f 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -46,7 +46,4 @@
<!-- Folder spaces -->
<dimen name="folder_footer_horiz_padding">24dp</dimen>
-
- <!-- Transient taskbar -->
- <dimen name="transient_taskbar_icon_size">57dp</dimen>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b57eb02..4d2e1b7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -365,8 +365,8 @@
<dimen name="min_hotseat_icon_space">18dp</dimen>
<dimen name="max_hotseat_icon_space">50dp</dimen>
<dimen name="min_hotseat_qsb_width">0dp</dimen>
- <dimen name="taskbar_icon_size">44dp</dimen>
- <dimen name="transient_taskbar_icon_size">50dp</dimen>
+ <dimen name="taskbar_icon_size">0dp</dimen>
+ <dimen name="transient_taskbar_icon_size">0dp</dimen>
<!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="transient_taskbar_size">0dp</dimen>
<dimen name="transient_taskbar_margin">0dp</dimen>
@@ -374,10 +374,7 @@
<dimen name="transient_taskbar_key_shadow_distance">0dp</dimen>
<dimen name="transient_taskbar_stashed_size">0dp</dimen>
<dimen name="transient_taskbar_clamped_offset_bound">0dp</dimen>
- <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
- <dimen name="transient_taskbar_icon_spacing">0dp</dimen>
- <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
- <dimen name="taskbar_icon_spacing">8dp</dimen>
+ <dimen name="taskbar_icon_spacing">0dp</dimen>
<dimen name="taskbar_nav_buttons_size">0dp</dimen>
<dimen name="taskbar_contextual_button_margin">0dp</dimen>
<dimen name="taskbar_hotseat_nav_spacing">0dp</dimen>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 61707df..e71391f 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -176,14 +176,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (Utilities.ATLEAST_T) {
- getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- () -> {
- onBackPressed();
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
- });
- }
+ registerBackDispatcher();
}
@Override
@@ -246,6 +239,17 @@
}
+ protected void registerBackDispatcher() {
+ if (Utilities.ATLEAST_T) {
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ () -> {
+ onBackPressed();
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
+ });
+ }
+ }
+
public boolean isStarted() {
return (mActivityFlags & ACTIVITY_STATE_STARTED) != 0;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 25520e1..f124940 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -910,12 +910,24 @@
cellHeightPx = cellContentHeight;
cellLayoutBorderSpacePx.y -= extraHeightRequired / numBorders;
} else {
- // If it still doesn't fit, set borderSpace to 0 and distribute the space for
- // cellHeight, and reduce iconSize.
+ // If it still doesn't fit, set borderSpace to 0 to recover space.
cellHeightPx = (cellHeightPx * inv.numRows
+ cellLayoutBorderSpacePx.y * numBorders) / inv.numRows;
- iconSizePx = Math.min(iconSizePx, cellHeightPx - cellTextAndPaddingHeight);
cellLayoutBorderSpacePx.y = 0;
+ // Reduce iconDrawablePaddingPx to make cellContentHeight smaller.
+ int cellContentWithoutPadding = cellContentHeight - iconDrawablePaddingPx;
+ if (cellContentWithoutPadding <= cellHeightPx) {
+ iconDrawablePaddingPx = cellContentHeight - cellHeightPx;
+ } else {
+ // If it still doesn't fit, set iconDrawablePaddingPx to 0 to recover space,
+ // then proportional reduce iconSizePx and iconTextSizePx to fit.
+ iconDrawablePaddingPx = 0;
+ float ratio = cellHeightPx / (float) cellContentWithoutPadding;
+ iconSizePx = (int) (iconSizePx * ratio);
+ iconTextSizePx = (int) (iconTextSizePx * ratio);
+ }
+ cellTextAndPaddingHeight =
+ iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
}
cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 43772e4..e9723a5 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -120,6 +120,7 @@
import android.widget.Toast;
import androidx.annotation.CallSuper;
+import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -2065,6 +2066,14 @@
mStateManager.getState().onBackPressed(this);
}
+ protected void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float backProgress) {
+ mStateManager.getState().onBackProgressed(this, backProgress);
+ }
+
+ protected void onBackCancelled() {
+ mStateManager.getState().onBackCancelled(this);
+ }
+
protected void onScreenOff() {
// Reset AllApps to its initial state only if we are not in the middle of
// processing a multi-step drop
@@ -3317,4 +3326,12 @@
return false; // Return false to continue iterating through all the items.
});
}
+
+ /**
+ * Returns {@code true} if there are visible tasks with windowing mode set to
+ * {@link android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM}
+ */
+ public boolean areFreeformTasksVisible() {
+ return false; // Base launcher does not track freeform tasks
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 20df897..2c6458b 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -47,7 +47,7 @@
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.CacheDataUpdatedTask;
import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.model.LoaderResults;
+import com.android.launcher3.model.LauncherBinder;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDelegate;
import com.android.launcher3.model.ModelWriter;
@@ -405,22 +405,22 @@
MAIN_EXECUTOR.execute(cb::clearPendingBinds);
}
- LoaderResults loaderResults = new LoaderResults(
+ LauncherBinder launcherBinder = new LauncherBinder(
mApp, mBgDataModel, mBgAllAppsList, callbacksList);
if (bindDirectly) {
// Divide the set of loaded items into those that we are binding synchronously,
// and everything else that is to be bound normally (asynchronously).
- loaderResults.bindWorkspace(bindAllCallbacks);
+ launcherBinder.bindWorkspace(bindAllCallbacks);
// For now, continue posting the binding of AllApps as there are other
// issues that arise from that.
- loaderResults.bindAllApps();
- loaderResults.bindDeepShortcuts();
- loaderResults.bindWidgets();
+ launcherBinder.bindAllApps();
+ launcherBinder.bindDeepShortcuts();
+ launcherBinder.bindWidgets();
return true;
} else {
stopLoader();
mLoaderTask = new LoaderTask(
- mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);
+ mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, launcherBinder);
// Always post the loader task, instead of running directly
// (even on same thread) so that we exit any nested synchronized blocks
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 23ff10a..0d6ed04 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -9,12 +9,17 @@
fun getPrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so that we use a single cached instance
return context.applicationContext.getSharedPreferences(
- LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
+ LauncherFiles.SHARED_PREFERENCES_KEY,
+ Context.MODE_PRIVATE
+ )
}
@JvmStatic
fun getDevicePrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so that we use a single cached instance
return context.applicationContext.getSharedPreferences(
- LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE)
- }}
\ No newline at end of file
+ LauncherFiles.DEVICE_PREFERENCES_KEY,
+ Context.MODE_PRIVATE
+ )
+ }
+}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 5dddc6f..b9e4c17 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -34,6 +34,8 @@
import android.graphics.Color;
import android.view.animation.Interpolator;
+import androidx.annotation.FloatRange;
+
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.HintState;
@@ -342,6 +344,27 @@
}
}
+ /**
+ * Find {@link StateManager} and target {@link LauncherState} to handle back progress in
+ * predictive back gesture.
+ */
+ public void onBackProgressed(
+ Launcher launcher, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
+ StateManager<LauncherState> lsm = launcher.getStateManager();
+ LauncherState toState = lsm.getLastState();
+ lsm.onBackProgressed(toState, backProgress);
+ }
+
+ /**
+ * Find {@link StateManager} and target {@link LauncherState} to handle backProgress in
+ * predictive back gesture.
+ */
+ public void onBackCancelled(Launcher launcher) {
+ StateManager<LauncherState> lsm = launcher.getStateManager();
+ LauncherState toState = lsm.getLastState();
+ lsm.onBackCancelled(toState);
+ }
+
public static abstract class PageAlphaProvider {
public final Interpolator interpolator;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index eb68adb..4f5cc4a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -699,7 +699,7 @@
}
/** Returns true iff this PagedView's scroll amounts are initialized to each page index. */
- protected boolean pageScrollsInitialized() {
+ protected boolean isPageScrollsInitialized() {
return mPageScrolls != null && mPageScrolls.length == getChildCount();
}
@@ -708,12 +708,12 @@
*/
public void runOnPageScrollsInitialized(Runnable callback) {
mOnPageScrollsInitializedCallbacks.add(callback);
- if (pageScrollsInitialized()) {
+ if (isPageScrollsInitialized()) {
onPageScrollsInitialized();
}
}
- private void onPageScrollsInitialized() {
+ protected void onPageScrollsInitialized() {
for (Runnable callback : mOnPageScrollsInitializedCallbacks) {
callback.run();
}
@@ -727,7 +727,7 @@
final int childCount = getChildCount();
int[] pageScrolls = mPageScrolls;
boolean pageScrollChanged = false;
- if (!pageScrollsInitialized()) {
+ if (!isPageScrollsInitialized()) {
pageScrolls = new int[childCount];
pageScrollChanged = true;
}
@@ -1199,7 +1199,7 @@
}
public int getScrollForPage(int index) {
- if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
+ if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
return 0;
} else {
return mPageScrolls[index];
@@ -1209,7 +1209,7 @@
// While layout transitions are occurring, a child's position may stray from its baseline
// position. This method returns the magnitude of this stray at any given time.
public int getLayoutTransitionOffsetForPage(int index) {
- if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
+ if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
return 0;
} else {
View child = getChildAt(index);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b10256e..d7e84f0 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -723,4 +723,14 @@
}
return options;
}
+
+ /** Logs the Scale and Translate properties of a matrix. Ignores skew and perspective. */
+ public static void logMatrix(String label, Matrix matrix) {
+ float[] matrixValues = new float[9];
+ matrix.getValues(matrixValues);
+ Log.d(label, String.format("%s: %s\nscale (x,y) = (%f, %f)\ntranslate (x,y) = (%f, %f)",
+ label, matrix, matrixValues[Matrix.MSCALE_X], matrixValues[Matrix.MSCALE_Y],
+ matrixValues[Matrix.MTRANS_X], matrixValues[Matrix.MTRANS_Y]
+ ));
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 483309d..2b9c135 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -62,6 +62,7 @@
import android.widget.Toast;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
@@ -161,7 +162,9 @@
protected ShortcutAndWidgetContainer mDragSourceInternal;
- @Thunk final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ @Thunk public final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
+
@Thunk final IntArray mScreenOrder = new IntArray();
@Thunk boolean mDeferRemoveExtraEmptyScreen = false;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 9930abe..24bfedb 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
@@ -33,11 +34,15 @@
import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.FloatRange;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
@@ -61,6 +66,8 @@
implements StateHandler<LauncherState>, OnDeviceProfileChangeListener {
// This constant should match the second derivative of the animator interpolator.
public static final float INTERP_COEFF = 1.7f;
+ private static final float SWIPE_ALL_APPS_TO_HOME_MIN_SCALE = 0.9f;
+ private static final int REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS = 200;
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -139,6 +146,7 @@
private ActivityAllAppsContainerView<Launcher> mAppsView;
private final Launcher mLauncher;
+ private final AnimatedFloat mAllAppScale = new AnimatedFloat(this::onScaleProgressChanged);
private boolean mIsVerticalLayout;
// Whether this class should take care of closing the keyboard.
@@ -232,6 +240,52 @@
onProgressAnimationEnd();
}
+ @Override
+ public void onBackProgressed(
+ LauncherState toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
+ if (!mLauncher.isInState(ALL_APPS) || !NORMAL.equals(toState)) {
+ return;
+ }
+
+ float deceleratedProgress =
+ Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(backProgress);
+ float scaleProgress = SWIPE_ALL_APPS_TO_HOME_MIN_SCALE
+ + (1 - SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) * (1 - deceleratedProgress);
+
+ mAllAppScale.updateValue(scaleProgress);
+ }
+
+ @Override
+ public void onBackCancelled(LauncherState toState) {
+ if (!mLauncher.isInState(ALL_APPS) || !NORMAL.equals(toState)) {
+ return;
+ }
+
+ // TODO: once ag/20649618 is picked into tm-qpr, we don't need to animate back on cancel
+ // swipe because framework will do that for us in {@link #onBackProgressed}.
+ animateAllAppsToNoScale();
+ }
+
+ private void onScaleProgressChanged() {
+ final float scaleProgress = mAllAppScale.value;
+ SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
+ mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+
+ AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
+ if (rv != null && rv.getScrollbar() != null) {
+ rv.getScrollbar().setVisibility(scaleProgress < 1f ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ // TODO(b/264906511): We need to disable view clipping on all apps' parent views so
+ // that the extra roll of app icons are displayed.
+ }
+
+ private void animateAllAppsToNoScale() {
+ mAllAppScale.animateToValue(1f)
+ .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
+ .start();
+ }
+
/**
* Creates an animation which updates the vertical transition progress and updates all the
* dependent UI using various animation events
@@ -258,6 +312,8 @@
if (config.userControlled && success && mShouldControlKeyboard) {
mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
}
+
+ mAllAppScale.updateValue(1f);
});
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index fc1b830..29767bf 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -239,23 +239,24 @@
mAdapterItems.addAll(mSearchResults);
} else {
int position = 0;
+ boolean addApps = true;
if (mWorkProviderManager != null) {
position += mWorkProviderManager.addWorkItems(mAdapterItems);
- if (!mWorkProviderManager.shouldShowWorkApps()) {
- return;
- }
+ addApps = mWorkProviderManager.shouldShowWorkApps();
}
- String lastSectionName = null;
- for (AppInfo info : mApps) {
- mAdapterItems.add(AdapterItem.asApp(info));
+ if (addApps) {
+ String lastSectionName = null;
+ for (AppInfo info : mApps) {
+ mAdapterItems.add(AdapterItem.asApp(info));
- String sectionName = info.sectionName;
- // Create a new section if the section names do not match
- if (!sectionName.equals(lastSectionName)) {
- lastSectionName = sectionName;
- mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
+ String sectionName = info.sectionName;
+ // Create a new section if the section names do not match
+ if (!sectionName.equals(lastSectionName)) {
+ lastSectionName = sectionName;
+ mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
+ }
+ position++;
}
- position++;
}
}
mAccessibilityResultsCount = (int) mAdapterItems.stream()
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index ca08164..4878077 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -163,7 +163,8 @@
mWorkManager = new WorkProfileManager(
mActivityContext.getSystemService(UserManager.class),
- this, LauncherPrefs.getPrefs(mActivityContext));
+ this, LauncherPrefs.getPrefs(mActivityContext),
+ mActivityContext.getStatsLogManager());
mAH = Arrays.asList(null, null, null);
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
@@ -807,7 +808,7 @@
}
@Override
- public void drawOnScrim(Canvas canvas) {
+ public void drawOnScrimWithScale(Canvas canvas, float scale) {
boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
// Draw full background panel for tablets.
@@ -832,7 +833,9 @@
if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
return;
}
- int bottom = getHeaderBottom() + getVisibleContainerView().getPaddingTop();
+ final float offset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
+ final float bottom =
+ scale * (getHeaderBottom() + getVisibleContainerView().getPaddingTop()) + offset;
FloatingHeaderView headerView = getFloatingHeaderView();
if (isTablet) {
// Start adding header protection if search bar or tabs will attach to the top.
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index c9466a8..11ce738 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_COLLAPSE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_EXTEND;
import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
import android.animation.LayoutTransition;
@@ -37,6 +39,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.views.ActivityContext;
/**
@@ -59,6 +62,8 @@
private final int mScrollThreshold;
private ImageView mIcon;
private TextView mTextView;
+ private final StatsLogManager mStatsLogManager;
+
public WorkModeSwitch(@NonNull Context context) {
this(context, null, 0);
@@ -72,6 +77,7 @@
super(context, attrs, defStyleAttr);
mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
mActivityContext = ActivityContext.lookupContext(getContext());
+ mStatsLogManager = mActivityContext.getStatsLogManager();
}
@Override
@@ -197,10 +203,12 @@
public void extend() {
mTextView.setVisibility(VISIBLE);
+ mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_EXTEND);
}
public void shrink(){
mTextView.setVisibility(GONE);
+ mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_COLLAPSE);
}
public int getScrollThreshold() {
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 547b74c..279f0d3 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -43,8 +43,8 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
import java.lang.annotation.Retention;
@@ -80,6 +80,7 @@
private final UserManager mUserManager;
private final BaseAllAppsContainerView<?> mAllApps;
private final Predicate<ItemInfo> mMatcher;
+ private final StatsLogManager mStatsLogManager;
private WorkModeSwitch mWorkModeSwitch;
@@ -88,11 +89,13 @@
private SharedPreferences mPreferences;
public WorkProfileManager(
- UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs) {
+ UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs,
+ StatsLogManager statsLogManager) {
mUserManager = userManager;
mAllApps = allApps;
mPreferences = prefs;
mMatcher = mAllApps.mPersonalMatcher.negate();
+ mStatsLogManager = statsLogManager;
}
/**
@@ -227,9 +230,7 @@
private void onWorkFabClicked(View view) {
if (Utilities.ATLEAST_P && mCurrentState == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
- ActivityContext activityContext = ActivityContext.lookupContext(
- mWorkModeSwitch.getContext());
- activityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
+ mStatsLogManager.logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
setWorkProfileEnabled(false);
}
}
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index b55a1e4..e886543 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -56,6 +56,8 @@
public static final Interpolator DECELERATED_EASE = new PathInterpolator(0, 0, .2f, 1f);
public static final Interpolator ACCELERATED_EASE = new PathInterpolator(0.4f, 0, 1f, 1f);
+ public static final Interpolator PREDICTIVE_BACK_DECELERATED_EASE =
+ new PathInterpolator(0, 0, 0, 1f);
/**
* The default emphasized interpolator. Used for hero / emphasized movement of content.
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index b46e43f..daf83d4 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -273,6 +273,10 @@
"ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
"Enable option to replace decorator-based search result backgrounds with drawables");
+ public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = new DeviceFlag(
+ "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false,
+ "Enable option to launch search results using the new standardized transitions");
+
public static final BooleanFlag TWO_PREDICTED_ROWS_ALL_APPS_SEARCH = new DeviceFlag(
"TWO_PREDICTED_ROWS_ALL_APPS_SEARCH", false,
"Use 2 rows of app predictions in All Apps search zero-state");
@@ -364,7 +368,7 @@
"ENABLE_DEVICE_PROFILE_LOGGING", false, "Allows DeviceProfile logging");
public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(
- "ENABLE_LAUNCH_FROM_STAGED_APP", false,
+ "ENABLE_LAUNCH_FROM_STAGED_APP", true,
"Enable the ability to tap a staged app during split select to launch it in full screen"
);
@@ -377,6 +381,10 @@
"ENABLE_TASKBAR_EDU_TOOLTIP", false,
"Enable the tooltip version of the Taskbar education flow.");
+ public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(
+ "ENABLE_MULTI_INSTANCE", false,
+ "Enables creation and filtering of multiple task instances in overview");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 09fe740..f54d05d 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -568,7 +568,8 @@
.setSpring(new SpringForce(0)
.setDampingRatio(DAMPENING_RATIO)
.setStiffness(STIFFNESS));
- mDelta = view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP;
+ mDelta = Math.min(
+ range, view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP);
}
public void animateToPos(float value) {
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 9a961ca..de47cb5 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -17,6 +17,7 @@
package com.android.launcher3.graphics;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
@@ -39,6 +40,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -72,12 +74,13 @@
private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA);
private static final long DURATION_SCALE = 500;
+ private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500;
// The smaller the number, the faster the animation would be.
// Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE
private static final float COMPLETE_ANIM_FRACTION = 0.3f;
- private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.85f : 0.7f;
+ private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.867f : 0.7f;
private static final float PROGRESS_STROKE_SCALE = 0.075f;
private static final int PRELOAD_ACCENT_COLOR_INDEX = 0;
@@ -110,12 +113,13 @@
private int mTrackAlpha;
private float mTrackLength;
- private float mIconScale;
private boolean mRanFinishAnimation;
- private int mOverlayAlpha = 127;
- private int mRefreshRateMillis;
+ private final int mRefreshRateMillis;
+ private final AnimatedFloat mIconScale = new AnimatedFloat(this::invalidateSelf);
+ private final AnimatedFloat mOverlayAlpha = new AnimatedFloat(this::updateOverlayAlpha);
+ private boolean mShouldAnimateScaleAndAlpha;
// Progress of the internal state. [0, 1] indicates the fraction of completed progress,
// [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation.
@@ -155,6 +159,12 @@
mIsDarkMode = isDarkMode;
mRefreshRateMillis = refreshRateMillis;
+ // If it's a pending app we will animate scale and alpha when it's no longer pending.
+ if (ENABLE_DOWNLOAD_APP_UX_V2.get() && info.getProgressLevel() == 0) {
+ mShouldAnimateScaleAndAlpha = true;
+ mOverlayAlpha.updateValue(127);
+ }
+
setLevel(info.getProgressLevel());
setIsStartable(info.isAppStartable());
}
@@ -199,7 +209,8 @@
canvas.drawPath(mScaledProgressPath, mProgressPaint);
int saveCount = canvas.save();
- canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
+ canvas.scale(
+ mIconScale.value, mIconScale.value, bounds.exactCenterX(), bounds.exactCenterY());
super.drawInternal(canvas, bounds);
canvas.restoreToCount(saveCount);
@@ -301,18 +312,34 @@
* - only icon is drawn in normal state
*/
private void setInternalProgress(float progress) {
+ // Animate scale and alpha from pending to downloading state.
+ if (ENABLE_DOWNLOAD_APP_UX_V2.get()
+ && mShouldAnimateScaleAndAlpha && mInternalStateProgress == 0 && progress > 0) {
+ Animator iconScaleAnimator = mIconScale.animateToValue(SMALL_SCALE);
+ iconScaleAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION);
+ iconScaleAnimator.setInterpolator(EMPHASIZED);
+ iconScaleAnimator.start();
+
+ Animator overlayAlphaAnimator = mOverlayAlpha.animateToValue(0);
+ overlayAlphaAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION);
+ overlayAlphaAnimator.setInterpolator(EMPHASIZED);
+ overlayAlphaAnimator.start();
+ }
+
mInternalStateProgress = progress;
if (progress <= 0) {
- mIconScale = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE;
+ mIconScale.updateValue(ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE);
mScaledTrackPath.reset();
mTrackAlpha = MAX_PAINT_ALPHA;
} else if (progress < 1) {
mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true);
if (ENABLE_DOWNLOAD_APP_UX_V2.get()) {
- mPaint.setColorFilter(null);
mPathMeasure.getSegment(0, mTrackLength, mScaledTrackPath, true);
}
- mIconScale = SMALL_SCALE;
+
+ if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || !mShouldAnimateScaleAndAlpha) {
+ mIconScale.updateValue(SMALL_SCALE);
+ }
mTrackAlpha = MAX_PAINT_ALPHA;
} else {
setIsDisabled(mItem.isDisabled());
@@ -321,11 +348,11 @@
if (fraction >= 1) {
// Animation has completed
- mIconScale = 1;
+ mIconScale.updateValue(1);
mTrackAlpha = 0;
} else {
mTrackAlpha = Math.round((1 - fraction) * MAX_PAINT_ALPHA);
- mIconScale = SMALL_SCALE + (1 - SMALL_SCALE) * fraction;
+ mIconScale.updateValue(SMALL_SCALE + (1 - SMALL_SCALE) * fraction);
}
}
invalidateSelf();
@@ -370,9 +397,7 @@
if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) {
return;
}
- if (applyPendingIconOverlay()) {
- invalidateSelf();
- } else {
+ if (!applyPendingIconOverlay()) {
reschedule();
}
}
@@ -408,7 +433,7 @@
long waveMotionDelay = (mItem.cellX * WAVE_MOTION_DELAY_FACTOR_MILLIS)
+ (mItem.cellY * WAVE_MOTION_DELAY_FACTOR_MILLIS);
long time = SystemClock.uptimeMillis();
- int newAlpha = (int) Utilities.mapBoundToRange(
+ float newAlpha = Utilities.mapBoundToRange(
(float) (time + waveMotionDelay) % ALPHA_DURATION_MILLIS,
0,
ALPHA_DURATION_MILLIS,
@@ -416,22 +441,25 @@
MAX_PAINT_ALPHA,
LINEAR);
if (newAlpha > OVERLAY_ALPHA_RANGE) {
- newAlpha = (int) (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE));
+ newAlpha = (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE));
}
boolean invalidate = false;
- if (mOverlayAlpha != newAlpha) {
- mOverlayAlpha = newAlpha;
- int overlayColor = mIsDarkMode ? 0 : 255;
- int currArgb = Color.argb(mOverlayAlpha, overlayColor, overlayColor, overlayColor);
- mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent(
- currArgb,
- FILTER_FACTORY));
+ if ((int) mOverlayAlpha.value != newAlpha) {
+ mOverlayAlpha.updateValue(newAlpha);
invalidate = true;
}
return invalidate;
}
+ private void updateOverlayAlpha() {
+ int overlayColor = mIsDarkMode ? 0 : 255;
+ int currArgb =
+ Color.argb((int) mOverlayAlpha.value, overlayColor, overlayColor, overlayColor);
+ mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent(currArgb, FILTER_FACTORY));
+ invalidateSelf();
+ }
+
protected static class PreloadIconConstantState extends FastBitmapConstantState {
protected final ItemInfoWithIcon mInfo;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 24d8c9d..2159c6b 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -624,7 +624,13 @@
LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM(1232),
@UiEvent(doc = "User has invoked split to left half with a keyboard shortcut.")
- LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233)
+ LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233),
+
+ @UiEvent(doc = "User has collapsed the work FAB button by swiping down")
+ LAUNCHER_WORK_FAB_BUTTON_COLLAPSE(1276),
+
+ @UiEvent(doc = "User has collapsed the work FAB button by swiping up")
+ LAUNCHER_WORK_FAB_BUTTON_EXTEND(1277),
;
// ADD MORE
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 6da948c..8f85bfb 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
-import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED;
import android.content.ComponentName;
import android.content.Context;
@@ -39,7 +38,6 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SafeCloseable;
@@ -275,14 +273,8 @@
}
public void updateIconsAndLabels(HashSet<String> packages, UserHandle user) {
- if (TestProtocol.sDebugTracing) {
- Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: packages=" + packages);
- }
for (AppInfo info : data) {
if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) {
- if (TestProtocol.sDebugTracing) {
- Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: updating info=" + info);
- }
mIconCache.updateTitleAndIcon(info);
info.sectionName = mIndex.computeSectionName(info.title);
mDataChanged = true;
diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
similarity index 95%
rename from src/com/android/launcher3/model/BaseLoaderResults.java
rename to src/com/android/launcher3/model/BaseLauncherBinder.java
index 8c6428b..9f8db51 100644
--- a/src/com/android/launcher3/model/BaseLoaderResults.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -47,12 +47,11 @@
import java.util.concurrent.Executor;
/**
- * Base Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
*/
-public abstract class BaseLoaderResults {
+public abstract class BaseLauncherBinder {
- protected static final String TAG = "LoaderResults";
- protected static final int INVALID_SCREEN_ID = -1;
+ protected static final String TAG = "LauncherBinder";
private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
protected final LooperExecutor mUiExecutor;
@@ -65,7 +64,7 @@
private int mMyBindingId;
- public BaseLoaderResults(LauncherAppState app, BgDataModel dataModel,
+ public BaseLauncherBinder(LauncherAppState app, BgDataModel dataModel,
AllAppsList allAppsList, Callbacks[] callbacksList, LooperExecutor uiExecutor) {
mUiExecutor = uiExecutor;
mApp = app;
@@ -101,8 +100,14 @@
}
}
+ /**
+ * BindDeepShortcuts is abstract because it is a no-op for the go launcher.
+ */
public abstract void bindDeepShortcuts();
+ /**
+ * Binds the all apps results from LoaderTask to the callbacks UX.
+ */
public void bindAllApps() {
// shallow copy
AppInfo[] apps = mBgAllAppsList.copyData();
@@ -110,6 +115,9 @@
executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor);
}
+ /**
+ * bindWidgets is abstract because it is a no-op for the go launcher.
+ */
public abstract void bindWidgets();
/**
@@ -160,6 +168,9 @@
});
}
+ /**
+ * Only used in LoaderTask.
+ */
public LooperIdleLock newIdleLock(Object lock) {
LooperIdleLock idleLock = new LooperIdleLock(lock, mUiExecutor.getLooper());
// If we are not binding or if the main looper is already idle, there is no reason to wait
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1d6971e..46a6a66 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -125,7 +125,7 @@
private FirstScreenBroadcast mFirstScreenBroadcast;
- private final LoaderResults mResults;
+ private final LauncherBinder mLauncherBinder;
private final LauncherApps mLauncherApps;
private final UserManager mUserManager;
@@ -145,12 +145,12 @@
private String mDbName;
public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
- ModelDelegate modelDelegate, LoaderResults results) {
+ ModelDelegate modelDelegate, LauncherBinder launcherBinder) {
mApp = app;
mBgAllAppsList = bgAllAppsList;
mBgDataModel = dataModel;
mModelDelegate = modelDelegate;
- mResults = results;
+ mLauncherBinder = launcherBinder;
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
@@ -163,7 +163,7 @@
// Wait until the either we're stopped or the other threads are done.
// This way we don't start loading all apps until the workspace has settled
// down.
- LooperIdleLock idleLock = mResults.newIdleLock(this);
+ LooperIdleLock idleLock = mLauncherBinder.newIdleLock(this);
// Just in case mFlushingWorkerThread changes but we aren't woken up,
// wait no longer than 1sec at a time
while (!mStopped && idleLock.awaitLocked(1000));
@@ -221,7 +221,7 @@
}
verifyNotStopped();
- mResults.bindWorkspace(true /* incrementBindId */);
+ mLauncherBinder.bindWorkspace(true /* incrementBindId */);
logASplit(logger, "bindWorkspace");
mModelDelegate.workspaceLoadComplete();
@@ -245,7 +245,7 @@
logASplit(logger, "loadAllApps");
verifyNotStopped();
- mResults.bindAllApps();
+ mLauncherBinder.bindAllApps();
logASplit(logger, "bindAllApps");
verifyNotStopped();
@@ -271,7 +271,7 @@
logASplit(logger, "loadDeepShortcuts");
verifyNotStopped();
- mResults.bindDeepShortcuts();
+ mLauncherBinder.bindDeepShortcuts();
logASplit(logger, "bindDeepShortcuts");
verifyNotStopped();
@@ -290,7 +290,7 @@
logASplit(logger, "load widgets");
verifyNotStopped();
- mResults.bindWidgets();
+ mLauncherBinder.bindWidgets();
logASplit(logger, "bindWidgets");
verifyNotStopped();
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 3e2d051..7ab3013 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -268,8 +268,8 @@
return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;
case ALLOW_ROTATION_PREFERENCE_KEY:
- DisplayController.Info info = InvariantDeviceProfile.INSTANCE.get(
- getContext()).getDeviceProfile(getContext()).getDisplayInfo();
+ DisplayController.Info info =
+ DisplayController.INSTANCE.get(getContext()).getInfo();
if (info.isTablet(info.realBounds)) {
// Launcher supports rotation by default. No need to show this setting.
return false;
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index ad1e7f0..34ac8c2 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -28,6 +28,8 @@
import android.os.Handler;
import android.os.Looper;
+import androidx.annotation.FloatRange;
+
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
@@ -195,6 +197,21 @@
}
}
+ /** Handles backProgress in predictive back gesture by passing it to state handlers. */
+ public void onBackProgressed(
+ STATE_TYPE toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
+ for (StateHandler handler : getStateHandlers()) {
+ handler.onBackProgressed(toState, backProgress);
+ }
+ }
+
+ /** Handles back cancelled event in predictive back gesture by passing it to state handlers. */
+ public void onBackCancelled(STATE_TYPE toState) {
+ for (StateHandler handler : getStateHandlers()) {
+ handler.onBackCancelled(toState);
+ }
+ }
+
private void goToState(
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
animated &= areAnimatorsEnabled();
@@ -586,6 +603,13 @@
*/
void setStateWithAnimation(
STATE_TYPE toState, StateAnimationConfig config, PendingAnimation animation);
+
+ /** Handles backProgress in predictive back gesture for target state. */
+ default void onBackProgressed(
+ STATE_TYPE toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {};
+
+ /** Handles back cancelled event in predictive back gesture for target state. */
+ default void onBackCancelled(STATE_TYPE toState) {};
}
public interface StateListener<STATE_TYPE> {
diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java
index 1deb23d..f5ee91b 100644
--- a/src/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/src/com/android/launcher3/testing/shared/TestProtocol.java
@@ -148,7 +148,6 @@
public static final String NULL_INT_SET = "b/200572078";
public static final String MISSING_PROMISE_ICON = "b/202985412";
public static final String TASKBAR_IN_APP_STATE = "b/227657604";
- public static final String INCORRECT_INFO_UPDATED = "b/239465630";
public static final String NPE_TRANSIENT_TASKBAR = "b/257549303";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index b7e0105..64951ca 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -23,14 +23,14 @@
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller.SessionInfo;
-import android.os.Process;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -66,6 +66,8 @@
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
/**
* Class for handling clicks on workspace and all-apps items
@@ -156,32 +158,18 @@
private static void onClickPendingAppItem(View v, Launcher launcher, String packageName,
boolean downloadStarted) {
- if (downloadStarted) {
- // If the download has started, simply direct to the market app.
- startMarketIntentForPackage(v, launcher, packageName);
- return;
- }
- UserHandle user = v.getTag() instanceof ItemInfo
- ? ((ItemInfo) v.getTag()).user : Process.myUserHandle();
- new AlertDialog.Builder(launcher)
- .setTitle(R.string.abandoned_promises_title)
- .setMessage(R.string.abandoned_promise_explanation)
- .setPositiveButton(R.string.abandoned_search,
- (d, i) -> startMarketIntentForPackage(v, launcher, packageName))
- .setNeutralButton(R.string.abandoned_clean_this,
- (d, i) -> launcher.getWorkspace()
- .persistRemoveItemsByMatcher(ItemInfoMatcher.ofPackages(
- Collections.singleton(packageName), user),
- "user explicitly removes the promise app icon"))
- .create().show();
- }
-
- private static void startMarketIntentForPackage(View v, Launcher launcher, String packageName) {
ItemInfo item = (ItemInfo) v.getTag();
+ CompletableFuture<SessionInfo> siFuture;
if (Utilities.ATLEAST_Q) {
- SessionInfo sessionInfo = InstallSessionHelper.INSTANCE.get(launcher)
- .getActiveSessionInfo(item.user, packageName);
- if (sessionInfo != null) {
+ siFuture = CompletableFuture.supplyAsync(() ->
+ InstallSessionHelper.INSTANCE.get(launcher)
+ .getActiveSessionInfo(item.user, packageName),
+ UI_HELPER_EXECUTOR);
+ } else {
+ siFuture = CompletableFuture.completedFuture(null);
+ }
+ Consumer<SessionInfo> marketLaunchAction = sessionInfo -> {
+ if (sessionInfo != null && Utilities.ATLEAST_Q) {
LauncherApps launcherApps = launcher.getSystemService(LauncherApps.class);
try {
launcherApps.startPackageInstallerSessionDetailsActivity(sessionInfo, null,
@@ -191,11 +179,27 @@
Log.e(TAG, "Unable to launch market intent for package=" + packageName, e);
}
}
- }
+ // Fallback to using custom market intent.
+ Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
+ launcher.startActivitySafely(v, intent, item);
+ };
- // Fallback to using custom market intent.
- Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
- launcher.startActivitySafely(v, intent, item);
+ if (downloadStarted) {
+ // If the download has started, simply direct to the market app.
+ siFuture.thenAcceptAsync(marketLaunchAction, MAIN_EXECUTOR);
+ return;
+ }
+ new AlertDialog.Builder(launcher)
+ .setTitle(R.string.abandoned_promises_title)
+ .setMessage(R.string.abandoned_promise_explanation)
+ .setPositiveButton(R.string.abandoned_search,
+ (d, i) -> siFuture.thenAcceptAsync(marketLaunchAction, MAIN_EXECUTOR))
+ .setNeutralButton(R.string.abandoned_clean_this,
+ (d, i) -> launcher.getWorkspace()
+ .persistRemoveItemsByMatcher(ItemInfoMatcher.ofPackages(
+ Collections.singleton(packageName), item.user),
+ "user explicitly removes the promise app icon"))
+ .create().show();
}
/**
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 758b3a9..1922310 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -24,12 +24,15 @@
object DimensionUtils {
/**
- * Point where x is width, and y is height of taskbar based on provided [deviceProfile]
- * x or y could also be -1 to indicate there is no dimension specified
+ * Point where x is width, and y is height of taskbar based on provided [deviceProfile] x or y
+ * could also be -1 to indicate there is no dimension specified
*/
@JvmStatic
- fun getTaskbarPhoneDimensions(deviceProfile: DeviceProfile, res: Resources,
- isPhoneMode: Boolean): Point {
+ fun getTaskbarPhoneDimensions(
+ deviceProfile: DeviceProfile,
+ res: Resources,
+ isPhoneMode: Boolean
+ ): Point {
val p = Point()
// Taskbar for large screen
if (!isPhoneMode) {
@@ -57,4 +60,4 @@
p.y = ViewGroup.LayoutParams.MATCH_PARENT
return p
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
new file mode 100644
index 0000000..7b49583
--- /dev/null
+++ b/src/com/android/launcher3/util/LockedUserState.kt
@@ -0,0 +1,57 @@
+package com.android.launcher3.util
+
+import android.content.Context
+import android.content.Intent
+import android.os.Process
+import android.os.UserManager
+import androidx.annotation.VisibleForTesting
+
+class LockedUserState(private val mContext: Context) : SafeCloseable {
+ var isUserUnlocked: Boolean
+ private set
+ private val mUserUnlockedActions: RunnableList = RunnableList()
+
+ @VisibleForTesting
+ val mUserUnlockedReceiver = SimpleBroadcastReceiver {
+ if (Intent.ACTION_USER_UNLOCKED == it.action) {
+ isUserUnlocked = true
+ notifyUserUnlocked()
+ }
+ }
+
+ init {
+ isUserUnlocked =
+ mContext
+ .getSystemService(UserManager::class.java)!!
+ .isUserUnlocked(Process.myUserHandle())
+ if (isUserUnlocked) {
+ notifyUserUnlocked()
+ } else {
+ mUserUnlockedReceiver.register(mContext, Intent.ACTION_USER_UNLOCKED)
+ }
+ }
+
+ private fun notifyUserUnlocked() {
+ mUserUnlockedActions.executeAllAndDestroy()
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ }
+
+ /** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */
+ override fun close() {
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ }
+
+ /**
+ * Adds a `Runnable` to be executed when a user is unlocked. If the user is already unlocked,
+ * this runnable will run immediately because RunnableList will already have been destroyed.
+ */
+ fun runOnUserUnlocked(action: Runnable) {
+ mUserUnlockedActions.add(action)
+ }
+
+ companion object {
+ @VisibleForTesting val INSTANCE = MainThreadInitializedObject { LockedUserState(it) }
+
+ @JvmStatic fun get(context: Context): LockedUserState = INSTANCE.get(context)
+ }
+}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 4c0bfde..870ff12 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -46,6 +46,7 @@
private int mBackgroundColor;
private boolean mIsVisible = true;
private boolean mLastDispatchedOpaqueness;
+ private float mHeaderScale = 1f;
public ScrimView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -91,7 +92,16 @@
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawingController != null) {
- mDrawingController.drawOnScrim(canvas);
+ mDrawingController.drawOnScrimWithScale(canvas, mHeaderScale);
+ }
+ }
+
+ /** Set scrim header's scale and bottom offset. */
+ public void setScrimHeaderScale(float scale) {
+ boolean hasChanged = mHeaderScale != scale;
+ mHeaderScale = scale;
+ if (hasChanged) {
+ invalidate();
}
}
@@ -176,6 +186,6 @@
/**
* Called inside ScrimView#OnDraw
*/
- void drawOnScrim(Canvas canvas);
+ void drawOnScrimWithScale(Canvas canvas, float scale);
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 220d1c1..38cdb4b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -169,6 +169,7 @@
private View mSearchBarContainer;
private WidgetsSearchBar mSearchBar;
private TextView mHeaderTitle;
+ private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -642,6 +643,51 @@
return sheet;
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return maybeHandleTouchEvent(ev) || super.onTouchEvent(ev);
+ }
+
+ private boolean maybeHandleTouchEvent(MotionEvent ev) {
+ boolean isEventHandled = false;
+
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mCurrentTouchEventRecyclerView = isTouchOnScrollbar(ev) ? getRecyclerView() : null;
+ }
+
+ if (mCurrentTouchEventRecyclerView != null) {
+ final float offsetX = mContent.getX();
+ final float offsetY = mContent.getY();
+ ev.offsetLocation(-offsetX, -offsetY);
+ isEventHandled = mCurrentTouchEventRecyclerView.dispatchTouchEvent(ev);
+ ev.offsetLocation(offsetX, offsetY);
+ }
+
+ if (ev.getAction() == MotionEvent.ACTION_UP
+ || ev.getAction() == MotionEvent.ACTION_CANCEL) {
+ mCurrentTouchEventRecyclerView = null;
+ }
+
+ return isEventHandled;
+ }
+
+ private boolean isTouchOnScrollbar(MotionEvent ev) {
+ final float offsetX = mContent.getX();
+ final float offsetY = mContent.getY();
+ WidgetsRecyclerView rv = getRecyclerView();
+
+ ev.offsetLocation(-offsetX, -offsetY);
+ boolean isOnScrollBar = rv != null && rv.getScrollbar() != null && rv.isHitOnScrollBar(ev);
+ ev.offsetLocation(offsetX, offsetY);
+
+ return isOnScrollBar;
+ }
+
/** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
@VisibleForTesting
public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 5969e3e..698e764 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -127,8 +127,7 @@
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
- mTouchDownOnScroller =
- mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+ mTouchDownOnScroller = isHitOnScrollBar(e);
}
if (mTouchDownOnScroller) {
final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
@@ -144,6 +143,15 @@
}
}
+ /**
+ * Detects whether a {@code MotionEvent} is on the scroll bar
+ * @param e The {@code MotionEvent} on the screen
+ * @return {@code true} if the motion is on the scroll bar
+ */
+ boolean isHitOnScrollBar(MotionEvent e) {
+ return mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+ }
+
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java b/src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java
similarity index 88%
rename from src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
rename to src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java
index abce2a2..e1a5f24 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java
@@ -27,11 +27,11 @@
import java.util.List;
/**
- * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
*/
-public class LoaderResults extends BaseLoaderResults {
+public class LauncherBinder extends BaseLauncherBinder {
- public LoaderResults(LauncherAppState app, BgDataModel dataModel,
+ public LauncherBinder(LauncherAppState app, BgDataModel dataModel,
AllAppsList allAppsList, Callbacks[] callbacks) {
super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index bedf277..b170061 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -280,7 +280,7 @@
</intent-filter>
</activity-alias>
<activity-alias android:name="Activity15" android:exported="true"
- android:label="ThemeIconTestActivity"
+ android:label="IconThemedActivity"
android:icon="@drawable/test_theme_icon"
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
<intent-filter>
diff --git a/tests/res/xml/shortcuts.xml b/tests/res/xml/shortcuts.xml
index fde0dbb..94e8edd 100644
--- a/tests/res/xml/shortcuts.xml
+++ b/tests/res/xml/shortcuts.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
<shortcut
- android:shortcutId="shortcut1"
+ android:shortcutId="shortcut1_themed"
android:icon="@drawable/test_theme_icon"
android:shortcutShortLabel="@string/shortcut1">
<intent android:action="com.android.launcher3.intent.action.test_shortcut"/>
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index 13e56f3..2da5eee 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -23,11 +23,11 @@
import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER
import com.android.launcher3.util.DisplayController.Info
import com.android.launcher3.util.WindowBounds
+import java.io.PrintWriter
+import java.io.StringWriter
import org.junit.Before
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.mock
-import java.io.PrintWriter
-import java.io.StringWriter
import org.mockito.Mockito.`when` as whenever
abstract class DeviceProfileBaseTest {
@@ -49,31 +49,36 @@
isGestureMode = true
}
- protected fun newDP(): DeviceProfile = DeviceProfile(
- context,
- inv,
- info,
- windowBounds,
- SparseArray(),
- isMultiWindowMode,
- transposeLayoutWithOrientation,
- useTwoPanels,
- isGestureMode,
- DEFAULT_PROVIDER
- )
+ protected fun newDP(): DeviceProfile =
+ DeviceProfile(
+ context,
+ inv,
+ info,
+ windowBounds,
+ SparseArray(),
+ isMultiWindowMode,
+ transposeLayoutWithOrientation,
+ useTwoPanels,
+ isGestureMode,
+ DEFAULT_PROVIDER
+ )
- protected fun initializeVarsForPhone(isGestureMode: Boolean = true,
- isVerticalBar: Boolean = false) {
- val (x, y) = if (isVerticalBar)
- Pair(2400, 1080)
- else
- Pair(1080, 2400)
+ protected fun initializeVarsForPhone(
+ isGestureMode: Boolean = true,
+ isVerticalBar: Boolean = false
+ ) {
+ val (x, y) = if (isVerticalBar) Pair(2400, 1080) else Pair(1080, 2400)
- windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(
- if (isVerticalBar) 118 else 0,
- if (isVerticalBar) 74 else 118,
- if (!isGestureMode && isVerticalBar) 126 else 0,
- if (isGestureMode) 63 else if (isVerticalBar) 0 else 126))
+ windowBounds =
+ WindowBounds(
+ Rect(0, 0, x, y),
+ Rect(
+ if (isVerticalBar) 118 else 0,
+ if (isVerticalBar) 74 else 118,
+ if (!isGestureMode && isVerticalBar) 126 else 0,
+ if (isGestureMode) 63 else if (isVerticalBar) 0 else 126
+ )
+ )
whenever(info.isTablet(any())).thenReturn(false)
whenever(info.getDensityDpi()).thenReturn(420)
@@ -82,79 +87,76 @@
this.isGestureMode = isGestureMode
transposeLayoutWithOrientation = true
- inv = InvariantDeviceProfile().apply {
- numRows = 5
- numColumns = 4
- numSearchContainerColumns = 4
+ inv =
+ InvariantDeviceProfile().apply {
+ numRows = 5
+ numColumns = 4
+ numSearchContainerColumns = 4
- iconSize = floatArrayOf(60f, 54f, 60f, 60f)
- iconTextSize = FloatArray(4) { 14f }
- deviceType = InvariantDeviceProfile.TYPE_PHONE
+ iconSize = floatArrayOf(60f, 54f, 60f, 60f)
+ iconTextSize = FloatArray(4) { 14f }
+ deviceType = InvariantDeviceProfile.TYPE_PHONE
- minCellSize = listOf(
- PointF(80f, 104f),
- PointF(80f, 104f),
- PointF(80f, 104f),
- PointF(80f, 104f)
- ).toTypedArray()
+ minCellSize =
+ listOf(
+ PointF(80f, 104f),
+ PointF(80f, 104f),
+ PointF(80f, 104f),
+ PointF(80f, 104f)
+ )
+ .toTypedArray()
- borderSpaces = listOf(
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 16f)
- ).toTypedArray()
+ borderSpaces =
+ listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
+ .toTypedArray()
- numFolderRows = 3
- numFolderColumns = 3
- folderStyle = R.style.FolderDefaultStyle
+ numFolderRows = 3
+ numFolderColumns = 3
+ folderStyle = R.style.FolderDefaultStyle
- inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
+ inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
- horizontalMargin = FloatArray(4) { 22f }
+ horizontalMargin = FloatArray(4) { 22f }
- allAppsCellSize = listOf(
- PointF(80f, 104f),
- PointF(80f, 104f),
- PointF(80f, 104f),
- PointF(80f, 104f)
- ).toTypedArray()
- allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
- allAppsIconTextSize = FloatArray(4) { 14f }
- allAppsBorderSpaces = listOf(
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 16f)
- ).toTypedArray()
+ allAppsCellSize =
+ listOf(
+ PointF(80f, 104f),
+ PointF(80f, 104f),
+ PointF(80f, 104f),
+ PointF(80f, 104f)
+ )
+ .toTypedArray()
+ allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
+ allAppsIconTextSize = FloatArray(4) { 14f }
+ allAppsBorderSpaces =
+ listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
+ .toTypedArray()
- numShownHotseatIcons = 4
+ numShownHotseatIcons = 4
- numDatabaseHotseatIcons = 4
+ numDatabaseHotseatIcons = 4
- hotseatColumnSpan = IntArray(4) { 4 }
- hotseatBarBottomSpace = FloatArray(4) { 48f }
- hotseatQsbSpace = FloatArray(4) { 36f }
+ hotseatColumnSpan = IntArray(4) { 4 }
+ hotseatBarBottomSpace = FloatArray(4) { 48f }
+ hotseatQsbSpace = FloatArray(4) { 36f }
- numAllAppsColumns = 4
+ numAllAppsColumns = 4
- isScalable = true
+ isScalable = true
- inlineQsb = BooleanArray(4) { false }
+ inlineQsb = BooleanArray(4) { false }
- devicePaddingId = R.xml.paddings_handhelds
- }
+ devicePaddingId = R.xml.paddings_handhelds
+ }
}
- protected fun initializeVarsForTablet(isLandscape: Boolean = false,
- isGestureMode: Boolean = true) {
- val (x, y) = if (isLandscape)
- Pair(2560, 1600)
- else
- Pair(1600, 2560)
+ protected fun initializeVarsForTablet(
+ isLandscape: Boolean = false,
+ isGestureMode: Boolean = true
+ ) {
+ val (x, y) = if (isLandscape) Pair(2560, 1600) else Pair(1600, 2560)
- windowBounds =
- WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
+ windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
whenever(info.isTablet(any())).thenReturn(true)
whenever(info.getDensityDpi()).thenReturn(320)
@@ -163,85 +165,77 @@
this.isGestureMode = isGestureMode
useTwoPanels = false
- inv = InvariantDeviceProfile().apply {
- numRows = 5
- numColumns = 6
- numSearchContainerColumns = 3
+ inv =
+ InvariantDeviceProfile().apply {
+ numRows = 5
+ numColumns = 6
+ numSearchContainerColumns = 3
- iconSize = FloatArray(4) { 60f }
- iconTextSize = FloatArray(4) { 14f }
- deviceType = InvariantDeviceProfile.TYPE_TABLET
+ iconSize = FloatArray(4) { 60f }
+ iconTextSize = FloatArray(4) { 14f }
+ deviceType = InvariantDeviceProfile.TYPE_TABLET
- minCellSize = listOf(
- PointF(102f, 120f),
- PointF(120f, 104f),
- PointF(102f, 120f),
- PointF(102f, 120f)
- ).toTypedArray()
+ minCellSize =
+ listOf(
+ PointF(102f, 120f),
+ PointF(120f, 104f),
+ PointF(102f, 120f),
+ PointF(102f, 120f)
+ )
+ .toTypedArray()
- borderSpaces = listOf(
- PointF(16f, 64f),
- PointF(64f, 16f),
- PointF(16f, 64f),
- PointF(16f, 64f)
- ).toTypedArray()
+ borderSpaces =
+ listOf(PointF(16f, 64f), PointF(64f, 16f), PointF(16f, 64f), PointF(16f, 64f))
+ .toTypedArray()
- numFolderRows = 3
- numFolderColumns = 3
- folderStyle = R.style.FolderDefaultStyle
+ numFolderRows = 3
+ numFolderColumns = 3
+ folderStyle = R.style.FolderDefaultStyle
- inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
+ inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
- horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
+ horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
- allAppsCellSize = listOf(
- PointF(96f, 142f),
- PointF(126f, 126f),
- PointF(96f, 142f),
- PointF(96f, 142f)
- ).toTypedArray()
- allAppsIconSize = FloatArray(4) { 60f }
- allAppsIconTextSize = FloatArray(4) { 14f }
- allAppsBorderSpaces = listOf(
- PointF(8f, 16f),
- PointF(16f, 16f),
- PointF(8f, 16f),
- PointF(8f, 16f)
- ).toTypedArray()
+ allAppsCellSize =
+ listOf(
+ PointF(96f, 142f),
+ PointF(126f, 126f),
+ PointF(96f, 142f),
+ PointF(96f, 142f)
+ )
+ .toTypedArray()
+ allAppsIconSize = FloatArray(4) { 60f }
+ allAppsIconTextSize = FloatArray(4) { 14f }
+ allAppsBorderSpaces =
+ listOf(PointF(8f, 16f), PointF(16f, 16f), PointF(8f, 16f), PointF(8f, 16f))
+ .toTypedArray()
- numShownHotseatIcons = 6
+ numShownHotseatIcons = 6
- numDatabaseHotseatIcons = 6
+ numDatabaseHotseatIcons = 6
- hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
- hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
- hotseatQsbSpace = FloatArray(4) { 32f }
+ hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
+ hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
+ hotseatQsbSpace = FloatArray(4) { 32f }
- numAllAppsColumns = 6
+ numAllAppsColumns = 6
- isScalable = true
- devicePaddingId = R.xml.paddings_6x5
+ isScalable = true
+ devicePaddingId = R.xml.paddings_6x5
- inlineQsb = booleanArrayOf(
- false,
- true,
- false,
- false
- )
+ inlineQsb = booleanArrayOf(false, true, false, false)
- devicePaddingId = R.xml.paddings_handhelds
- }
+ devicePaddingId = R.xml.paddings_handhelds
+ }
}
- protected fun initializeVarsForTwoPanel(isLandscape: Boolean = false,
- isGestureMode: Boolean = true) {
- val (x, y) = if (isLandscape)
- Pair(2208, 1840)
- else
- Pair(1840, 2208)
+ protected fun initializeVarsForTwoPanel(
+ isLandscape: Boolean = false,
+ isGestureMode: Boolean = true
+ ) {
+ val (x, y) = if (isLandscape) Pair(2208, 1840) else Pair(1840, 2208)
- windowBounds = WindowBounds(Rect(0, 0, x, y),
- Rect(0, 110, 0, 0))
+ windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 110, 0, 0))
whenever(info.isTablet(any())).thenReturn(true)
whenever(info.getDensityDpi()).thenReturn(420)
@@ -250,74 +244,63 @@
this.isGestureMode = isGestureMode
useTwoPanels = true
- inv = InvariantDeviceProfile().apply {
- numRows = 4
- numColumns = 4
- numSearchContainerColumns = 4
+ inv =
+ InvariantDeviceProfile().apply {
+ numRows = 4
+ numColumns = 4
+ numSearchContainerColumns = 4
- iconSize = floatArrayOf(60f, 52f, 52f, 60f)
- iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
- deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
+ iconSize = floatArrayOf(60f, 52f, 52f, 60f)
+ iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
+ deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
- minCellSize = listOf(
- PointF(80f, 104f),
- PointF(80f, 104f),
- PointF(68f, 116f),
- PointF(80f, 102f)
- ).toTypedArray()
+ minCellSize =
+ listOf(
+ PointF(80f, 104f),
+ PointF(80f, 104f),
+ PointF(68f, 116f),
+ PointF(80f, 102f)
+ )
+ .toTypedArray()
- borderSpaces = listOf(
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 20f),
- PointF(20f, 20f)
- ).toTypedArray()
+ borderSpaces =
+ listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 20f), PointF(20f, 20f))
+ .toTypedArray()
- numFolderRows = 3
- numFolderColumns = 3
- folderStyle = R.style.FolderDefaultStyle
+ numFolderRows = 3
+ numFolderColumns = 3
+ folderStyle = R.style.FolderDefaultStyle
- inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
+ inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
- horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
+ horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
- allAppsCellSize = listOf(
- PointF(0f, 0f),
- PointF(0f, 0f),
- PointF(68f, 104f),
- PointF(80f, 104f)
- ).toTypedArray()
- allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
- allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
- allAppsBorderSpaces = listOf(
- PointF(16f, 16f),
- PointF(16f, 16f),
- PointF(16f, 28f),
- PointF(20f, 16f)
- ).toTypedArray()
+ allAppsCellSize =
+ listOf(PointF(0f, 0f), PointF(0f, 0f), PointF(68f, 104f), PointF(80f, 104f))
+ .toTypedArray()
+ allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
+ allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
+ allAppsBorderSpaces =
+ listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 28f), PointF(20f, 16f))
+ .toTypedArray()
- numShownHotseatIcons = 6
+ numShownHotseatIcons = 6
- numDatabaseHotseatIcons = 6
+ numDatabaseHotseatIcons = 6
- hotseatColumnSpan = IntArray(4) { 6 }
- hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
- hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
+ hotseatColumnSpan = IntArray(4) { 6 }
+ hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
+ hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
- numAllAppsColumns = 6
- numDatabaseAllAppsColumns = 6
+ numAllAppsColumns = 6
+ numDatabaseAllAppsColumns = 6
- isScalable = true
+ isScalable = true
- inlineQsb = booleanArrayOf(
- false,
- false,
- false,
- false
- )
+ inlineQsb = booleanArrayOf(false, false, false, false)
- devicePaddingId = R.xml.paddings_handhelds
- }
+ devicePaddingId = R.xml.paddings_handhelds
+ }
}
fun dump(dp: DeviceProfile): String {
@@ -327,4 +310,4 @@
printWriter.flush()
return stringWriter.toString()
}
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
index a32ce3c..469d79f 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
@@ -26,6 +26,7 @@
import java.util.Map;
import java.util.Queue;
import java.util.Set;
+import java.util.stream.Collectors;
public class CellLayoutBoard {
@@ -140,6 +141,73 @@
return mWidgetsMap.get(c);
}
+ private void removeWidgetFromBoard(WidgetRect widget) {
+ for (int xi = widget.mBounds.left; xi < widget.mBounds.right; xi++) {
+ for (int yi = widget.mBounds.top; yi < widget.mBounds.bottom; yi++) {
+ mWidget[xi][yi] = '-';
+ }
+ }
+ }
+
+ private void removeOverlappingItems(Rect rect) {
+ // Remove overlapping widgets and remove them from the board
+ mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
+ if (rect.intersect(widget.mBounds)) {
+ removeWidgetFromBoard(widget);
+ return false;
+ }
+ return true;
+ }).collect(Collectors.toList());
+ // Remove overlapping icons and remove them from the board
+ mIconPoints = mIconPoints.stream().filter(iconPoint -> {
+ int x = iconPoint.coord.x;
+ int y = iconPoint.coord.y;
+ if (rect.contains(x, y)) {
+ mWidget[x][y] = '-';
+ return false;
+ }
+ return true;
+ }).collect(Collectors.toList());
+ }
+
+ private void removeOverlappingItems(Point p) {
+ // Remove overlapping widgets and remove them from the board
+ mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
+ if (widget.mBounds.contains(p.x, p.y)) {
+ removeWidgetFromBoard(widget);
+ return false;
+ }
+ return true;
+ }).collect(Collectors.toList());
+ // Remove overlapping icons and remove them from the board
+ mIconPoints = mIconPoints.stream().filter(iconPoint -> {
+ int x = iconPoint.coord.x;
+ int y = iconPoint.coord.y;
+ if (p.x == x && p.y == y) {
+ mWidget[x][y] = '-';
+ return false;
+ }
+ return true;
+ }).collect(Collectors.toList());
+ }
+
+ public void addWidget(int x, int y, int spanX, int spanY, char type) {
+ Rect rect = new Rect(x, y + spanY - 1, x + spanX - 1, y);
+ removeOverlappingItems(rect);
+ WidgetRect widgetRect = new WidgetRect(type, rect);
+ mWidgetsRects.add(widgetRect);
+ for (int xi = rect.left; xi < rect.right + 1; xi++) {
+ for (int yi = rect.bottom; yi < rect.top + 1; yi++) {
+ mWidget[xi][yi] = type;
+ }
+ }
+ }
+
+ public void addIcon(int x, int y) {
+ removeOverlappingItems(new Point(x, y));
+ mWidget[x][y] = 'i';
+ }
+
public static WidgetRect getWidgetRect(int x, int y, Set<Point> used, char[][] board) {
char type = board[x][y];
Queue<Point> search = new ArrayDeque<Point>();
@@ -227,4 +295,17 @@
board.mIconPoints = getIconPoints(board.mWidget);
return board;
}
+
+ public String toString(int maxX, int maxY) {
+ StringBuilder s = new StringBuilder();
+ maxX = Math.min(maxX, mWidget.length);
+ maxY = Math.min(maxY, mWidget[0].length);
+ for (int y = 0; y < maxY; y++) {
+ for (int x = 0; x < maxX; x++) {
+ s.append(mWidget[x][y]);
+ }
+ s.append('\n');
+ }
+ return s.toString();
+ }
}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 9da7e0f..843f011 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -26,6 +26,7 @@
import androidx.test.filters.SmallTest;
import com.android.launcher3.CellLayout;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.celllayout.testcases.FullReorderCase;
import com.android.launcher3.celllayout.testcases.MoveOutReorderCase;
import com.android.launcher3.celllayout.testcases.PushReorderCase;
@@ -46,6 +47,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -108,6 +110,42 @@
return match;
}
+ private void printCurrentWorkspace() {
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
+ ArrayList<CellLayoutBoard> boards = workspaceToBoards();
+ for (int i = 0; i < boards.size(); i++) {
+ Log.d(TAG, "Screen number " + i);
+ Log.d(TAG, ".\n" + boards.get(i).toString(idp.numColumns, idp.numRows));
+ }
+ }
+
+ private ArrayList<CellLayoutBoard> workspaceToBoards() {
+ return getFromLauncher(l -> {
+ ArrayList<CellLayoutBoard> boards = new ArrayList<>();
+ int widgetCount = 0;
+ for (CellLayout cellLayout : l.getWorkspace().mWorkspaceScreens) {
+ CellLayoutBoard board = new CellLayoutBoard();
+ int count = cellLayout.getShortcutsAndWidgets().getChildCount();
+ for (int i = 0; i < count; i++) {
+ View callView = cellLayout.getShortcutsAndWidgets().getChildAt(i);
+ CellLayoutLayoutParams params =
+ (CellLayoutLayoutParams) callView.getLayoutParams();
+ // is icon
+ if (callView instanceof DoubleShadowBubbleTextView) {
+ board.addIcon(params.cellX, params.cellY);
+ } else {
+ // is widget
+ board.addWidget(params.cellX, params.cellY, params.cellHSpan,
+ params.cellVSpan, (char) ('A' + widgetCount));
+ widgetCount++;
+ }
+ }
+ boards.add(board);
+ }
+ return boards;
+ });
+ }
+
private void runTestCase(ReorderTestCase testCase)
throws ExecutionException, InterruptedException {
Point mainWidgetCellPos = testCase.mStart.getMain();
@@ -127,6 +165,7 @@
for (CellLayoutBoard board : testCase.mEnd) {
isValid |= validateBoard(board);
}
+ printCurrentWorkspace();
assertTrue("Non of the valid boards match with the current state", isValid);
}
diff --git a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
index d26381d..03352fe 100644
--- a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
+++ b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
@@ -30,9 +30,7 @@
import com.android.launcher3.util.LauncherModelHelper
import java.util.UUID
-/**
- * Base class for workspace related tests.
- */
+/** Base class for workspace related tests. */
abstract class AbstractWorkspaceModelTest {
companion object {
val emptyScreenSpaces = listOf(Rect(0, 0, 5, 5))
@@ -64,10 +62,7 @@
mModelHelper.destroy()
}
-
- /**
- * Sets up workspaces with the given screen IDs with some items and a 2x2 space.
- */
+ /** Sets up workspaces with the given screen IDs with some items and a 2x2 space. */
fun setupWorkspaces(screenIdsWithItems: List<Int>) {
var nextItemId = 1
screenIdsWithItems.forEach { screenId ->
@@ -83,8 +78,7 @@
screen1: List<Rect>? = null,
screen2: List<Rect>? = null,
screen3: List<Rect>? = null,
- ) = listOf(screen0, screen1, screen2, screen3)
- .let(this::setupWithSpaces)
+ ) = listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces)
private fun setupWithSpaces(workspaceSpaces: List<List<Rect>?>) {
var nextItemId = 1
@@ -110,9 +104,7 @@
var itemId = itemStartId
val occupancy = GridOccupancy(mIdp.numColumns, mIdp.numRows)
occupancy.markCells(0, 0, mIdp.numColumns, mIdp.numRows, true)
- spaces.forEach { spaceRect ->
- occupancy.markCells(spaceRect, false)
- }
+ spaces.forEach { spaceRect -> occupancy.markCells(spaceRect, false) }
mExistingScreens.add(screenId)
mScreenOccupancy.append(screenId, occupancy)
for (x in 0 until mIdp.numColumns) {
@@ -139,24 +131,21 @@
return itemId
}
- fun getExistingItem() = WorkspaceItemInfo()
- .apply { intent = Intent().setComponent(ComponentName("a", "b")) }
+ fun getExistingItem() =
+ WorkspaceItemInfo().apply { intent = Intent().setComponent(ComponentName("a", "b")) }
fun getNewItem(): WorkspaceItemInfo {
val itemPackage = UUID.randomUUID().toString()
- return WorkspaceItemInfo()
- .apply { intent = Intent().setComponent(ComponentName(itemPackage, itemPackage)) }
+ return WorkspaceItemInfo().apply {
+ intent = Intent().setComponent(ComponentName(itemPackage, itemPackage))
+ }
}
}
-data class NewItemSpace(
- val screenId: Int,
- val cellX: Int,
- val cellY: Int
-) {
+data class NewItemSpace(val screenId: Int, val cellX: Int, val cellY: Int) {
fun toIntArray() = intArrayOf(screenId, cellX, cellY)
companion object {
fun fromIntArray(array: kotlin.IntArray) = NewItemSpace(array[0], array[1], array[2])
}
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 65d938b..749ffcf 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -23,9 +23,9 @@
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.Executors
import com.android.launcher3.util.IntArray
-import com.android.launcher3.util.same
-import com.android.launcher3.util.eq
import com.android.launcher3.util.any
+import com.android.launcher3.util.eq
+import com.android.launcher3.util.same
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -34,31 +34,24 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.times
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
-/**
- * Tests for [AddWorkspaceItemsTask]
- */
+/** Tests for [AddWorkspaceItemsTask] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
- @Captor
- private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
+ @Captor private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
- @Captor
- private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
+ @Captor private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
- @Mock
- private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
+ @Mock private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
- @Mock
- private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
-
+ @Mock private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
@Before
override fun setup() {
@@ -89,10 +82,7 @@
@Test
fun givenNewAndExistingItems_whenExecuteTask_thenOnlyAddNewItem() {
- val itemsToAdd = arrayOf(
- getNewItem(),
- getExistingItem()
- )
+ val itemsToAdd = arrayOf(getNewItem(), getExistingItem())
givenNewItemSpaces(NewItemSpace(1, 0, 0))
val nonEmptyScreenIds = listOf(0)
@@ -132,13 +122,14 @@
@Test
fun givenMultipleItems_whenExecuteTask_thenAddThem() {
- val itemsToAdd = arrayOf(
- getNewItem(),
- getExistingItem(),
- getNewItem(),
- getNewItem(),
- getExistingItem(),
- )
+ val itemsToAdd =
+ arrayOf(
+ getNewItem(),
+ getExistingItem(),
+ getNewItem(),
+ getNewItem(),
+ getExistingItem(),
+ )
givenNewItemSpaces(
NewItemSpace(1, 3, 3),
NewItemSpace(2, 0, 0),
@@ -159,27 +150,16 @@
// Items that are added to the second screen should be animated
val itemsAddedToSecondScreen = addedItems.filter { it.itemInfo.screenId == 2 }
assertThat(itemsAddedToSecondScreen.size).isEqualTo(2)
- itemsAddedToSecondScreen.forEach {
- assertThat(it.isAnimated).isTrue()
- }
+ itemsAddedToSecondScreen.forEach { assertThat(it.isAnimated).isTrue() }
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 3)
}
- /**
- * Sets up the item space data that will be returned from WorkspaceItemSpaceFinder.
- */
+ /** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */
private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) {
val spaceStack = newItemSpaces.toMutableList()
whenever(
- mWorkspaceItemSpaceFinder.findSpaceForItem(
- any(),
- any(),
- any(),
- any(),
- any(),
- any()
+ mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any(), any(), any())
)
- )
.then { spaceStack.removeFirst().toIntArray() }
}
@@ -187,20 +167,21 @@
* Verifies if WorkspaceItemSpaceFinder was called with proper arguments and how many times was
* it called.
*/
- private fun verifyItemSpaceFinderCall(
- nonEmptyScreenIds: List<Int>,
- numberOfExpectedCall: Int
- ) {
+ private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
.findSpaceForItem(
- same(mAppState), same(mModelHelper.bgDataModel),
- eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())), eq(IntArray()), eq(1), eq(1)
+ same(mAppState),
+ same(mModelHelper.bgDataModel),
+ eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
+ eq(IntArray()),
+ eq(1),
+ eq(1)
)
}
/**
- * Sets up the workspaces with items, executes the task, collects the added items from the
- * model callback then returns it.
+ * Sets up the workspaces with items, executes the task, collects the added items from the model
+ * callback then returns it.
*/
private fun testAddItems(
nonEmptyScreenIds: List<Int>,
@@ -209,21 +190,21 @@
setupWorkspaces(nonEmptyScreenIds)
val task = newTask(*itemsToAdd)
var updateCount = 0
- mModelHelper.executeTaskForTest(task)
- .forEach {
- updateCount++
- it.run()
- }
+ mModelHelper.executeTaskForTest(task).forEach {
+ updateCount++
+ it.run()
+ }
val addedItems = mutableListOf<AddedItem>()
if (updateCount > 0) {
- verify(mDataModelCallbacks).bindAppsAdded(
- any(),
- mNotAnimatedItemArgumentCaptor.capture(), mAnimatedItemArgumentCaptor.capture()
- )
+ verify(mDataModelCallbacks)
+ .bindAppsAdded(
+ any(),
+ mNotAnimatedItemArgumentCaptor.capture(),
+ mAnimatedItemArgumentCaptor.capture()
+ )
addedItems.addAll(mAnimatedItemArgumentCaptor.value.map { AddedItem(it, true) })
addedItems.addAll(mNotAnimatedItemArgumentCaptor.value.map { AddedItem(it, false) })
-
}
return addedItems
@@ -234,12 +215,10 @@
* with a mock.
*/
private fun newTask(vararg items: ItemInfo): AddWorkspaceItemsTask =
- items.map { Pair.create(it, Any()) }
+ items
+ .map { Pair.create(it, Any()) }
.toMutableList()
.let { AddWorkspaceItemsTask(it, mWorkspaceItemSpaceFinder) }
}
-private data class AddedItem(
- val itemInfo: ItemInfo,
- val isAnimated: Boolean
-)
+private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 7d36740..f55b244 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,7 +1,5 @@
package com.android.launcher3.model;
-import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
@@ -16,7 +14,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -29,7 +26,6 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.LauncherModelHelper;
import org.junit.After;
@@ -47,15 +43,12 @@
@RunWith(AndroidJUnit4.class)
public class CacheDataUpdatedTaskTest {
- private static final String TAG = "CacheDataUpdatedTaskTest";
-
private static final String NEW_LABEL_PREFIX = "new-label-";
private LauncherModelHelper mModelHelper;
@Before
public void setup() throws Exception {
- TestProtocol.sDebugTracing = true;
mModelHelper = new LauncherModelHelper();
mModelHelper.initializeData("cache_data_updated_task_data");
@@ -98,7 +91,6 @@
@After
public void tearDown() {
mModelHelper.destroy();
- TestProtocol.sDebugTracing = false;
}
private CacheDataUpdatedTask newTask(int op, String... pkg) {
@@ -122,7 +114,6 @@
// Verify that only app1 var updated in allAppsList
assertFalse(mModelHelper.getAllAppsList().data.isEmpty());
for (AppInfo info : mModelHelper.getAllAppsList().data) {
- Log.i(INCORRECT_INFO_UPDATED, "testCacheUpdate_update_apps: checking info=" + info);
if (info.componentName.getPackageName().equals("app1")) {
assertFalse(info.bitmap.isNullOrLowRes());
} else {
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 76a186b..dcc8ec7 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -17,7 +17,7 @@
import android.content.Context
import android.content.Intent
-import android.database.Cursor;
+import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import android.os.Process
@@ -38,7 +38,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-/** Unit tests for [GridSizeMigrationUtil] */
+/** Unit tests for [GridSizeMigrationUtil] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class GridSizeMigrationUtilTest {
@@ -64,19 +64,20 @@
context = modelHelper.sandboxContext
db = modelHelper.provider.db
- validPackages = setOf(
- TEST_PACKAGE,
- testPackage1,
- testPackage2,
- testPackage3,
- testPackage4,
- testPackage5,
- testPackage6,
- testPackage7,
- testPackage8,
- testPackage9,
- testPackage10
- )
+ validPackages =
+ setOf(
+ TEST_PACKAGE,
+ testPackage1,
+ testPackage2,
+ testPackage3,
+ testPackage4,
+ testPackage5,
+ testPackage6,
+ testPackage7,
+ testPackage8,
+ testPackage9,
+ testPackage10
+ )
idp = InvariantDeviceProfile.INSTANCE[context]
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
@@ -90,8 +91,8 @@
}
/**
- * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
- * not needed anymore
+ * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
+ * needed anymore
*/
@Test
@Throws(Exception::class)
@@ -124,25 +125,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Check hotseat items
- var c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(SCREEN, INTENT),
- "container=$CONTAINER_HOTSEAT",
- null,
- SCREEN,
- null
- ) ?: throw IllegalStateException()
+ var c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(SCREEN, INTENT),
+ "container=$CONTAINER_HOTSEAT",
+ null,
+ SCREEN,
+ null
+ )
+ ?: throw IllegalStateException()
assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
@@ -163,14 +166,16 @@
c.close()
// Check workspace items
- c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(CELLX, CELLY, INTENT),
- "container=$CONTAINER_DESKTOP",
- null,
- null,
- null
- ) ?: throw IllegalStateException()
+ c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(CELLX, CELLY, INTENT),
+ "container=$CONTAINER_DESKTOP",
+ null,
+ null,
+ null
+ )
+ ?: throw IllegalStateException()
intentIndex = c.getColumnIndex(INTENT)
val cellXIndex = c.getColumnIndex(CELLX)
@@ -195,8 +200,8 @@
}
/**
- * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
- * not needed anymore
+ * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
+ * needed anymore
*/
@Test
@Throws(Exception::class)
@@ -235,39 +240,46 @@
val readerGridB = DbReader(db, TABLE_NAME, context, validPackages)
// migrate from A -> B
GridSizeMigrationUtil.migrate(
- context,
- db,
- readerGridA,
- readerGridB,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ readerGridA,
+ readerGridB,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Check hotseat items in grid B
- var c = context.contentResolver.query(
+ var c =
+ context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
- verifyHotseat(c, idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
+ verifyHotseat(
+ c,
+ idp,
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ )
// Check workspace items in grid B
- c = context.contentResolver.query(
+ c =
+ context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
var locMap = parseLocMap(context, c)
// Expected items in grid B
// _ _ _ _
@@ -285,38 +297,45 @@
// migrate from B -> A
GridSizeMigrationUtil.migrate(
- context,
- db,
- readerGridB,
- readerGridA,
- 5,
- Point(5, 5),
- DeviceGridState(idp),
- DeviceGridState(context)
+ context,
+ db,
+ readerGridB,
+ readerGridA,
+ 5,
+ Point(5, 5),
+ DeviceGridState(idp),
+ DeviceGridState(context)
)
// Check hotseat items in grid A
- c = context.contentResolver.query(
+ c =
+ context.contentResolver.query(
TMP_CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
// Expected hotseat items in grid A
// 1 2 _ 3 4
- verifyHotseat(c, idp, mutableListOf(
- testPackage1, testPackage2, null, testPackage3, testPackage4).toList())
+ verifyHotseat(
+ c,
+ idp,
+ mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList()
+ )
// Check workspace items in grid A
- c = context.contentResolver.query(
+ c =
+ context.contentResolver.query(
TMP_CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
locMap = parseLocMap(context, c)
// Expected workspace items in grid A
// _ _ _ _ _
@@ -338,39 +357,46 @@
// migrate from A -> B
GridSizeMigrationUtil.migrate(
- context,
- db,
- readerGridA,
- readerGridB,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ readerGridA,
+ readerGridB,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Check hotseat items in grid B
- c = context.contentResolver.query(
+ c =
+ context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
- verifyHotseat(c, idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
+ verifyHotseat(
+ c,
+ idp,
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ )
// Check workspace items in grid B
- c = context.contentResolver.query(
+ c =
+ context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
- ) ?: throw IllegalStateException()
+ )
+ ?: throw IllegalStateException()
locMap = parseLocMap(context, c)
// Expected workspace items in grid B
// _ _ _ _
@@ -406,7 +432,7 @@
val locMap = mutableMapOf<String, Triple<Int, Int, Int>>()
while (c.moveToNext()) {
locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
- Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
+ Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
}
c.close()
return locMap.toMap()
@@ -414,12 +440,13 @@
@Test
fun migrateToLargerHotseat() {
- val srcHotseatItems = intArrayOf(
- modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
- modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
- modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
- modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
- )
+ val srcHotseatItems =
+ intArrayOf(
+ modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
+ modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
+ modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
+ modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
+ )
val numSrcDatabaseHotseatIcons = srcHotseatItems.size
idp.numDatabaseHotseatIcons = 6
idp.numColumns = 4
@@ -427,25 +454,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Check hotseat items
- val c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(SCREEN, INTENT),
- "container=$CONTAINER_HOTSEAT",
- null,
- SCREEN,
- null
- ) ?: throw IllegalStateException()
+ val c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(SCREEN, INTENT),
+ "container=$CONTAINER_HOTSEAT",
+ null,
+ SCREEN,
+ null
+ )
+ ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(numSrcDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -483,25 +512,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Check hotseat items
- val c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(SCREEN, INTENT),
- "container=$CONTAINER_HOTSEAT",
- null,
- SCREEN,
- null
- ) ?: throw IllegalStateException()
+ val c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(SCREEN, INTENT),
+ "container=$CONTAINER_HOTSEAT",
+ null,
+ SCREEN,
+ null
+ )
+ ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(idp.numDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -527,8 +558,8 @@
}
/**
- * Migrating from a smaller grid to a large one should keep the pages
- * if the column difference is less than 2
+ * Migrating from a smaller grid to a large one should keep the pages if the column difference
+ * is less than 2
*/
@Test
@Throws(Exception::class)
@@ -549,25 +580,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Get workspace items
- val c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(INTENT, SCREEN),
- "container=$CONTAINER_DESKTOP",
- null,
- null,
- null
- ) ?: throw IllegalStateException()
+ val c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(INTENT, SCREEN),
+ "container=$CONTAINER_DESKTOP",
+ null,
+ null,
+ null
+ )
+ ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -589,8 +622,8 @@
}
/**
- * Migrating from a smaller grid to a large one should reflow the pages
- * if the column difference is more than 2
+ * Migrating from a smaller grid to a large one should reflow the pages if the column difference
+ * is more than 2
*/
@Test
@Throws(Exception::class)
@@ -610,25 +643,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Get workspace items
- val c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(INTENT, SCREEN),
- "container=$CONTAINER_DESKTOP",
- null,
- null,
- null
- ) ?: throw IllegalStateException()
+ val c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(INTENT, SCREEN),
+ "container=$CONTAINER_DESKTOP",
+ null,
+ null,
+ null
+ )
+ ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -651,9 +686,7 @@
disableNewMigrationLogic()
}
- /**
- * Migrating from a larger grid to a smaller, we reflow from page 0
- */
+ /** Migrating from a larger grid to a smaller, we reflow from page 0 */
@Test
@Throws(Exception::class)
fun migrateFromLargerGrid() {
@@ -672,25 +705,27 @@
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
- context,
- db,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
+ context,
+ db,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp)
)
// Get workspace items
- val c = context.contentResolver.query(
- CONTENT_URI,
- arrayOf(INTENT, SCREEN),
- "container=$CONTAINER_DESKTOP",
- null,
- null,
- null
- ) ?: throw IllegalStateException()
+ val c =
+ context.contentResolver.query(
+ CONTENT_URI,
+ arrayOf(INTENT, SCREEN),
+ "container=$CONTAINER_DESKTOP",
+ null,
+ null,
+ null
+ )
+ ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -714,11 +749,13 @@
}
private fun enableNewMigrationLogic(srcGridSize: String) {
- context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ context
+ .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, true)
.commit()
- context.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
+ context
+ .getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
.edit()
.putString(DeviceGridState.KEY_WORKSPACE_SIZE, srcGridSize)
.commit()
@@ -726,9 +763,10 @@
}
private fun disableNewMigrationLogic() {
- context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ context
+ .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, false)
.commit()
}
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index bfb1ac6..b3d02be 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -24,9 +24,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * Tests for [WorkspaceItemSpaceFinder]
- */
+/** Tests for [WorkspaceItemSpaceFinder] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
@@ -44,17 +42,27 @@
}
private fun findSpace(spanX: Int, spanY: Int): NewItemSpace =
- mItemSpaceFinder.findSpaceForItem(
- mAppState, mModelHelper.bgDataModel,
- mExistingScreens, mNewScreens, spanX, spanY
- )
+ mItemSpaceFinder
+ .findSpaceForItem(
+ mAppState,
+ mModelHelper.bgDataModel,
+ mExistingScreens,
+ mNewScreens,
+ spanX,
+ spanY
+ )
.let { NewItemSpace.fromIntArray(it) }
private fun assertRegionVacant(newItemSpace: NewItemSpace, spanX: Int, spanY: Int) {
assertThat(
- mScreenOccupancy[newItemSpace.screenId]
- .isRegionVacant(newItemSpace.cellX, newItemSpace.cellY, spanX, spanY)
- ).isTrue()
+ mScreenOccupancy[newItemSpace.screenId].isRegionVacant(
+ newItemSpace.cellX,
+ newItemSpace.cellY,
+ spanX,
+ spanY
+ )
+ )
+ .isTrue()
}
@Test
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index c99ad76..951f5f8 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -29,8 +29,8 @@
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
/**
- * This is a case when after setting the hotseat, the space needs to be recalculated
- * but it doesn't need to change QSB width or remove icons
+ * This is a case when after setting the hotseat, the space needs to be recalculated but it
+ * doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_portrait() {
@@ -51,8 +51,8 @@
}
/**
- * This is a case when after setting the hotseat, and recalculating spaces
- * it still needs to remove icons for everything to fit
+ * This is a case when after setting the hotseat, and recalculating spaces it still needs to
+ * remove icons for everything to fit
*/
@Test
fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -73,8 +73,8 @@
}
/**
- * This is a case when after setting the hotseat, the space needs to be recalculated
- * but it doesn't need to change QSB width or remove icons
+ * This is a case when after setting the hotseat, the space needs to be recalculated but it
+ * doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_landscape() {
@@ -94,8 +94,8 @@
}
/**
- * This is a case when the hotseat spans a certain amount of columns
- * and the nav buttons push the hotseat to the side, but not enough to change the border space.
+ * This is a case when the hotseat spans a certain amount of columns and the nav buttons push
+ * the hotseat to the side, but not enough to change the border space.
*/
@Test
fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -118,9 +118,7 @@
assertThat(dp.hotseatQsbWidth).isEqualTo(1224)
}
- /**
- * This is a case when after setting the hotseat, the QSB width needs to be changed to fit
- */
+ /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@Test
fun decrease_qsb_when_not_enough_space_landscape() {
initializeVarsForTablet(isGestureMode = false, isLandscape = true)
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 302bd2f..c7628cc 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -38,6 +38,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.Objects;
@@ -118,6 +119,7 @@
}
@Test
+ @Ignore("b/243855320")
public void toggleWorks() {
assumeTrue(mWorkProfileSetupSuccessful);
waitForWorkTabSetup();
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 3f4a1c1..2c9785c 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -37,7 +37,6 @@
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,7 +64,6 @@
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
}
- @Ignore
@Test
@PortraitLandscape
public void testWidgetConfig() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 0db719e..9669010 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -147,7 +147,8 @@
// Set callback
PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0,
- new Intent(mCallbackAction), FLAG_ONE_SHOT | FLAG_MUTABLE);
+ new Intent(mCallbackAction).setPackage(mTargetContext.getPackageName()),
+ FLAG_ONE_SHOT | FLAG_MUTABLE);
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, "setCallback").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", callback));
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index 9d5763b..7ba0b53 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -36,9 +36,7 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.Executors;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayDeque;
@@ -52,7 +50,7 @@
@LargeTest
public class ThemeIconsTest extends AbstractLauncherUiTest {
- private static final String APP_NAME = "ThemeIconTestActivity";
+ private static final String APP_NAME = "IconThemedActivity";
private static final String SHORTCUT_APP_NAME = "LauncherTestApp";
private static final String SHORTCUT_NAME = "Shortcut 1";
@@ -111,9 +109,7 @@
}
}
- @Ignore
@Test
- @ScreenRecord // b/260722220
public void testShortcutIconWithTheme() throws Exception {
setThemeEnabled(true);
TaplTestsLauncher3.initialize(this);
diff --git a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
index 57db13a..4303bfb 100644
--- a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
+++ b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
@@ -22,43 +22,41 @@
* be null"). To fix this, we can use methods that modify the return type to be nullable. This
* causes Kotlin to skip the null checks.
*/
-
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
/**
- * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> eq(obj: T): T = Mockito.eq<T>(obj)
/**
- * Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> same(obj: T): T = Mockito.same<T>(obj)
/**
- * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
+
inline fun <reified T> any(): T = any(T::class.java)
-/**
- * Kotlin type-inferred version of Mockito.nullable()
- */
+/** Kotlin type-inferred version of Mockito.nullable() */
inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
/**
- * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
- * when null is returned.
+ * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException when
+ * null is returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
@@ -82,8 +80,9 @@
/**
* A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
* kotlin tests are mocking kotlin objects and the methods take non-null parameters:
- *
+ * ```
* java.lang.NullPointerException: capture() must not be null
+ * ```
*/
class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) {
private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz)
@@ -102,15 +101,15 @@
/**
* Helper function for creating and using a single-use ArgumentCaptor in kotlin.
- *
+ * ```
* val captor = argumentCaptor<Foo>()
* verify(...).someMethod(captor.capture())
* val captured = captor.value
- *
+ * ```
* becomes:
- *
+ * ```
* val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
- *
+ * ```
* NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
*/
inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
diff --git a/tests/src/com/android/launcher3/util/LockedUserStateTest.kt b/tests/src/com/android/launcher3/util/LockedUserStateTest.kt
new file mode 100644
index 0000000..84156e7
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/LockedUserStateTest.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.Intent
+import android.os.Process
+import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+/** Unit tests for {@link LockedUserUtil} */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockedUserStateTest {
+
+ @Mock lateinit var userManager: UserManager
+ @Mock lateinit var context: Context
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(context.getSystemService(UserManager::class.java)).thenReturn(userManager)
+ }
+
+ @Test
+ fun runOnUserUnlocked_runs_action_immediately_if_already_unlocked() {
+ `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(true)
+ LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
+ val action: Runnable = mock()
+
+ LockedUserState.get(context).runOnUserUnlocked(action)
+ verify(action).run()
+ }
+
+ @Test
+ fun runOnUserUnlocked_waits_to_run_action_until_user_is_unlocked() {
+ `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(false)
+ LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
+ val action: Runnable = mock()
+
+ LockedUserState.get(context).runOnUserUnlocked(action)
+ verifyZeroInteractions(action)
+
+ LockedUserState.get(context)
+ .mUserUnlockedReceiver
+ .onReceive(context, Intent(Intent.ACTION_USER_UNLOCKED))
+
+ verify(action).run()
+ }
+
+ @Test
+ fun isUserUnlocked_returns_true_when_user_is_unlocked() {
+ `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(true)
+ LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
+ assertThat(LockedUserState.get(context).isUserUnlocked).isTrue()
+ }
+
+ @Test
+ fun isUserUnlocked_returns_false_when_user_is_locked() {
+ `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(false)
+ LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
+ assertThat(LockedUserState.get(context).isUserUnlocked).isFalse()
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
index bf3a092..a63136e 100644
--- a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
+++ b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
@@ -30,18 +30,18 @@
private val received = mutableListOf<Float>()
- private val receiveProperty: FloatProperty<Any> = object : FloatProperty<Any>("receive") {
- override fun setValue(obj: Any?, value: Float) {
- received.add(value)
+ private val receiveProperty: FloatProperty<Any> =
+ object : FloatProperty<Any>("receive") {
+ override fun setValue(obj: Any?, value: Float) {
+ received.add(value)
+ }
+ override fun get(o: Any): Float {
+ return 0f
+ }
}
- override fun get(o: Any): Float {
- return 0f
- }
- }
- private val factory = MultiPropertyFactory(null, receiveProperty, 3) {
- x: Float, y: Float -> x + y
- }
+ private val factory =
+ MultiPropertyFactory(null, receiveProperty, 3) { x: Float, y: Float -> x + y }
private val p1 = factory.get(0)
private val p2 = factory.get(1)
diff --git a/tests/src/com/android/launcher3/util/TouchUtilTest.kt b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
index d6c6e91..235d6ec 100644
--- a/tests/src/com/android/launcher3/util/TouchUtilTest.kt
+++ b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
@@ -18,9 +18,9 @@
import android.view.InputDevice
import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
-import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith