Merge "overview: rebalance hidden tasks in grid" into sc-v2-dev
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 72b8d3f..dacd8a2 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -80,7 +80,7 @@
}
@Override
- public Bundle call(String method) {
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
@@ -161,7 +161,7 @@
}
default:
- return super.call(method);
+ return super.call(method, arg);
}
}
}
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 64fe382..3f26977 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -56,14 +56,14 @@
<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_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="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_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>
@@ -73,7 +73,7 @@
<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_title" msgid="5021126669778966707">"اكتملت عملية الإعداد"</string>
<string name="allset_hint" msgid="2384632994739392447">"مرِّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية."</string>
<string name="allset_description" msgid="6350320429953234580">"يمكنك الآن بدء استخدام هاتفك."</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"إعدادات التنقّل داخل النظام"</annotation></string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index a4e5778..e61fd91 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -53,16 +53,16 @@
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Cambia sensibilidad de gesto \"Atrás\" en Configuración"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Desliza el dedo para volver"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Desliza el dedo desde el borde derecho o izquierdo para volver a la última pantalla."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Desliza el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Asegúrate de no detenerte antes de soltarlo."</string>
- <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Asegúrate de deslizar el dedo derecho hacia arriba."</string>
+ <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Desliza el dedo directamente hacia arriba."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Completaste el gesto para ir a la página principal. A continuación, obtén información para volver."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Completaste el gesto para ir a la página principal."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza el dedo para ir a la página principal"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza el dedo hacia arriba desde la parte inferior de la pantalla. Este gesto te llevará siempre a la pantalla principal."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Desliza el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prueba mantener presionada la ventana más tiempo antes de soltarla."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Asegúrate de deslizar el dedo derecho hacia arriba y, luego, detente."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Desliza el dedo directamente hacia arriba y luego detente."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ya sabes cómo usar los gestos. Para desactivarlos, ve a Configuración."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Completaste el gesto para cambiar de app."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza el dedo para cambiar de app"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index f7b0605..a3c9393 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -51,7 +51,7 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Vous avez appris le geste de retour en arrière."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Assurez-vous de ne pas balayer trop près du bas de l\'écran."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste de retour dans Paramètres"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Balayez l\'écran pour revenir en arrière"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Balayer l\'écran pour revenir en arrière"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Pour revenir à l\'écran précédent, balayez l\'écran de l\'extrémité gauche ou droite vers le centre."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Assurez-vous de balayer l\'écran à partir de l\'extrémité inférieure vers le haut."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Assurez-vous de ne pas interrompre le geste avant de lever le doigt."</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 7e2e957..5164792 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -53,20 +53,20 @@
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste retour dans les paramètres"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Balayez l\'écran pour revenir en arrière"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Pour revenir à l\'écran précédent, balayez l\'écran depuis le bord droit ou gauche jusqu\'au centre."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Veillez à balayer l\'écran du bas vers le haut."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Veillez à balayer l\'écran de bas en haut."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Veillez à ne pas marquer de pause dans votre geste avant de relever le doigt."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Veillez à balayer l\'écran vers le haut."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Vous savez désormais revenir à l\'écran d\'accueil. Apprenez maintenant à revenir en arrière."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Vous avez appris le geste pour revenir à l\'écran d\'accueil."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Balayer pour revenir à l\'écran d\'accueil"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Balayez pour revenir à l\'écran d\'accueil"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Balayez l\'écran de bas en haut. Ce geste vous ramènera toujours à l\'écran d\'accueil."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Veillez à balayer l\'écran du bas vers le haut."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Veillez à balayer l\'écran de bas en haut."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Essayez d\'appuyer plus longtemps sur la fenêtre avant de relever le doigt."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Veillez à balayer l\'écran vers le haut et à marquer une pause dans votre geste."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Veillez à balayer l\'écran vers le haut, puis à marquer une pause."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Vous avez appris à utiliser les gestes. Pour les désactiver, accédez aux paramètres."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Vous avez appris le geste pour passer d\'une appli à l\'autre."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayer pour passer d\'une appli à l\'autre"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'appli, balayez l\'écran du bas vers le haut, appuyez de manière prolongée et relâchez."</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayez pour passer d\'une appli à l\'autre"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'appli, balayez l\'écran de bas en haut, appuyez de manière prolongée et relâchez."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Vous avez terminé"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"OK"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Paramètres"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 44f2f15..50ebb27 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -49,7 +49,7 @@
<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_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>
@@ -83,5 +83,5 @@
<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="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"अभी नहीं"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 9ec5295..ba564a7 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -52,14 +52,14 @@
<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_intro_subtitle" msgid="7912576483031802797">"마지막 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요."</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_intro_subtitle" msgid="2632238748497975326">"화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다."</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>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index f6841fa..96da966 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -56,7 +56,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Swipe vanaf de onderrand van het scherm omhoog."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Pauzeer niet voordat je loslaat."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Swipe recht omhoog."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Je weet nu hoe je teruggaat naar het startscherm. Ontdek als volgende hoe je kunt teruggaan."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Je weet nu hoe je weer naar het startscherm gaat. Ontdek als volgende hoe je weer teruggaat."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Je weet nu hoe je teruggaat naar het startscherm."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe om naar het startscherm te gaan"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe omhoog vanaf de onderkant van het scherm. Met dit gebaar ga je altijd naar het startscherm."</string>
@@ -66,11 +66,11 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Je weet nu hoe je gebaren gebruikt. Als je gebaren wilt uitzetten, kun je dat via Instellingen doen."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Je weet nu hoe je het gebaar Schakelen tussen apps maakt."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe om tussen apps te schakelen"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat los om tussen apps te wisselen."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat los om tussen apps te schakelen."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Klaar"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Klaar"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Instellingen"</string>
- <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Opnieuw"</string>
+ <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Probeer opnieuw"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Dat gaat lekker."</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Klaar"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index c7e0bb7..9e641de 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -49,20 +49,20 @@
<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_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="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_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="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"请从屏幕底部边缘向上滑动。"</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_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>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 4e97fbd..659ff9a 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,6 +16,8 @@
<resources>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size">48dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size_grid">32dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
<!-- For Launchers that want to override the default dialog corner radius -->
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index aba16c2..5777fb9 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -108,6 +108,13 @@
}
};
+ private final Runnable mOpaquenessListener = new Runnable() {
+ @Override
+ public void run() {
+ dispatchTransactionSurface(mDepth);
+ }
+ };
+
private final Launcher mLauncher;
/**
* Blur radius when completely zoomed out, in pixels.
@@ -158,23 +165,28 @@
if (windowToken != null) {
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
}
- CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
- mCrossWindowBlurListener);
+ onAttached();
}
@Override
public void onViewDetachedFromWindow(View view) {
CrossWindowBlurListeners.getInstance().removeListener(mCrossWindowBlurListener);
+ mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener);
}
};
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
if (mLauncher.getRootView().isAttachedToWindow()) {
- CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
- mCrossWindowBlurListener);
+ onAttached();
}
}
}
+ private void onAttached() {
+ CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
+ mCrossWindowBlurListener);
+ mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener);
+ }
+
/**
* Sets if the underlying activity is started or not
*/
@@ -262,7 +274,7 @@
public void onOverlayScrollChanged(float progress) {
// Round out the progress to dedupe frequent, non-perceptable updates
int progressI = (int) (progress * 256);
- float progressF = progressI / 256f;
+ float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f);
if (Float.compare(mOverlayScrollProgress, progressF) == 0) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index b5c834d..56c28f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -38,9 +38,9 @@
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
-
/**
* A data source which integrates with a Launcher instance
*/
@@ -159,8 +159,7 @@
* automatically reset once the recents animation finishes
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
- @NonNull RecentsAnimationCallbacks callbacks,
- long duration) {
+ @NonNull RecentsAnimationCallbacks callbacks, long duration) {
TaskbarStashController stashController = mControllers.taskbarStashController;
ObjectAnimator animator = mIconAlignmentForGestureState
.animateToValue(1)
@@ -180,31 +179,15 @@
stashController.animateToIsStashed(false, duration);
}
});
- callbacks.addListener(new RecentsAnimationListener() {
- @Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- endGestureStateOverride(true);
- }
- @Override
- public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- endGestureStateOverride(!controller.getFinishTargetIsLauncher());
- }
-
- private void endGestureStateOverride(boolean finishedToApp) {
- callbacks.removeListener(this);
- mIsAnimatingToLauncherViaGesture = false;
-
- mIconAlignmentForGestureState
- .animateToValue(0)
- .start();
-
- if (finishedToApp) {
- // We only need this for the exiting live tile case.
- stashController.animateToIsStashed(stashController.isStashedInApp());
- }
- }
+ TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
+ callbacks.addListener(listener);
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.setTaskLaunchListener(() -> {
+ listener.endGestureStateOverride(true);
+ callbacks.removeListener(listener);
});
+
return animator;
}
@@ -249,4 +232,36 @@
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
}
+
+ private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
+ private final RecentsAnimationCallbacks mCallbacks;
+
+ TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ endGestureStateOverride(true);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ endGestureStateOverride(!controller.getFinishTargetIsLauncher());
+ }
+
+ private void endGestureStateOverride(boolean finishedToApp) {
+ mCallbacks.removeListener(this);
+ mIsAnimatingToLauncherViaGesture = false;
+
+ mIconAlignmentForGestureState
+ .animateToValue(0)
+ .start();
+
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ if (finishedToApp) {
+ controller.animateToIsStashed(controller.isStashedInApp());
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index dd7c403..6fbef9b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -18,7 +18,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import android.content.Intent;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.IntDef;
@@ -90,9 +89,7 @@
}
private void navigateHome() {
- mService.startActivity(new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
private void navigateToOverview() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 2009cd7..069af96 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -36,9 +36,13 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.view.HapticFeedbackConstants;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -75,9 +79,14 @@
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.util.LauncherUnfoldAnimationController;
+import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.unfold.UnfoldTransitionFactory;
+import com.android.unfold.UnfoldTransitionProgressProvider;
+import com.android.unfold.config.UnfoldTransitionConfig;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -97,10 +106,51 @@
private FixedContainerItems mAllAppsPredictions;
private HotseatPredictionController mHotseatPredictionController;
+ @Nullable
+ private LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
+
@Override
protected void setupViews() {
super.setupViews();
mHotseatPredictionController = new HotseatPredictionController(this);
+
+ final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this);
+ if (config.isEnabled()) {
+ final UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
+ UnfoldTransitionFactory.createUnfoldTransitionProgressProvider(
+ this,
+ config,
+ ProxyScreenStatusProvider.INSTANCE,
+ getSystemService(DeviceStateManager.class),
+ getSystemService(SensorManager.class),
+ getMainThreadHandler(),
+ getMainExecutor()
+ );
+
+ mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController(
+ this,
+ getWindowManager(),
+ unfoldTransitionProgressProvider
+ );
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onResume();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onPause();
+ }
+
+ super.onPause();
}
@Override
@@ -231,6 +281,10 @@
public void onDestroy() {
super.onDestroy();
mHotseatPredictionController.destroy();
+
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onDestroy();
+ }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
index d14e8ef..0e12e30 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
@@ -14,35 +14,18 @@
package com.android.launcher3.uioverrides.plugins;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-
import android.content.Context;
-import android.os.Looper;
import com.android.launcher3.Utilities;
import com.android.systemui.shared.plugins.PluginInitializer;
public class PluginInitializerImpl implements PluginInitializer {
@Override
- public Looper getBgLooper() {
- return MODEL_EXECUTOR.getLooper();
- }
-
- @Override
- public void onPluginManagerInit() {
- }
-
- @Override
- public String[] getWhitelistedPlugins(Context context) {
+ public String[] getPrivilegedPlugins(Context context) {
return new String[0];
}
@Override
- public PluginEnablerImpl getPluginEnabler(Context context) {
- return new PluginEnablerImpl(context);
- }
-
- @Override
public void handleWtfs() {
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
index 2e422b7..f653906 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -16,6 +16,8 @@
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -24,6 +26,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginInstanceManager;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs;
@@ -31,6 +34,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
public class PluginManagerWrapper {
@@ -47,8 +51,14 @@
private PluginManagerWrapper(Context c) {
mContext = c;
PluginInitializerImpl pluginInitializer = new PluginInitializerImpl();
- mPluginManager = new PluginManagerImpl(c, pluginInitializer);
- mPluginEnabler = pluginInitializer.getPluginEnabler(c);
+ mPluginEnabler = new PluginEnablerImpl(c);
+ PluginInstanceManager.Factory instanceManagerFactory = new PluginInstanceManager.Factory(
+ c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR, pluginInitializer);
+
+ mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
+ pluginInitializer.isDebuggable(),
+ Optional.ofNullable(Thread.getDefaultUncaughtExceptionHandler()), mPluginEnabler,
+ new PluginPrefs(c), pluginInitializer.getPrivilegedPlugins(c));
}
public PluginEnablerImpl getPluginEnabler() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index d822c8c..f8c9fd1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -70,7 +70,9 @@
@Override
protected float getDepthUnchecked(Context context) {
- return 1f;
+ // The scrim fades in at approximately 50% of the swipe gesture.
+ // This means that the depth should be greater than 1, in order to fully zoom out.
+ return 2f;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6249e6a..42c89fd 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1534,7 +1534,9 @@
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
- TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+ }
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
if (mActivity != null) {
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index fd44e02..e2f198c 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -173,7 +173,9 @@
@Override
protected void notifyGestureAnimationStartToRecents() {
if (mRunningOverHome) {
- mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ if (SysUINavigationMode.getMode(mContext).hasGestures) {
+ mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ }
} else {
super.notifyGestureAnimationStartToRecents();
}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 19cad53..3239b00 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -106,7 +106,9 @@
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
mActivity.getRootView().setForceHideBackArrow(true);
- mActivity.setHintUserWillBeActive();
+ if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ mActivity.setHintUserWillBeActive();
+ }
if (!canUseWorkspaceView || appCanEnterPip) {
return new LauncherHomeAnimationFactory();
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5d1f908..8fb851c 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -49,6 +49,7 @@
public static final int TYPE_SHOW_NEXT_FOCUS = 2;
public static final int TYPE_HIDE = 3;
public static final int TYPE_TOGGLE = 4;
+ public static final int TYPE_HOME = 5;
private static final String TRANSITION_NAME = "Transition:toOverview";
@@ -154,6 +155,10 @@
// already hidden
return true;
}
+ if (cmd.type == TYPE_HOME) {
+ mService.startActivity(mOverviewComponentObserver.getHomeIntent());
+ return true;
+ }
} else {
switch (cmd.type) {
case TYPE_SHOW:
@@ -168,6 +173,9 @@
}
case TYPE_TOGGLE:
return launchTask(recents, getNextTask(recents), cmd);
+ case TYPE_HOME:
+ recents.startHome();
+ return true;
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 39af0db..d531339 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -21,7 +21,7 @@
}
@Override
- public Bundle call(String method) {
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
@@ -66,7 +66,7 @@
}
}
- return super.call(method);
+ return super.call(method, arg);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 080533b..f49c9b0 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -183,6 +183,13 @@
}
/**
+ * Called when the current task's thumbnail has changed.
+ */
+ public void refreshActionVisibility(ThumbnailData thumbnail) {
+ getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
+ }
+
+ /**
* End rendering live tile in Overview.
*
* @param callback callback to run, after switching to screenshot
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 61622ee..4979206 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -100,6 +100,7 @@
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.ProtoTracer;
+import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.plugins.PluginListener;
@@ -268,6 +269,12 @@
MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
}
+ @BinderThread
+ @Override
+ public void onScreenTurnedOn() {
+ MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurnedOn);
+ }
+
@Override
public void onRotationProposal(int rotation, boolean isValid) {
executeForTaskbarManager(() -> mTaskbarManager.onRotationProposal(rotation, isValid));
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 6bdc284..7ae0fc8 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -16,19 +16,15 @@
package com.android.quickstep.logging;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.Utilities.getPrefs;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_2;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_3;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_4;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_5;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_ENABLED;
+import static com.android.launcher3.model.DeviceGridState.KEY_WORKSPACE_SIZE;
import static com.android.launcher3.model.QuickstepModelDelegate.LAST_PREDICTION_ENABLED_STATE;
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
@@ -43,11 +39,11 @@
import com.android.launcher3.AutoInstallsLayout;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.util.SettingsCache;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -135,7 +131,8 @@
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (LAST_PREDICTION_ENABLED_STATE.equals(key)
- || KEY_MIGRATION_SRC_WORKSPACE_SIZE.equals(key)
+ || KEY_WORKSPACE_SIZE.equals(key)
+ || KEY_THEMED_ICONS.equals(key)
|| mLoggablePrefs.containsKey(key)) {
dispatchUserEvent();
}
@@ -153,32 +150,13 @@
? LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED
: LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED);
- SharedPreferences prefs = getPrefs(mContext);
- StatsLogManager.LauncherEvent gridSizeChangedEvent = null;
- String workspaceSize = prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, null);
- if (workspaceSize != null) {
- switch (Utilities.parsePoint(workspaceSize).x) {
- case 5:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_5;
- break;
- case 4:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_4;
- break;
- case 3:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_3;
- break;
- case 2:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_2;
- break;
- default:
- // Ignore illegal input.
- break;
- }
- }
+ StatsLogManager.LauncherEvent gridSizeChangedEvent =
+ new DeviceGridState(mContext).getWorkspaceSizeEvent();
if (gridSizeChangedEvent != null) {
logger.log(gridSizeChangedEvent);
}
+ SharedPreferences prefs = getPrefs(mContext);
if (FeatureFlags.ENABLE_THEMED_ICONS.get()) {
logger.log(prefs.getBoolean(KEY_THEMED_ICONS, false)
? LAUNCHER_THEMED_ICON_ENABLED
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index f1b4e3d..baca76c 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -48,15 +48,16 @@
public class AnimatorControllerWithResistance {
private enum RecentsResistanceParams {
- FROM_APP(0.75f, 0.5f, 1f),
- FROM_APP_TABLET(0.9f, 0.75f, 1f),
- FROM_OVERVIEW(1f, 0.75f, 0.5f);
+ FROM_APP(0.75f, 0.5f, 1f, false),
+ FROM_APP_TABLET(1f, 0.7f, 1f, true),
+ FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
RecentsResistanceParams(float scaleStartResist, float scaleMaxResist,
- float translationFactor) {
+ float translationFactor, boolean stopScalingAtTop) {
this.scaleStartResist = scaleStartResist;
this.scaleMaxResist = scaleMaxResist;
this.translationFactor = translationFactor;
+ this.stopScalingAtTop = stopScalingAtTop;
}
/**
@@ -74,6 +75,12 @@
* where 0 will keep it centered and 1 will have it barely touch the top of the screen.
*/
public final float translationFactor;
+
+ /**
+ * Whether to end scaling effect when the scaled down version of TaskView's top reaches the
+ * non-scaled version of TaskView's top.
+ */
+ public final boolean stopScalingAtTop;
}
private static final TimeInterpolator RECENTS_SCALE_RESIST_INTERPOLATOR = DEACCEL;
@@ -161,26 +168,6 @@
PointF pivot = new PointF();
float fullscreenScale = params.recentsOrientedState.getFullScreenScaleAndPivot(
startRect, params.dp, pivot);
- float prevScaleRate = (fullscreenScale - params.startScale)
- / (params.dp.heightPx - startRect.bottom);
- // This is what the scale would be at the end of the drag if we didn't apply resistance.
- float endScale = params.startScale - prevScaleRate * distanceToCover;
- // Create an interpolator that resists the scale so the scale doesn't get smaller than
- // RECENTS_SCALE_MAX_RESIST.
- float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist,
- params.startScale, endScale);
- float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist,
- params.startScale, endScale);
- final TimeInterpolator scaleInterpolator = t -> {
- if (t < startResist) {
- return t;
- }
- float resistProgress = Utilities.getProgress(t, startResist, 1);
- resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
- return startResist + resistProgress * (maxResist - startResist);
- };
- resistAnim.addFloat(params.scaleTarget, params.scaleProperty, params.startScale, endScale,
- scaleInterpolator);
// Compute where the task view would be based on the end scale.
RectF endRectF = new RectF(startRect);
@@ -195,6 +182,32 @@
resistAnim.addFloat(params.translationTarget, params.translationProperty,
params.startTranslation, endTranslation, RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
+ float prevScaleRate = (fullscreenScale - params.startScale)
+ / (params.dp.heightPx - startRect.bottom);
+ // This is what the scale would be at the end of the drag if we didn't apply resistance.
+ float endScale = params.startScale - prevScaleRate * distanceToCover;
+ // Create an interpolator that resists the scale so the scale doesn't get smaller than
+ // RECENTS_SCALE_MAX_RESIST.
+ float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist,
+ params.startScale, endScale);
+ float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist,
+ params.startScale, endScale);
+ float stopResist =
+ params.resistanceParams.stopScalingAtTop ? 1f - startRect.top / endRectF.top : 1f;
+ final TimeInterpolator scaleInterpolator = t -> {
+ if (t < startResist) {
+ return t;
+ }
+ if (t > stopResist) {
+ return maxResist;
+ }
+ float resistProgress = Utilities.getProgress(t, startResist, stopResist);
+ resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
+ return startResist + resistProgress * (maxResist - startResist);
+ };
+ resistAnim.addFloat(params.scaleTarget, params.scaleProperty, params.startScale, endScale,
+ scaleInterpolator);
+
return resistAnim;
}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
new file mode 100644
index 0000000..ea1ece8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import com.android.launcher3.Launcher;
+import com.android.unfold.UnfoldTransitionProgressProvider;
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+
+/**
+ * Controls animations that are happening during unfolding foldable devices
+ */
+public class LauncherUnfoldAnimationController {
+
+ private final Launcher mLauncher;
+ private final UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
+ private final UnfoldMoveFromCenterWorkspaceAnimator mMoveFromCenterWorkspaceAnimation;
+
+ private final AnimationListener mAnimationListener = new AnimationListener();
+
+ private boolean mIsTransitionRunning = false;
+ private boolean mIsReadyToPlayAnimation = false;
+
+ public LauncherUnfoldAnimationController(
+ Launcher launcher,
+ WindowManager windowManager,
+ UnfoldTransitionProgressProvider unfoldTransitionProgressProvider) {
+ mLauncher = launcher;
+ mUnfoldTransitionProgressProvider = unfoldTransitionProgressProvider;
+ mMoveFromCenterWorkspaceAnimation = new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
+ windowManager);
+ mUnfoldTransitionProgressProvider.addCallback(mAnimationListener);
+ }
+
+ /**
+ * Called when launcher is resumed
+ */
+ public void onResume() {
+ final ViewTreeObserver obs = mLauncher.getWorkspace().getViewTreeObserver();
+ obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (obs.isAlive()) {
+ onPreDrawAfterResume();
+ obs.removeOnPreDrawListener(this);
+ }
+ return true;
+ }
+ });
+ }
+
+ /**
+ * Called when launcher activity is paused
+ */
+ public void onPause() {
+ mIsReadyToPlayAnimation = false;
+
+ if (mIsTransitionRunning) {
+ mIsTransitionRunning = false;
+ mMoveFromCenterWorkspaceAnimation.onTransitionFinished();
+ }
+ }
+
+ /**
+ * Called when launcher activity is destroyed
+ */
+ public void onDestroy() {
+ mUnfoldTransitionProgressProvider.removeCallback(mAnimationListener);
+ }
+
+ /**
+ * Called after performing layouting of the views after configuration change
+ */
+ private void onPreDrawAfterResume() {
+ mIsReadyToPlayAnimation = true;
+
+ if (mIsTransitionRunning) {
+ mMoveFromCenterWorkspaceAnimation.onTransitionStarted();
+ }
+ }
+
+ private class AnimationListener implements TransitionProgressListener {
+
+ @Override
+ public void onTransitionStarted() {
+ mIsTransitionRunning = true;
+
+ if (mIsReadyToPlayAnimation) {
+ mMoveFromCenterWorkspaceAnimation.onTransitionStarted();
+ }
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ if (mIsReadyToPlayAnimation) {
+ mMoveFromCenterWorkspaceAnimation.onTransitionFinished();
+ }
+
+ mIsTransitionRunning = false;
+ }
+
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterWorkspaceAnimation.onTransitionProgress(progress);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 1ed2da3..b83e26e 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -23,6 +23,7 @@
import com.android.launcher3.Alarm;
import com.android.launcher3.R;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
/**
* Given positions along x- or y-axis, tracks velocity and acceleration and determines when there is
@@ -118,9 +119,10 @@
* @param pointerIndex Index for the pointer being tracked in the motion event
*/
public void addPosition(MotionEvent ev, int pointerIndex) {
- mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
- ? HARDER_TRIGGER_TIMEOUT
- : FORCE_PAUSE_TIMEOUT);
+ long timeoutMs = TestProtocol.sForcePauseTimeout != null
+ ? TestProtocol.sForcePauseTimeout
+ : mMakePauseHarderToTrigger ? HARDER_TRIGGER_TIMEOUT : FORCE_PAUSE_TIMEOUT;
+ mForcePauseTimeout.setAlarm(timeoutMs);
float newVelocity = mVelocityProvider.addMotionEvent(ev, ev.getPointerId(pointerIndex));
if (mPreviousVelocity != null) {
checkMotionPaused(newVelocity, mPreviousVelocity, ev.getEventTime());
diff --git a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
new file mode 100644
index 0000000..9eda8f4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import androidx.annotation.NonNull;
+
+import com.android.unfold.updates.screen.ScreenStatusProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Screen status provider implementation that exposes methods to provide screen
+ * status updates to listeners. It is used to receive screen turned on event from
+ * SystemUI to Launcher.
+ */
+public class ProxyScreenStatusProvider implements ScreenStatusProvider {
+
+ public static final ProxyScreenStatusProvider INSTANCE = new ProxyScreenStatusProvider();
+ private final List<ScreenListener> mListeners = new ArrayList<>();
+
+ /**
+ * Called when the screen is on and ready (windows are drawn and screen blocker is removed)
+ */
+ public void onScreenTurnedOn() {
+ mListeners.forEach(ScreenListener::onScreenTurnedOn);
+ }
+
+ @Override
+ public void addCallback(@NonNull ScreenListener listener) {
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void removeCallback(@NonNull ScreenListener listener) {
+ mListeners.remove(listener);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
new file mode 100644
index 0000000..126e044
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.annotation.NonNull;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.TranslationApplier;
+import com.android.unfold.UnfoldTransitionProgressProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Animation that moves launcher icons and widgets from center to the sides (final position)
+ */
+public class UnfoldMoveFromCenterWorkspaceAnimator
+ implements UnfoldTransitionProgressProvider.TransitionProgressListener {
+
+ private final Launcher mLauncher;
+ private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
+
+ private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
+ private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
+
+ public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) {
+ mLauncher = launcher;
+ mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
+ new WorkspaceViewsTranslationApplier());
+ }
+
+ @Override
+ public void onTransitionStarted() {
+ mMoveFromCenterAnimation.updateDisplayProperties();
+
+ Workspace workspace = mLauncher.getWorkspace();
+ Hotseat hotseat = mLauncher.getHotseat();
+
+ // App icons and widgets
+ workspace
+ .forEachVisiblePage(page -> {
+ final CellLayout cellLayout = (CellLayout) page;
+ ShortcutAndWidgetContainer itemsContainer = cellLayout
+ .getShortcutsAndWidgets();
+ disableClipping(cellLayout);
+
+ for (int i = 0; i < itemsContainer.getChildCount(); i++) {
+ View child = itemsContainer.getChildAt(i);
+ mMoveFromCenterAnimation.registerViewForAnimation(child);
+ }
+ });
+
+ disableClipping(workspace);
+
+ // Hotseat icons
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
+ disableClipping(hotseat);
+
+ for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
+ View child = hotseatIcons.getChildAt(i);
+ mMoveFromCenterAnimation.registerViewForAnimation(child);
+ }
+
+ onTransitionProgress(0f);
+ }
+
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterAnimation.onTransitionProgress(progress);
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ mMoveFromCenterAnimation.onTransitionFinished();
+ mMoveFromCenterAnimation.clearRegisteredViews();
+
+ restoreClipping(mLauncher.getWorkspace());
+ mLauncher.getWorkspace().forEachVisiblePage(page -> restoreClipping((CellLayout) page));
+ restoreClipping(mLauncher.getHotseat());
+
+ mOriginalClipChildren.clear();
+ mOriginalClipToPadding.clear();
+ }
+
+ private void disableClipping(ViewGroup view) {
+ mOriginalClipToPadding.put(view, view.getClipToPadding());
+ mOriginalClipChildren.put(view, view.getClipChildren());
+ view.setClipToPadding(false);
+ view.setClipChildren(false);
+ }
+
+ private void restoreClipping(ViewGroup view) {
+ final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
+ if (originalClipToPadding != null) {
+ view.setClipToPadding(originalClipToPadding);
+ }
+ final Boolean originalClipChildren = mOriginalClipChildren.get(view);
+ if (originalClipChildren != null) {
+ view.setClipChildren(originalClipChildren);
+ }
+ }
+
+ private static class WorkspaceViewsTranslationApplier implements TranslationApplier {
+
+ @Override
+ public void apply(@NonNull View view, float x, float y) {
+ if (view instanceof NavigableAppWidgetHostView) {
+ ((NavigableAppWidgetHostView) view).setTranslationForMoveFromCenterAnimation(x, y);
+ } else if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationForMoveFromCenterAnimation(x, y);
+ } else {
+ view.setTranslationX(x);
+ view.setTranslationY(y);
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 5b0ade0..813e653 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -17,8 +17,10 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
import com.android.launcher3.Utilities;
@@ -30,6 +32,7 @@
public class IconView extends View {
private Drawable mDrawable;
+ private int mDrawableWidth, mDrawableHeight;
public IconView(Context context) {
super(context);
@@ -50,11 +53,29 @@
mDrawable = d;
if (mDrawable != null) {
mDrawable.setCallback(this);
- mDrawable.setBounds(0, 0, getWidth(), getHeight());
+ setDrawableSizeInternal(getWidth(), getHeight());
}
invalidate();
}
+ /**
+ * Sets the size of the icon drawable.
+ */
+ public void setDrawableSize(int iconWidth, int iconHeight) {
+ mDrawableWidth = iconWidth;
+ mDrawableHeight = iconHeight;
+ if (mDrawable != null) {
+ setDrawableSizeInternal(getWidth(), getHeight());
+ }
+ }
+
+ private void setDrawableSizeInternal(int selfWidth, int selfHeight) {
+ Rect selfRect = new Rect(0, 0, selfWidth, selfHeight);
+ Rect drawableRect = new Rect();
+ Gravity.apply(Gravity.CENTER, mDrawableWidth, mDrawableHeight, selfRect, drawableRect);
+ mDrawable.setBounds(drawableRect);
+ }
+
public Drawable getDrawable() {
return mDrawable;
}
@@ -63,7 +84,7 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mDrawable != null) {
- mDrawable.setBounds(0, 0, w, h);
+ setDrawableSizeInternal(w, h);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2242206..538e61e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -42,6 +42,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.launcher3.testing.TestProtocol.TASK_VIEW_ID_CRASH;
import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -82,6 +83,7 @@
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -601,6 +603,7 @@
};
private RunnableList mSideTaskLaunchCallback;
+ private TaskLaunchListener mTaskLaunchListener;
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy) {
@@ -881,6 +884,21 @@
mSideTaskLaunchCallback.add(callback::executeAllAndDestroy);
}
+ /**
+ * This is a one-time callback when touching in live tile mode. It's reset to null right
+ * after it's called.
+ */
+ public void setTaskLaunchListener(TaskLaunchListener taskLaunchListener) {
+ mTaskLaunchListener = taskLaunchListener;
+ }
+
+ public void onTaskLaunchedInLiveTileMode() {
+ if (mTaskLaunchListener != null) {
+ mTaskLaunchListener.onTaskLaunched();
+ mTaskLaunchListener = null;
+ }
+ }
+
private void executeSideTaskLaunchCallback() {
if (mSideTaskLaunchCallback != null) {
mSideTaskLaunchCallback.executeAllAndDestroy();
@@ -1171,7 +1189,7 @@
mMovingTaskView = focusedTaskView;
removeView(focusedTaskView);
mMovingTaskView = null;
- focusedTaskView.onRecycle();
+ focusedTaskView.resetPersistentViewTransforms();
addView(focusedTaskView, mTaskViewStartIndex);
setCurrentPage(mTaskViewStartIndex);
@@ -1223,6 +1241,9 @@
// TODO set these type to array and check all taskIDs? Maybe we can get away w/ only one
int runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId)[0];
int focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId)[0];
+ Log.d(TASK_VIEW_ID_CRASH, "runningTaskId beforeBind: " + runningTaskId
+ + " runningTaskViewId: " + mRunningTaskViewId
+ + " forTaskView: " + getTaskViewFromTaskViewId(mRunningTaskViewId));
// Rebind and reset all task views
for (int i = requiredTaskCount - 1; i >= 0; i--) {
@@ -1247,6 +1268,18 @@
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskId(runningTaskId);
+ if (newRunningTaskView == null) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = requiredTaskCount - 1; i >= 0; i--) {
+ final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
+ final TaskView taskView = (TaskView) getChildAt(pageIndex);
+ int taskViewId = taskView.getTaskViewId();
+ sb.append(" taskViewId: " + taskViewId
+ + " taskId: " + getTaskIdsForTaskViewId(taskViewId)[0]
+ + " for taskView: " + taskView + "\n");
+ }
+ Log.d(TASK_VIEW_ID_CRASH, sb.toString());
+ }
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
}
@@ -4303,4 +4336,8 @@
// Set locus context is a binder call, don't want it to happen during a transition
UI_HELPER_EXECUTOR.post(() -> mActivity.setLocusContext(id, Bundle.EMPTY));
}
+
+ public interface TaskLaunchListener {
+ void onTaskLaunched();
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 320ea09..35e21ad 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -162,7 +162,9 @@
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mBitmapShader);
updateThumbnailMatrix();
- refreshOverlay();
+ if (mOverlayEnabled) {
+ getTaskOverlay().refreshActionVisibility(mThumbnailData);
+ }
} else {
mBitmapShader = null;
mThumbnailData = null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ec08280..2c33b6d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -584,6 +584,7 @@
}
});
anim.start();
+ recentsView.onTaskLaunchedInLiveTileMode();
} else {
launchTaskAnimated();
}
@@ -614,12 +615,14 @@
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
- getRecentsView().getRunningTaskViewId() != -1) {
+ RecentsView recentsView = getRecentsView();
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskViewId() != -1) {
+ recentsView.onTaskLaunchedInLiveTileMode();
+
// Return a fresh callback in the live tile case, so that it's not accidentally
// triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
RunnableList callbackList = new RunnableList();
- getRecentsView().addSideTaskLaunchCallback(callbackList);
+ recentsView.addSideTaskLaunchCallback(callbackList);
return callbackList;
}
return opts.onEndCallback;
@@ -871,6 +874,12 @@
setIconAndDimTransitionProgress(iconScale, invert);
}
+ protected void resetPersistentViewTransforms() {
+ mNonGridTranslationX = mNonGridTranslationY =
+ mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
+ resetViewTransforms();
+ }
+
protected void resetViewTransforms() {
// fullscreenTranslation and accumulatedTranslation should not be reset, as
// resetViewTransforms is called during Quickswitch scrolling.
@@ -894,9 +903,7 @@
@Override
public void onRecycle() {
- mNonGridTranslationX = mNonGridTranslationY =
- mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
- resetViewTransforms();
+ resetPersistentViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
mSnapshotView.setThumbnail(mTask, null);
@@ -1353,9 +1360,10 @@
float boxTranslationY;
int expectedWidth;
int expectedHeight;
- if (mActivity.getDeviceProfile().overviewShowAsGrid) {
- final int thumbnailPadding =
- mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ int iconDrawableSize;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ if (deviceProfile.overviewShowAsGrid) {
+ final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx;
final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
final int taskWidth = lastComputedTaskSize.width();
final int taskHeight = lastComputedTaskSize.height();
@@ -1368,11 +1376,13 @@
// that is associated with the original orientation of the focused task.
boxWidth = taskWidth;
boxHeight = taskHeight;
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizePx;
} else {
// Otherwise task is in grid, and should use lastComputedGridTaskSize.
Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
boxWidth = lastComputedGridTaskSize.width();
boxHeight = lastComputedGridTaskSize.height();
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizeGridPx;
}
// Bound width/height to the box size.
@@ -1389,6 +1399,7 @@
boxTranslationY = 0f;
expectedWidth = ViewGroup.LayoutParams.MATCH_PARENT;
expectedHeight = ViewGroup.LayoutParams.MATCH_PARENT;
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizePx;
}
setNonGridScale(nonGridScale);
@@ -1398,6 +1409,7 @@
params.height = expectedHeight;
setLayoutParams(params);
}
+ mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
}
private float getGridTrans(float endTranslation) {
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index e4f5a19..45e7e69 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -59,7 +59,6 @@
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.quickstep.views.RecentsView;
import org.junit.After;
@@ -215,7 +214,6 @@
// b/143488140
//@NavigationModeSwitch
@Test
- @ScreenRecord // b/187080582
public void testOverview() {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 67840d1..bc8602c 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -49,6 +49,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test rule that allows executing a test with Quickstep on and then Quickstep off.
@@ -182,17 +183,12 @@
};
targetContext.getMainExecutor().execute(() ->
SYS_UI_NAVIGATION_MODE.addModeChangeListener(listener));
- // b/139137636
-// latch.await(60, TimeUnit.SECONDS);
+ latch.await(60, TimeUnit.SECONDS);
targetContext.getMainExecutor().execute(() ->
SYS_UI_NAVIGATION_MODE.removeModeChangeListener(listener));
- Wait.atMost(() -> "Navigation mode didn't change to " + expectedMode,
- () -> currentSysUiNavigationMode() == expectedMode, WAIT_TIME_MS,
- launcher);
- // b/139137636
-// assertTrue(launcher, "Navigation mode didn't change to " + expectedMode,
-// currentSysUiNavigationMode() == expectedMode, description);
+ assertTrue(launcher, "Navigation mode didn't change to " + expectedMode,
+ currentSysUiNavigationMode() == expectedMode, description);
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 164e755..177d744 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -37,7 +37,6 @@
import com.android.launcher3.tapl.OverviewActions;
import com.android.launcher3.tapl.OverviewTask;
import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
@@ -158,14 +157,7 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord //b/193125090
public void testOverviewActions() throws Exception {
- // Experimenting for b/165029151:
- final Overview overview = mLauncher.pressHome().switchToOverview();
- if (overview.hasTasks()) overview.dismissAllTasks();
- mLauncher.pressHome();
- //
-
startTestAppsWithCheck();
OverviewActions actionsView =
mLauncher.pressHome().switchToOverview().getOverviewActions();
diff --git a/res/drawable-v28/widgets_bottom_sheet_background.xml b/res/drawable-v28/widgets_bottom_sheet_background.xml
deleted file mode 100644
index 7fb8681..0000000
--- a/res/drawable-v28/widgets_bottom_sheet_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/surface" />
- <corners
- android:topLeftRadius="?android:attr/dialogCornerRadius"
- android:topRightRadius="?android:attr/dialogCornerRadius"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- />
-</shape>
\ No newline at end of file
diff --git a/res/drawable/widgets_bottom_sheet_background.xml b/res/drawable/bg_widgets_full_sheet.xml
similarity index 65%
rename from res/drawable/widgets_bottom_sheet_background.xml
rename to res/drawable/bg_widgets_full_sheet.xml
index b877546..dfcd354 100644
--- a/res/drawable/widgets_bottom_sheet_background.xml
+++ b/res/drawable/bg_widgets_full_sheet.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2021 The Android Open Source Project
+<!-- Copyright (C) 2021 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.
@@ -14,13 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/surface" />
+ android:shape="rectangle" >
+ <solid android:color="?android:attr/colorBackground" />
<corners
- android:topLeftRadius="@dimen/default_dialog_corner_radius"
- android:topRightRadius="@dimen/default_dialog_corner_radius"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- />
+ android:topLeftRadius="@dimen/dialogCornerRadius"
+ android:topRightRadius="@dimen/dialogCornerRadius" />
</shape>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_picker_handle.xml b/res/drawable/bg_widgets_picker_handle.xml
deleted file mode 100644
index 68681a6..0000000
--- a/res/drawable/bg_widgets_picker_handle.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape android:shape="rectangle">
- <solid android:color="?android:attr/colorBackground" />
- <padding android:top="16dp"/>
- </shape>
- </item>
- <item android:gravity="center">
- <shape android:shape="rectangle">
- <solid android:color="?android:attr/textColorSecondary" />
- <size android:width="48dp" android:height="2dp" />
- </shape>
- </item>
-</layer-list>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 3d330dc..1a2cfc6 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -18,7 +18,7 @@
android:id="@+id/widgets_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/widgets_bottom_sheet_background"
+ android:background="@drawable/bg_rounded_corner_bottom_sheet"
android:paddingTop="16dp"
android:orientation="vertical">
<View
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 96b73c2..8afd40b 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -19,13 +19,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:theme="?attr/widgetsTheme" >
+ android:theme="?attr/widgetsTheme">
- <com.android.launcher3.views.TopRoundedCornerView
+ <com.android.launcher3.views.SpringRelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?android:attr/colorBackground">
+ android:background="@drawable/bg_widgets_full_sheet">
+
+ <View
+ android:id="@+id/collapse_handle"
+ android:layout_width="48dp"
+ android:layout_height="2dp"
+ android:layout_marginTop="16dp"
+ android:layout_centerHorizontal="true"
+ android:background="?android:attr/textColorSecondary"/>
<TextView
android:id="@+id/no_widgets_text"
@@ -35,6 +43,7 @@
android:visibility="gone"
android:fontFamily="sans-serif-medium"
android:textSize="20sp"
+ android:layout_below="@id/search_and_recommendations_container"
tools:text="No widgets available" />
<!-- Fast scroller popup -->
@@ -57,9 +66,10 @@
android:id="@+id/search_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_below="@id/collapse_handle"
android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:visibility="gone"
android:clipToPadding="false" />
- </com.android.launcher3.views.TopRoundedCornerView>
+ </com.android.launcher3.views.SpringRelativeLayout>
</com.android.launcher3.widget.picker.WidgetsFullSheet>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index fefad19..85f14cd 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -22,7 +22,7 @@
android:layout_height="match_parent"
android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false"
- android:paddingTop="@dimen/widget_picker_view_pager_top_padding"
+ android:layout_below="@id/collapse_handle"
android:descendantFocusability="afterDescendants"
launcher:pageIndicator="@+id/tabs">
@@ -40,5 +40,84 @@
</com.android.launcher3.workprofile.PersonalWorkPagedView>
- <include layout="@layout/widgets_personal_work_tabs"/>
+ <!-- SearchAndRecommendationsView contains the tab layout as well -->
+ <com.android.launcher3.widget.picker.SearchAndRecommendationsView
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:layout_below="@id/collapse_handle"
+ android:paddingBottom="0dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textSize="24sp"
+ android:layout_marginTop="24dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/widget_button_text"/>
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="0.1dp"
+ android:background="?android:attr/colorBackground"
+ android:paddingBottom="8dp"
+ android:clipToPadding="false">
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:background="@drawable/widgets_recommendation_background"
+ android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
+ android:visibility="gone" />
+
+ <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:paddingVertical="8dp"
+ android:paddingLeft="@dimen/widget_tabs_horizontal_padding"
+ android:paddingRight="@dimen/widget_tabs_horizontal_padding"
+ android:background="?android:attr/colorBackground"
+ style="@style/TextHeadline">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_personal_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_work_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+ </com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
+
+ </com.android.launcher3.widget.picker.SearchAndRecommendationsView>
</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index 0f7e020..dde82ea 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -13,10 +13,54 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.widget.picker.WidgetsRecyclerView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/primary_widgets_list_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
- android:clipToPadding="false" />
\ No newline at end of file
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_below="@id/collapse_handle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:clipToPadding="false" />
+
+ <!-- SearchAndRecommendationsView without the tab layout as well -->
+ <com.android.launcher3.widget.picker.SearchAndRecommendationsView
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:layout_below="@id/collapse_handle"
+ android:paddingBottom="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textSize="24sp"
+ android:layout_marginTop="24dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/widget_button_text"/>
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="0.1dp"
+ android:background="?android:attr/colorBackground"
+ android:paddingBottom="8dp"
+ android:clipToPadding="false">
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:background="@drawable/widgets_recommendation_background"
+ android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
+ android:visibility="gone" />
+ </com.android.launcher3.widget.picker.SearchAndRecommendationsView>
+
+</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
deleted file mode 100644
index 938c8ed..0000000
--- a/res/layout/widgets_full_sheet_search_and_recommendations.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<com.android.launcher3.widget.picker.SearchAndRecommendationsView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/search_and_recommendations_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
- android:layout_marginBottom="16dp"
- android:orientation="vertical">
-
- <View
- android:id="@+id/collapse_handle"
- android:layout_width="match_parent"
- android:layout_height="18dp"
- android:elevation="0.1dp"
- android:background="@drawable/bg_widgets_picker_handle"/>
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:textSize="24sp"
- android:layout_marginTop="24dp"
- android:textColor="?android:attr/textColorSecondary"
- android:text="@string/widget_button_text"/>
-
- <FrameLayout
- android:id="@+id/search_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:elevation="0.1dp"
- android:background="?android:attr/colorBackground"
- android:paddingBottom="8dp"
- android:clipToPadding="false">
- <include layout="@layout/widgets_search_bar" />
- </FrameLayout>
-
- <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
- android:id="@+id/recommended_widget_table"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:background="@drawable/widgets_recommendation_background"
- android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
- android:visibility="gone" />
-</com.android.launcher3.widget.picker.SearchAndRecommendationsView>
diff --git a/res/layout/widgets_personal_work_tabs.xml b/res/layout/widgets_personal_work_tabs.xml
deleted file mode 100644
index 532c422..0000000
--- a/res/layout/widgets_personal_work_tabs.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 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.
--->
-
-<com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="@dimen/all_apps_header_pill_height"
- android:gravity="center_horizontal"
- android:orientation="horizontal"
- android:layout_marginHorizontal="@dimen/widget_tabs_horizontal_margin"
- style="@style/TextHeadline">
-
- <Button
- android:id="@+id/tab_personal"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
- android:layout_weight="1"
- android:background="@drawable/all_apps_tabs_background"
- android:text="@string/widgets_full_sheet_personal_tab"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp"
- style="?android:attr/borderlessButtonStyle" />
-
- <Button
- android:id="@+id/tab_work"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
- android:layout_weight="1"
- android:background="@drawable/all_apps_tabs_background"
- android:text="@string/widgets_full_sheet_work_tab"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp"
- style="?android:attr/borderlessButtonStyle" />
-</com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
\ No newline at end of file
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index aee2c73..71a3403 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -85,7 +85,7 @@
<string name="permdesc_write_settings" msgid="5440712911516509985">"Consente all\'app di modificare le impostazioni e le scorciatoie in Home."</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è autorizzata a effettuare telefonate"</string>
<string name="gadget_error_text" msgid="740356548025791839">"Impossibile caricare il widget"</string>
- <string name="gadget_setup_text" msgid="1745356155479272374">"Tocca per completare la configurazione"</string>
+ <string name="gadget_setup_text" msgid="1745356155479272374">"Tocca e completa configurazione"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"Modifica nome"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"App <xliff:g id="APP_NAME">%1$s</xliff:g> disattivata"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 80a6f10..6893888 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -68,7 +68,7 @@
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"షార్ట్కట్ను తరలించడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కండి & హోల్డ్ చేయండి."</string>
<string name="out_of_space" msgid="6692471482459245734">"ఈ మొదటి స్క్రీన్లో స్థలం లేదు"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"అనువర్తనాల జాబితా"</string>
+ <string name="all_apps_button_label" msgid="8130441508702294465">"యాప్ల జాబితా"</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>
@@ -83,7 +83,7 @@
<string name="permdesc_read_settings" msgid="5833423719057558387">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను చదవడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్లు మరియు సత్వరమార్గాలను వ్రాయడం"</string>
<string name="permdesc_write_settings" msgid="5440712911516509985">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను మార్చడానికి యాప్ను అనుమతిస్తుంది."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ఫోన్ కాల్లను చేసేందుకు <xliff:g id="APP_NAME">%1$s</xliff:g>కి అనుమతి లేదు"</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="1745356155479272374">"సెటప్ను పూర్తి చేయడానికి ట్యాప్ చేయండి"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"ఇది సిస్టమ్ యాప్ మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index c2ebeff..55cedf4 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -41,6 +41,8 @@
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
<color name="folder_dot_color">@android:color/system_accent2_50</color>
+ <color name="folder_pagination_color_light">@android:color/system_accent1_600</color>
+ <color name="folder_pagination_color_dark">@android:color/system_accent2_100</color>
<color name="home_settings_header_accent">@android:color/system_accent1_600</color>
<color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 00cf31c..2c01163 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -42,6 +42,7 @@
<attr name="popupNotificationDotColor" format="color" />
<attr name="folderDotColor" format="color" />
+ <attr name="folderPaginationColor" format="color" />
<attr name="folderFillColor" format="color" />
<attr name="folderIconRadius" format="float" />
<attr name="folderIconBorderColor" format="color" />
@@ -151,6 +152,12 @@
<attr name="demoModeLayoutId" format="reference" />
<attr name="isScalable" format="boolean" />
<attr name="devicePaddingId" format="reference" />
+ <attr name="gridEnabled" format="integer" >
+ <!-- Enable on all devices; default value -->
+ <enum name="all_displays" value="0" />
+ <!-- Enable on single display devices only -->
+ <enum name="single_display" value="1" />
+ </attr>
</declare-styleable>
@@ -176,11 +183,20 @@
<attr name="borderSpacingDps" format="float" />
<attr name="iconImageSize" format="float" />
- <!-- landscapeIconSize defaults to iconSize, if not specified -->
+ <!-- landscapeIconSize defaults to iconImageSize, if not specified -->
<attr name="landscapeIconSize" format="float" />
+ <!-- twoPanelPortraitIconSize defaults to iconImageSize, if not specified -->
+ <attr name="twoPanelPortraitIconSize" format="float" />
+ <!-- twoPanelLandscapeIconSize defaults to landscapeIconSize, if not specified -->
+ <attr name="twoPanelLandscapeIconSize" format="float" />
+
<attr name="iconTextSize" format="float" />
<!-- landscapeIconTextSize defaults to iconTextSize, if not specified -->
<attr name="landscapeIconTextSize" format="float" />
+ <!-- twoPanelPortraitIconTextSize defaults to iconTextSize, if not specified -->
+ <attr name="twoPanelPortraitIconTextSize" format="float" />
+ <!-- twoPanelLandscapeIconTextSize defaults to landscapeIconTextSize, if not specified -->
+ <attr name="twoPanelLandscapeIconTextSize" format="float" />
<!-- If set, this display option is used to determine the default grid -->
<attr name="canBeDefault" format="boolean|integer" >
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1b68fb6..cc5c5a3 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -73,6 +73,8 @@
<color name="folder_background_dark">#464746</color>
<color name="folder_dot_color">?attr/colorPrimary</color>
+ <color name="folder_pagination_color_light">#ff006c5f</color>
+ <color name="folder_pagination_color_dark">#ffbfebe3</color>
<color name="text_color_primary_dark">#FFFFFFFF</color>
<color name="text_color_secondary_dark">#FFFFFFFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 838d0ec..8457bd8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -143,8 +143,7 @@
<dimen name="widget_cell_font_size">14sp</dimen>
<dimen name="widget_tabs_button_horizontal_padding">4dp</dimen>
- <dimen name="widget_tabs_horizontal_margin">32dp</dimen>
- <dimen name="widget_apps_header_pill_height">48dp</dimen>
+ <dimen name="widget_tabs_horizontal_padding">16dp</dimen>
<dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
<dimen name="recommended_widgets_table_vertical_padding">8dp</dimen>
@@ -178,8 +177,6 @@
<dimen name="widget_picker_education_tip_max_width">308dp</dimen>
<dimen name="widget_picker_education_tip_min_margin">4dp</dimen>
- <dimen name="widget_picker_view_pager_top_padding">10dp</dimen>
-
<!-- Padding applied to shortcut previews -->
<dimen name="shortcut_preview_padding_left">0dp</dimen>
<dimen name="shortcut_preview_padding_right">0dp</dimen>
@@ -324,7 +321,8 @@
<!-- Overview placeholder to compile in Launcer3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
- <dimen name="task_thumbnail_icon_size_grid">0dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
<dimen name="overview_task_margin">0dp</dimen>
<dimen name="overview_task_margin_grid">0dp</dimen>
<dimen name="overview_actions_margin_gesture">0dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index 0e2dff0..ebc4075 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -17,6 +17,7 @@
<resources>
<item type="id" name="apps_list_view_work" />
<item type="id" name="tag_widget_entry" />
+ <item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
<item type="id" name="view_type_widgets_search_header" />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b7661b9..8ad4fcd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -50,6 +50,7 @@
<item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
<item name="folderDotColor">@color/folder_dot_color</item>
+ <item name="folderPaginationColor">@color/folder_pagination_color_light</item>
<item name="folderFillColor">@color/folder_background_light</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
<item name="folderTextColor">@color/workspace_text_color_dark</item>
@@ -108,6 +109,7 @@
<item name="popupShadeThird">@color/popup_shade_third_dark</item>
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
<item name="folderDotColor">@color/folder_dot_color</item>
+ <item name="folderPaginationColor">@color/folder_pagination_color_dark</item>
<item name="folderFillColor">@color/folder_background_dark</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
<item name="folderTextColor">@color/workspace_text_color_light</item>
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 34a8025..a397db5 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -76,7 +76,7 @@
setupUserManager();
setupBackupManager();
mModelHelper = new LauncherModelHelper();
- RestoreDbTask.setPending(RuntimeEnvironment.application, true);
+ RestoreDbTask.setPending(RuntimeEnvironment.application);
mDb = mModelHelper.provider.getDb();
mIdp = InvariantDeviceProfile.INSTANCE.get(RuntimeEnvironment.application);
}
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
index d2051e0..87b0887 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
@@ -124,11 +124,9 @@
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- srcHotseatItems.length);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
@@ -204,11 +202,9 @@
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- numSrcDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
@@ -247,16 +243,13 @@
mModelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI),
};
- int numSrcDatabaseHotseatIcons = srcHotseatItems.length;
mIdp.numDatabaseHotseatIcons = 4;
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- numSrcDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index c730fc0..fb44ca1 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -82,7 +82,7 @@
mTestProfile.numColumns = 5;
mUserHandle = Process.myUserHandle();
mAdapter = new WidgetsListAdapter(mContext, mMockLayoutInflater, mMockWidgetCache,
- mIconCache, null, null);
+ mIconCache, () -> 0, null, null);
mAdapter.registerAdapterDataObserver(mListener);
doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 81b0c5f..b7d7788 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -41,7 +41,6 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.testing.TestActivity;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.DatabaseWidgetPreviewLoader;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
@@ -79,8 +78,6 @@
@Mock
private DeviceProfile mDeviceProfile;
@Mock
- private DatabaseWidgetPreviewLoader mWidgetPreviewLoader;
- @Mock
private OnHeaderClickListener mOnHeaderClickListener;
@Before
@@ -99,18 +96,10 @@
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
return componentWithLabel.getComponent().getShortClassName();
}).when(mIconCache).getTitleNoCache(any());
-
- WidgetsListAdapter widgetsListAdapter = new WidgetsListAdapter(mContext,
- LayoutInflater.from(mTestActivity),
- mWidgetPreviewLoader,
- mIconCache,
- /* iconClickListener= */ view -> {},
- /* iconLongClickListener= */ view -> false);
mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
LayoutInflater.from(mTestActivity),
mOnHeaderClickListener,
- new WidgetsListDrawableFactory(mTestActivity),
- widgetsListAdapter);
+ new WidgetsListDrawableFactory(mTestActivity));
}
@After
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
index a0ba7c3..2b4cea0 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
@@ -41,7 +41,6 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.testing.TestActivity;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.DatabaseWidgetPreviewLoader;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
@@ -79,8 +78,6 @@
@Mock
private DeviceProfile mDeviceProfile;
@Mock
- private DatabaseWidgetPreviewLoader mWidgetPreviewLoader;
- @Mock
private OnHeaderClickListener mOnHeaderClickListener;
@Before
@@ -99,18 +96,10 @@
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
return componentWithLabel.getComponent().getShortClassName();
}).when(mIconCache).getTitleNoCache(any());
-
- WidgetsListAdapter widgetsListAdapter = new WidgetsListAdapter(mContext,
- LayoutInflater.from(mTestActivity),
- mWidgetPreviewLoader,
- mIconCache,
- /* iconClickListener= */ view -> {},
- /* iconLongClickListener= */ view -> false);
mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
LayoutInflater.from(mTestActivity),
mOnHeaderClickListener,
- new WidgetsListDrawableFactory(mTestActivity),
- widgetsListAdapter);
+ new WidgetsListDrawableFactory(mTestActivity));
}
@After
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 8f9d132..9f66fb7 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -107,19 +107,12 @@
return componentWithLabel.getComponent().getShortClassName();
}).when(mIconCache).getTitleNoCache(any());
- WidgetsListAdapter widgetsListAdapter = new WidgetsListAdapter(mContext,
- LayoutInflater.from(mTestActivity),
- mWidgetPreviewLoader,
- mIconCache,
- /* iconClickListener= */ view -> {},
- /* iconLongClickListener= */ view -> false);
mViewHolderBinder = new WidgetsListTableViewHolderBinder(
LayoutInflater.from(mTestActivity),
mOnIconClickListener,
mOnLongClickListener,
new CachingWidgetPreviewLoader(mWidgetPreviewLoader),
- new WidgetsListDrawableFactory(mTestActivity),
- widgetsListAdapter);
+ new WidgetsListDrawableFactory(mTestActivity));
}
@After
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index f800cf6..353e52b 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -90,6 +90,8 @@
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
+ private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
+
private float mScaleForReorderBounce = 1f;
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
@@ -321,7 +323,8 @@
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
- boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER;
+ boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
+ || mDisplay == DISPLAY_TASKBAR;
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), useTheme);
mDotParams.color = IconPalette.getMutedColor(iconDrawable.getIconColor(), 0.54f);
@@ -799,8 +802,10 @@
}
private void updateTranslation() {
- super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x);
- super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y);
+ super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
+ + mTranslationForMoveFromCenterAnimation.x);
+ super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
+ + mTranslationForMoveFromCenterAnimation.y);
}
public void setReorderBounceOffset(float x, float y) {
@@ -833,6 +838,11 @@
return mScaleForReorderBounce;
}
+ public void setTranslationForMoveFromCenterAnimation(float x, float y) {
+ mTranslationForMoveFromCenterAnimation.set(x, y);
+ updateTranslation();
+ }
+
public View getView() {
return this;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index d2d00c8..eb058e8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -184,6 +184,8 @@
public final boolean overviewShowAsGrid;
public int overviewTaskMarginPx;
public int overviewTaskIconSizePx;
+ public int overviewTaskIconDrawableSizePx;
+ public int overviewTaskIconDrawableSizeGridPx;
public int overviewTaskThumbnailTopMarginPx;
public final int overviewActionsMarginThreeButtonPx;
public final int overviewActionsTopMarginGesturePx;
@@ -362,6 +364,10 @@
? res.getDimensionPixelSize(R.dimen.overview_task_margin_grid)
: res.getDimensionPixelSize(R.dimen.overview_task_margin);
overviewTaskIconSizePx = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
+ overviewTaskIconDrawableSizePx =
+ res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size);
+ overviewTaskIconDrawableSizeGridPx =
+ res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2;
if (overviewShowAsGrid) {
if (isLandscape) {
@@ -419,14 +425,15 @@
// For devices with more extra space, we take a larger piece from each cell.
int piece = extraSpace < Utilities.dpToPx(TALL_DEVICE_MORE_EXTRA_SPACE_THRESHOLD_DP)
- ? 5 : 3;
+ ? 7 : 5;
int extraSpace = ((getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2)
* inv.numRows) / piece;
- int halfExtraSpace = extraSpace / 2;
- hotseatBarTopPaddingPx += halfExtraSpace;
- hotseatBarSizeExtraSpacePx = halfExtraSpace;
+ workspaceTopPadding = extraSpace / 8;
+ int halfLeftOver = (extraSpace - workspaceTopPadding) / 2;
+ hotseatBarTopPaddingPx += halfLeftOver;
+ hotseatBarSizeExtraSpacePx = halfLeftOver;
} else {
// ie. For a display with a large aspect ratio, we can keep the icons on the
// workspace in portrait mode closer together by adding more height to the hotseat.
@@ -605,12 +612,30 @@
iconScale = Math.min(1f, scale);
cellScaleToFit = scale;
-
// Workspace
final boolean isVerticalLayout = isVerticalBarLayout();
- float invIconSizeDp = isLandscape ? inv.landscapeIconSize : inv.iconSize;
+ float invIconSizeDp;
+ float invIconTextSizeSp;
+
+ if (isTwoPanels) {
+ if (isLandscape) {
+ invIconSizeDp = inv.twoPanelLandscapeIconSize;
+ invIconTextSizeSp = inv.twoPanelLandscapeIconTextSize;
+ } else {
+ invIconSizeDp = inv.twoPanelPortraitIconSize;
+ invIconTextSizeSp = inv.twoPanelPortraitIconTextSize;
+ }
+ } else {
+ if (isLandscape) {
+ invIconSizeDp = inv.landscapeIconSize;
+ invIconTextSizeSp = inv.landscapeIconTextSize;
+ } else {
+ invIconSizeDp = inv.iconSize;
+ invIconTextSizeSp = inv.iconTextSize;
+ }
+ }
+
iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, iconScale));
- float invIconTextSizeSp = isLandscape ? inv.landscapeIconTextSize : inv.iconTextSize;
iconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * iconScale);
iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index a2bd201..1fc8958 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -36,6 +35,7 @@
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
@@ -44,6 +44,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IntArray;
@@ -66,11 +67,10 @@
public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
- public static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size";
- public static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count";
-
private static final int DEFAULT_TRUE = -1;
private static final int DEFAULT_SPLIT_DISPLAY = 2;
+ private static final int GRID_ENABLED_ALL_DISPLAYS = 0;
+ private static final int GRID_ENABLED_SINGLE_DISPLAY = 1;
private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
@@ -97,12 +97,17 @@
public int numFolderColumns;
public float iconSize;
public float landscapeIconSize;
+ public float twoPanelPortraitIconSize;
+ public float twoPanelLandscapeIconSize;
public float landscapeIconTextSize;
+ public float twoPanelPortraitIconTextSize;
+ public float twoPanelLandscapeIconTextSize;
public int iconBitmapSize;
public int fillResIconDpi;
public float iconTextSize;
public float allAppsIconSize;
public float allAppsIconTextSize;
+ public boolean isSplitDisplay;
public float minCellHeight;
public float minCellWidth;
@@ -160,9 +165,13 @@
numFolderColumns = p.numFolderColumns;
iconSize = p.iconSize;
landscapeIconSize = p.landscapeIconSize;
+ twoPanelPortraitIconSize = p.twoPanelPortraitIconSize;
+ twoPanelLandscapeIconSize = p.twoPanelLandscapeIconSize;
iconBitmapSize = p.iconBitmapSize;
iconTextSize = p.iconTextSize;
landscapeIconTextSize = p.landscapeIconTextSize;
+ twoPanelPortraitIconTextSize = p.twoPanelPortraitIconTextSize;
+ twoPanelLandscapeIconTextSize = p.twoPanelLandscapeIconTextSize;
numShownHotseatIcons = p.numShownHotseatIcons;
numDatabaseHotseatIcons = p.numDatabaseHotseatIcons;
numAllAppsColumns = p.numAllAppsColumns;
@@ -188,10 +197,7 @@
if (!newGridName.equals(gridName)) {
Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply();
}
- Utilities.getPrefs(context).edit()
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numDatabaseHotseatIcons)
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(numColumns, numRows))
- .apply();
+ new DeviceGridState(this).writeToPrefs(context);
DisplayController.INSTANCE.get(context).addChangeListener(
(displayContext, info, flags) -> {
@@ -278,14 +284,19 @@
numFolderColumns = closestProfile.numFolderColumns;
isScalable = closestProfile.isScalable;
devicePaddingId = closestProfile.devicePaddingId;
+ this.isSplitDisplay = isSplitDisplay;
mExtraAttrs = closestProfile.extraAttrs;
iconSize = displayOption.iconSize;
landscapeIconSize = displayOption.landscapeIconSize;
+ twoPanelPortraitIconSize = displayOption.twoPanelPortraitIconSize;
+ twoPanelLandscapeIconSize = displayOption.twoPanelLandscapeIconSize;
iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics);
iconTextSize = displayOption.iconTextSize;
landscapeIconTextSize = displayOption.landscapeIconTextSize;
+ twoPanelPortraitIconTextSize = displayOption.twoPanelPortraitIconTextSize;
+ twoPanelLandscapeIconTextSize = displayOption.twoPanelLandscapeIconTextSize;
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
minCellHeight = displayOption.minCellHeight;
@@ -384,16 +395,19 @@
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
- GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
- final int displayDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > displayDepth)
- && type != XmlPullParser.END_DOCUMENT) {
- if ((type == XmlPullParser.START_TAG) && "display-option".equals(
- parser.getName())) {
- profiles.add(new DisplayOption(gridOption, context,
- Xml.asAttributeSet(parser),
- isSplitDisplay ? DEFAULT_SPLIT_DISPLAY : DEFAULT_TRUE));
+ GridOption gridOption =
+ new GridOption(context, Xml.asAttributeSet(parser), isSplitDisplay);
+ if (gridOption.isEnabled) {
+ final int displayDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG
+ || parser.getDepth() > displayDepth)
+ && type != XmlPullParser.END_DOCUMENT) {
+ if ((type == XmlPullParser.START_TAG) && "display-option".equals(
+ parser.getName())) {
+ profiles.add(new DisplayOption(gridOption, context,
+ Xml.asAttributeSet(parser),
+ isSplitDisplay ? DEFAULT_SPLIT_DISPLAY : DEFAULT_TRUE));
+ }
}
}
}
@@ -405,7 +419,7 @@
ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();
if (!TextUtils.isEmpty(gridName)) {
for (DisplayOption option : profiles) {
- if (gridName.equals(option.grid.name)) {
+ if (gridName.equals(option.grid.name) && option.grid.isEnabled) {
filteredProfiles.add(option);
}
}
@@ -424,6 +438,32 @@
return filteredProfiles;
}
+ /**
+ * @return all the grid options that can be shown on the device
+ */
+ public List<GridOption> parseAllGridOptions(Context context) {
+ List<GridOption> result = new ArrayList<>();
+ try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
+ final int depth = parser.getDepth();
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG
+ || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if ((type == XmlPullParser.START_TAG)
+ && GridOption.TAG_NAME.equals(parser.getName())) {
+ GridOption option =
+ new GridOption(context, Xml.asAttributeSet(parser), isSplitDisplay);
+ if (option.isEnabled) {
+ result.add(option);
+ }
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Error parsing device profile", e);
+ return Collections.emptyList();
+ }
+ return result;
+ }
+
private int getLauncherIconDensity(int requiredSize) {
// Densities typically defined by an app.
int[] densityBuckets = new int[] {
@@ -585,6 +625,7 @@
public final String name;
public final int numRows;
public final int numColumns;
+ public final boolean isEnabled;
private final int numFolderRows;
private final int numFolderColumns;
@@ -604,7 +645,7 @@
private final SparseArray<TypedValue> extraAttrs;
- public GridOption(Context context, AttributeSet attrs) {
+ public GridOption(Context context, AttributeSet attrs, boolean isSplitDisplay) {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridDisplayOption);
name = a.getString(R.styleable.GridDisplayOption_name);
@@ -637,6 +678,12 @@
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, 0);
+ final int enabledInt =
+ a.getInteger(R.styleable.GridDisplayOption_gridEnabled,
+ GRID_ENABLED_ALL_DISPLAYS);
+ isEnabled = enabledInt == GRID_ENABLED_ALL_DISPLAYS
+ || enabledInt == GRID_ENABLED_SINGLE_DISPLAY && !isSplitDisplay;
+
a.recycle();
extraAttrs = Themes.createValueMap(context, attrs,
IntArray.wrap(R.styleable.GridDisplayOption));
@@ -659,7 +706,11 @@
private float iconSize;
private float iconTextSize;
private float landscapeIconSize;
+ private float twoPanelPortraitIconSize;
+ private float twoPanelLandscapeIconSize;
private float landscapeIconTextSize;
+ private float twoPanelPortraitIconTextSize;
+ private float twoPanelLandscapeIconTextSize;
private float allAppsIconSize;
private float allAppsIconTextSize;
@@ -682,9 +733,19 @@
iconSize = a.getFloat(R.styleable.ProfileDisplayOption_iconImageSize, 0);
landscapeIconSize = a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize,
iconSize);
+ twoPanelPortraitIconSize = a.getFloat(
+ R.styleable.ProfileDisplayOption_twoPanelPortraitIconSize, iconSize);
+ twoPanelLandscapeIconSize = a.getFloat(
+ R.styleable.ProfileDisplayOption_twoPanelLandscapeIconSize,
+ landscapeIconSize);
iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
landscapeIconTextSize = a.getFloat(
R.styleable.ProfileDisplayOption_landscapeIconTextSize, iconTextSize);
+ twoPanelPortraitIconTextSize = a.getFloat(
+ R.styleable.ProfileDisplayOption_twoPanelPortraitIconTextSize, iconTextSize);
+ twoPanelLandscapeIconTextSize = a.getFloat(
+ R.styleable.ProfileDisplayOption_twoPanelLandscapeIconTextSize,
+ landscapeIconTextSize);
allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize,
iconSize);
@@ -710,9 +771,13 @@
private DisplayOption multiply(float w) {
iconSize *= w;
landscapeIconSize *= w;
+ twoPanelPortraitIconSize *= w;
+ twoPanelLandscapeIconSize *= w;
allAppsIconSize *= w;
iconTextSize *= w;
landscapeIconTextSize *= w;
+ twoPanelPortraitIconTextSize *= w;
+ twoPanelLandscapeIconTextSize *= w;
allAppsIconTextSize *= w;
minCellHeight *= w;
minCellWidth *= w;
@@ -723,9 +788,13 @@
private DisplayOption add(DisplayOption p) {
iconSize += p.iconSize;
landscapeIconSize += p.landscapeIconSize;
+ twoPanelPortraitIconSize += p.twoPanelPortraitIconSize;
+ twoPanelLandscapeIconSize += p.twoPanelLandscapeIconSize;
allAppsIconSize += p.allAppsIconSize;
iconTextSize += p.iconTextSize;
landscapeIconTextSize += p.landscapeIconTextSize;
+ twoPanelPortraitIconTextSize += p.twoPanelPortraitIconTextSize;
+ twoPanelLandscapeIconTextSize += p.twoPanelLandscapeIconTextSize;
allAppsIconTextSize += p.allAppsIconTextSize;
minCellHeight += p.minCellHeight;
minCellWidth += p.minCellWidth;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8249887..1ebfda1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1298,7 +1298,7 @@
}
if (!foundCellSpan) {
- mWorkspace.onNoCellFound(layout);
+ mWorkspace.onNoCellFound(layout, info, /* logInstanceId= */ null);
return;
}
@@ -1930,7 +1930,7 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Key event", event);
+ TestLogging.recordKeyEvent(TestProtocol.SEQUENCE_MAIN, "Key event", event);
return (event.getKeyCode() == KeyEvent.KEYCODE_HOME) || super.dispatchKeyEvent(event);
}
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index 140794b..dc533f0 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -31,6 +31,6 @@
@Override
public void onRestoreFinished() {
- RestoreDbTask.setPending(this, true);
+ RestoreDbTask.setPending(this);
}
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 95a8d81..49f20c6 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -151,15 +151,7 @@
mOpenHelper = DatabaseHelper.createDatabaseHelper(
getContext(), false /* forMigration */);
- if (RestoreDbTask.isPending(getContext())) {
- if (!RestoreDbTask.performRestore(getContext(), mOpenHelper,
- new BackupManager(getContext()))) {
- mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
- }
- // Set is pending to false irrespective of the result, so that it doesn't get
- // executed again.
- RestoreDbTask.setPending(getContext(), false);
- }
+ RestoreDbTask.restoreIfNeeded(getContext(), mOpenHelper);
}
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 242e3e3..eb3f94c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -353,7 +353,7 @@
} else if (focus == View.FOCUS_RIGHT) {
nextPage = currentPage + panelCount;
} else {
- // no neighbours to those direction
+ // no neighbours to other directions
return new IntSet();
}
nextPage = validateNewPage(nextPage);
@@ -362,12 +362,7 @@
return new IntSet();
}
- int pageCount = getPageCount();
- IntSet neighbourIndices = new IntSet();
- for (int page = nextPage; page < nextPage + panelCount && page < pageCount; page++) {
- neighbourIndices.add(page);
- }
- return neighbourIndices;
+ return getPageIndices(nextPage);
}
/**
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7d818d2..b92cf09 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -648,21 +648,6 @@
handler.sendMessage(msg);
}
- /**
- * Parses a string encoded using {@link #getPointString(int, int)}
- */
- public static Point parsePoint(String point) {
- String[] split = point.split(",");
- return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
- }
-
- /**
- * Encodes a point to string to that it can be persisted atomically.
- */
- public static String getPointString(int x, int y) {
- return String.format(Locale.ENGLISH, "%d,%d", x, y);
- }
-
public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) {
try {
context.unregisterReceiver(receiver);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9a8b80d..3bfa1e2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -16,8 +16,6 @@
package com.android.launcher3;
-import static androidx.annotation.VisibleForTesting.PROTECTED;
-
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -65,7 +63,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
-import androidx.annotation.VisibleForTesting;
+import androidx.annotation.Nullable;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
@@ -86,6 +84,7 @@
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.data.AppInfo;
@@ -325,6 +324,11 @@
setPageSpacing(Math.max(maxInsets, maxPadding));
}
+ updateWorkspaceScreensPadding();
+ }
+
+ private void updateWorkspaceScreensPadding() {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
int paddingBottom = grid.cellLayoutBottomPaddingPx;
@@ -457,7 +461,6 @@
}
@Override
- @VisibleForTesting(otherwise = PROTECTED)
public int getPanelCount() {
return isTwoPanelEnabled() ? 2 : super.getPanelCount();
}
@@ -621,10 +624,6 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
- int paddingBottom = grid.cellLayoutBottomPaddingPx;
- newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
mWorkspaceScreens.put(screenId, newScreen);
mScreenOrder.add(insertIndex, screenId);
@@ -633,6 +632,7 @@
mLauncher.getStateManager().getState(), newScreen, insertIndex);
updatePageScrollValues();
+ updateWorkspaceScreensPadding();
return newScreen;
}
@@ -1607,7 +1607,7 @@
// Don't accept the drop if there's no room for the item
if (!foundCell) {
- onNoCellFound(dropTargetLayout);
+ onNoCellFound(dropTargetLayout, d.dragInfo, d.logInstanceId);
return false;
}
}
@@ -1775,7 +1775,7 @@
boolean droppedOnOriginalCell = false;
- int snapScreen = -1;
+ boolean snappedToNewPage = false;
boolean resizeOnDrop = false;
Runnable onCompleteRunnable = null;
if (d.dragSource != this || mDragInfo == null) {
@@ -1857,11 +1857,14 @@
}
if (foundCell) {
- if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {
- snapScreen = getPageIndexForScreenId(screenId);
+ int targetScreenIndex = getPageIndexForScreenId(screenId);
+ int snapScreen = getLeftmostVisiblePageForIndex(targetScreenIndex);
+ // On large screen devices two pages can be shown at the same time, and snap
+ // isn't needed if the source and target screens appear at the same time
+ if (snapScreen != mCurrentPage && !hasMovedIntoHotseat) {
snapToPage(snapScreen);
+ snappedToNewPage = true;
}
-
final ItemInfo info = (ItemInfo) cell.getTag();
if (hasMovedLayouts) {
// Reparent the view
@@ -1906,7 +1909,7 @@
lp.cellX, lp.cellY, item.spanX, item.spanY);
} else {
if (!returnToOriginalCellToPreventShuffling) {
- onNoCellFound(dropTargetLayout);
+ onNoCellFound(dropTargetLayout, d.dragInfo, d.logInstanceId);
}
if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {
d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
@@ -1953,7 +1956,7 @@
ANIMATE_INTO_POSITION_AND_DISAPPEAR;
animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);
} else {
- int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
+ int duration = snappedToNewPage ? ADJACENT_SCREEN_DROP_DURATION : -1;
mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
this);
}
@@ -1974,10 +1977,16 @@
}
}
- public void onNoCellFound(View dropTargetLayout) {
+ public void onNoCellFound(
+ View dropTargetLayout, ItemInfo itemInfo, @Nullable InstanceId logInstanceId) {
int strId = mLauncher.isHotseatLayout(dropTargetLayout)
? R.string.hotseat_out_of_space : R.string.out_of_space;
Toast.makeText(mLauncher, mLauncher.getString(strId), Toast.LENGTH_SHORT).show();
+ StatsLogManager.StatsLogger logger = mStatsLogManager.logger().withItemInfo(itemInfo);
+ if (logInstanceId != null) {
+ logger = logger.withInstanceId(logInstanceId);
+ }
+ logger.log(LauncherEvent.LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE);
}
/**
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9faac5b..0fb5e77 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -188,7 +188,8 @@
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
if (item instanceof WorkspaceItemInfo) {
// Support the action unless the item is in a context menu.
- return item.screenId >= 0 && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ return (item.screenId >= 0 || item.screenId == Workspace.LEFT_PANEL_ID)
+ && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
}
return (item instanceof LauncherAppWidgetInfo)
|| (item instanceof FolderInfo);
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index e4f5539..fc8d855 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -9,7 +9,6 @@
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
@@ -23,23 +22,13 @@
import android.os.Messenger;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Xml;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.GridOption;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Executors;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* Exposes various launcher grid options and allows the caller to change them.
* APIs:
@@ -94,7 +83,7 @@
MatrixCursor cursor = new MatrixCursor(new String[] {
KEY_NAME, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, KEY_IS_DEFAULT});
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
- for (GridOption gridOption : parseAllGridOptions()) {
+ for (GridOption gridOption : idp.parseAllGridOptions(getContext())) {
cursor.newRow()
.add(KEY_NAME, gridOption.name)
.add(KEY_ROWS, gridOption.numRows)
@@ -116,25 +105,6 @@
}
}
- private List<GridOption> parseAllGridOptions() {
- List<GridOption> result = new ArrayList<>();
- try (XmlResourceParser parser = getContext().getResources().getXml(R.xml.device_profiles)) {
- final int depth = parser.getDepth();
- int type;
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if ((type == XmlPullParser.START_TAG)
- && GridOption.TAG_NAME.equals(parser.getName())) {
- result.add(new GridOption(getContext(), Xml.asAttributeSet(parser)));
- }
- }
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Error parsing device profile", e);
- return Collections.emptyList();
- }
- return result;
- }
-
@Override
public String getType(Uri uri) {
return "vnd.android.cursor.dir/launcher_grid";
@@ -155,9 +125,10 @@
switch (uri.getPath()) {
case KEY_DEFAULT_GRID: {
String gridName = values.getAsString(KEY_NAME);
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
// Verify that this is a valid grid option
GridOption match = null;
- for (GridOption option : parseAllGridOptions()) {
+ for (GridOption option : idp.parseAllGridOptions(getContext())) {
if (option.name.equals(gridName)) {
match = option;
break;
@@ -167,8 +138,7 @@
return 0;
}
- InvariantDeviceProfile.INSTANCE.get(getContext())
- .setCurrentGrid(getContext(), gridName);
+ idp.setCurrentGrid(getContext(), gridName);
return 1;
}
case ICON_THEMED:
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 94778a2..55995f2 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -270,13 +270,13 @@
CellLayout leftPanel = mRootView.findViewById(R.id.workspace_left);
leftPanel.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
mDp.workspacePadding.top,
- mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
+ mDp.workspacePadding.right,
mDp.workspacePadding.bottom);
mWorkspaceScreens.put(LEFT_PANEL_ID, leftPanel);
}
CellLayout firstScreen = mRootView.findViewById(R.id.workspace);
- firstScreen.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
+ firstScreen.setPadding(mDp.workspacePadding.left,
mDp.workspacePadding.top,
mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
mDp.workspacePadding.bottom);
@@ -286,8 +286,8 @@
WallpaperColors wallpaperColors = wallpaperColorsOverride != null
? wallpaperColorsOverride
: WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
- mWallpaperColorResources = LocalColorExtractor.newInstance(context)
- .generateColorsOverride(wallpaperColors);
+ mWallpaperColorResources = wallpaperColors != null ? LocalColorExtractor.newInstance(
+ context).generateColorsOverride(wallpaperColors) : null;
} else {
mWallpaperColorResources = null;
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 79e5b5d..d959ee2 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -486,7 +486,10 @@
LAUNCHER_TURN_ON_WORK_APPS_TAP(838),
@UiEvent(doc = "User tapped on 'Turn off work apps' button in all apps window.")
- LAUNCHER_TURN_OFF_WORK_APPS_TAP(839)
+ LAUNCHER_TURN_OFF_WORK_APPS_TAP(839),
+
+ @UiEvent(doc = "Launcher item drop failed since there was not enough room on the screen.")
+ LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872)
;
// ADD MORE
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
new file mode 100644
index 0000000..761053d
--- /dev/null
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_2;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_3;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_4;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_5;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Utility class representing persisted grid properties.
+ */
+public class DeviceGridState {
+
+ public static final String KEY_WORKSPACE_SIZE = "migration_src_workspace_size";
+ public static final String KEY_HOTSEAT_COUNT = "migration_src_hotseat_count";
+ public static final String KEY_DEVICE_TYPE = "migration_src_device_type";
+
+ public static final int TYPE_PHONE = 0;
+ public static final int TYPE_MULTI_DISPLAY = 1;
+ public static final int TYPE_TABLET = 2;
+
+ private final String mGridSizeString;
+ private final int mNumHotseat;
+ private final int mDeviceType;
+
+ public DeviceGridState(InvariantDeviceProfile idp) {
+ mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", idp.numColumns, idp.numRows);
+ mNumHotseat = idp.numDatabaseHotseatIcons;
+ mDeviceType = idp.supportedProfiles.size() > 2
+ ? TYPE_MULTI_DISPLAY
+ : idp.supportedProfiles.stream().allMatch(dp -> dp.isTablet)
+ ? TYPE_TABLET
+ : TYPE_PHONE;
+ }
+
+ public DeviceGridState(Context context) {
+ SharedPreferences prefs = Utilities.getPrefs(context);
+ mGridSizeString = prefs.getString(KEY_WORKSPACE_SIZE, "");
+ mNumHotseat = prefs.getInt(KEY_HOTSEAT_COUNT, -1);
+ mDeviceType = prefs.getInt(KEY_DEVICE_TYPE, TYPE_PHONE);
+ }
+
+ /**
+ * Returns the device type for the grid
+ */
+ public int getDeviceType() {
+ return mDeviceType;
+ }
+
+ /**
+ * Stores the device state to shared preferences
+ */
+ public void writeToPrefs(Context context) {
+ Utilities.getPrefs(context).edit()
+ .putString(KEY_WORKSPACE_SIZE, mGridSizeString)
+ .putInt(KEY_HOTSEAT_COUNT, mNumHotseat)
+ .putInt(KEY_DEVICE_TYPE, mDeviceType)
+ .apply();
+ }
+
+ /**
+ * Returns the logging event corresponding to the grid state
+ */
+ public LauncherEvent getWorkspaceSizeEvent() {
+ if (!TextUtils.isEmpty(mGridSizeString)) {
+ switch (mGridSizeString.charAt(0)) {
+ case '5':
+ return LAUNCHER_GRID_SIZE_5;
+ case '4':
+ return LAUNCHER_GRID_SIZE_4;
+ case '3':
+ return LAUNCHER_GRID_SIZE_3;
+ case '2':
+ return LAUNCHER_GRID_SIZE_2;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DeviceGridState that = (DeviceGridState) o;
+ return mNumHotseat == that.mNumHotseat
+ && mDeviceType == that.mDeviceType
+ && Objects.equals(mGridSizeString, that.mGridSizeString);
+ }
+}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 3935bcf..e64b25c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -16,9 +16,6 @@
package com.android.launcher3.model;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
-import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.content.ComponentName;
@@ -107,11 +104,7 @@
* Check given a new IDP, if migration is necessary.
*/
public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
- SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
-
- return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
- || idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
+ return !new DeviceGridState(idp).equals(new DeviceGridState(context));
}
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
@@ -124,15 +117,15 @@
/**
* When migrating the grid for preview, we copy the table
- * {@link LauncherSettings.Favorites.TABLE_NAME} into
- * {@link LauncherSettings.Favorites.PREVIEW_TABLE_NAME}, run grid size migration from the
+ * {@link LauncherSettings.Favorites#TABLE_NAME} into
+ * {@link LauncherSettings.Favorites#PREVIEW_TABLE_NAME}, run grid size migration from the
* former to the later, then use the later table for preview.
*
* Similarly when doing the actual grid migration, the former grid option's table
- * {@link LauncherSettings.Favorites.TABLE_NAME} is copied into the new grid option's
- * {@link LauncherSettings.Favorites.TMP_TABLE}, we then run the grid size migration algorithm
+ * {@link LauncherSettings.Favorites#TABLE_NAME} is copied into the new grid option's
+ * {@link LauncherSettings.Favorites#TMP_TABLE}, we then run the grid size migration algorithm
* to migrate the later to the former, and load the workspace from the default
- * {@link LauncherSettings.Favorites.TABLE_NAME}.
+ * {@link LauncherSettings.Favorites#TABLE_NAME}.
*
* @return false if the migration failed.
*/
@@ -147,10 +140,7 @@
}
SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
HashSet<String> validPackages = getValidPackages(context);
- int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
- idp.numDatabaseHotseatIcons);
if (migrateForPreview) {
if (!LauncherSettings.Settings.call(
@@ -175,11 +165,11 @@
DbReader srcReader = new DbReader(t.getDb(),
migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME
: LauncherSettings.Favorites.TMP_TABLE,
- context, validPackages, srcHotseatCount);
+ context, validPackages);
DbReader destReader = new DbReader(t.getDb(),
migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME
: LauncherSettings.Favorites.TABLE_NAME,
- context, validPackages, idp.numDatabaseHotseatIcons);
+ context, validPackages);
Point targetSize = new Point(idp.numColumns, idp.numRows);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(),
@@ -202,10 +192,7 @@
if (!migrateForPreview) {
// Save current configuration, so that the migration does not run again.
- prefs.edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons)
- .apply();
+ new DeviceGridState(idp).writeToPrefs(context);
}
}
}
@@ -504,7 +491,6 @@
private final String mTableName;
private final Context mContext;
private final HashSet<String> mValidPackages;
- private final int mHotseatSize;
private int mLastScreenId = -1;
private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>();
@@ -513,12 +499,11 @@
new ArrayMap<>();
DbReader(SQLiteDatabase db, String tableName, Context context,
- HashSet<String> validPackages, int hotseatSize) {
+ HashSet<String> validPackages) {
mDb = db;
mTableName = tableName;
mContext = context;
mValidPackages = validPackages;
- mHotseatSize = hotseatSize;
}
protected ArrayList<DbEntry> loadHotseatEntries() {
@@ -543,11 +528,6 @@
entry.itemType = c.getInt(indexItemType);
entry.screenId = c.getInt(indexScreen);
- if (entry.screenId >= mHotseatSize) {
- entriesToRemove.add(entry.id);
- continue;
- }
-
try {
// calculate weight
switch (entry.itemType) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1378a1a..41a760b 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -759,16 +759,13 @@
if (widgetProviderInfo != null
&& (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
|| appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
- logDeleteWidgetInfo(mApp.getInvariantDeviceProfile(),
- widgetProviderInfo);
-
- // This can happen when display size changes.
- c.markDeleted("Widget removed, min sizes not met: "
- + "span=" + appWidgetInfo.spanX + "x"
- + appWidgetInfo.spanY + " minSpan="
+ FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
+ + " minSizes not meet: span=" + appWidgetInfo.spanX
+ + "x" + appWidgetInfo.spanY + " minSpan="
+ widgetProviderInfo.minSpanX + "x"
+ widgetProviderInfo.minSpanY);
- continue;
+ logWidgetInfo(mApp.getInvariantDeviceProfile(),
+ widgetProviderInfo);
}
if (!c.isOnWorkspaceOrHotseat()) {
c.markDeleted("Widget found where container != " +
@@ -989,10 +986,8 @@
}
@SuppressLint("NewApi") // Already added API check.
- private static void logDeleteWidgetInfo(InvariantDeviceProfile idp,
+ private static void logWidgetInfo(InvariantDeviceProfile idp,
LauncherAppWidgetProviderInfo widgetProviderInfo) {
- FileLog.d(TAG, "Deleting " + widgetProviderInfo.getComponent()
- + " due to min size constraint");
Point cellSize = new Point();
for (DeviceProfile deviceProfile : idp.supportedProfiles) {
deviceProfile.getCellSize(cellSize);
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index f7c730a..29eefe2 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -53,6 +53,9 @@
private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
private static final int ENTER_ANIMATION_DURATION = 400;
+ private static final int DOT_ACTIVE_ALPHA = 255;
+ private static final int DOT_INACTIVE_ALPHA = 128;
+
// This value approximately overshoots to 1.5 times the original size.
private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
@@ -75,8 +78,6 @@
private final Paint mCirclePaint;
private final float mDotRadius;
- private final int mActiveColor;
- private final int mInActiveColor;
private final boolean mIsRtl;
private int mNumPages;
@@ -110,12 +111,10 @@
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Style.FILL);
+ mCirclePaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
setOutlineProvider(new MyOutlineProver());
- mActiveColor = Themes.getColorAccent(context);
- mInActiveColor = Themes.getAttrColor(context, android.R.attr.colorControlHighlight);
-
mIsRtl = Utilities.isRtl(getResources());
}
@@ -253,18 +252,18 @@
circleGap = -circleGap;
}
for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
- mCirclePaint.setColor(i == mActivePage ? mActiveColor : mInActiveColor);
+ mCirclePaint.setAlpha(i == mActivePage ? DOT_ACTIVE_ALPHA : DOT_INACTIVE_ALPHA);
canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], mCirclePaint);
x += circleGap;
}
} else {
- mCirclePaint.setColor(mInActiveColor);
+ mCirclePaint.setAlpha(DOT_INACTIVE_ALPHA);
for (int i = 0; i < mNumPages; i++) {
canvas.drawCircle(x, y, mDotRadius, mCirclePaint);
x += circleGap;
}
- mCirclePaint.setColor(mActiveColor);
+ mCirclePaint.setAlpha(DOT_ACTIVE_ALPHA);
canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mCirclePaint);
}
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 223f4f1..8d02a4a 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,6 +16,7 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -38,6 +39,7 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.model.GridBackupTable;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -57,7 +59,7 @@
public class RestoreDbTask {
private static final String TAG = "RestoreDbTask";
- private static final String RESTORE_TASK_PENDING = "restore_task_pending";
+ private static final String RESTORED_DEVICE_TYPE = "restored_task_pending";
private static final String INFO_COLUMN_NAME = "name";
private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
@@ -65,13 +67,33 @@
private static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
private static final String APPWIDGET_IDS = "appwidget_ids";
- public static boolean performRestore(Context context, DatabaseHelper helper,
- BackupManager backupManager) {
+ /**
+ * Tries to restore the backup DB if needed
+ */
+ public static void restoreIfNeeded(Context context, DatabaseHelper helper) {
+ if (!isPending(context)) {
+ return;
+ }
+ if (!performRestore(context, helper)) {
+ helper.createEmptyDB(helper.getWritableDatabase());
+ }
+
+ // Set is pending to false irrespective of the result, so that it doesn't get
+ // executed again.
+ Utilities.getPrefs(context).edit().remove(RESTORED_DEVICE_TYPE).commit();
+ }
+
+ private static boolean performRestore(Context context, DatabaseHelper helper) {
+ if (new DeviceGridState(LauncherAppState.getIDP(context)).getDeviceType()
+ != Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE)) {
+ // DO not restore if the device types are different
+ return false;
+ }
SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.backupWorkspace(context, db);
- task.sanitizeDB(helper, db, backupManager);
+ task.sanitizeDB(helper, db, new BackupManager(context));
task.restoreAppWidgetIdsIfExists(context);
t.commit();
return true;
@@ -279,12 +301,17 @@
}
public static boolean isPending(Context context) {
- return Utilities.getPrefs(context).getBoolean(RESTORE_TASK_PENDING, false);
+ return Utilities.getPrefs(context).contains(RESTORED_DEVICE_TYPE);
}
- public static void setPending(Context context, boolean isPending) {
- FileLog.d(TAG, "Restore data received through full backup " + isPending);
- Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
+ /**
+ * Marks the DB state as pending restoration
+ */
+ public static void setPending(Context context) {
+ FileLog.d(TAG, "Restore data received through full backup ");
+ Utilities.getPrefs(context).edit()
+ .putInt(RESTORED_DEVICE_TYPE, new DeviceGridState(context).getDeviceType())
+ .commit();
}
private void restoreAppWidgetIdsIfExists(Context context) {
diff --git a/src/com/android/launcher3/recyclerview/ViewHolderBinder.java b/src/com/android/launcher3/recyclerview/ViewHolderBinder.java
index 5b8d5bc..6215827 100644
--- a/src/com/android/launcher3/recyclerview/ViewHolderBinder.java
+++ b/src/com/android/launcher3/recyclerview/ViewHolderBinder.java
@@ -17,8 +17,12 @@
import android.view.ViewGroup;
+import androidx.annotation.IntDef;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Creates and populates views with data
*
@@ -26,6 +30,15 @@
* @param <V> A subclass of {@link ViewHolder} which holds references to views.
*/
public interface ViewHolderBinder<T, V extends ViewHolder> {
+
+ int POSITION_DEFAULT = 0;
+ int POSITION_FIRST = 1 << 0;
+ int POSITION_LAST = 1 << 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {POSITION_DEFAULT, POSITION_FIRST, POSITION_LAST}, flag = true)
+ @interface ListPosition {}
+
/**
* Creates a new view, and attach it to the parent {@link ViewGroup}. Then, populates UI
* references in a {@link ViewHolder}.
@@ -33,7 +46,7 @@
V newViewHolder(ViewGroup parent);
/** Populate UI references in {@link ViewHolder} with data. */
- void bindViewHolder(V viewHolder, T data, int position);
+ void bindViewHolder(V viewHolder, T data, @ListPosition int position);
/**
* Called when the view is recycled. Views are recycled in batches once they are sufficiently
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5106992..86acff7 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -62,6 +62,10 @@
}
public Bundle call(String method) {
+ return call(method, /*arg=*/ null);
+ }
+
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT: {
@@ -98,14 +102,22 @@
l -> WidgetsFullSheet.getWidgetsView(l).getCurrentScrollY());
}
+ case TestProtocol.REQUEST_TARGET_INSETS: {
+ return getUIProperty(Bundle::putParcelable, activity -> {
+ WindowInsets insets = activity.getWindow()
+ .getDecorView().getRootWindowInsets();
+ return Insets.max(
+ insets.getSystemGestureInsets(),
+ insets.getSystemWindowInsets());
+ }, this::getCurrentActivity);
+ }
+
case TestProtocol.REQUEST_WINDOW_INSETS: {
- return getUIProperty(Bundle::putParcelable, a -> {
- WindowInsets insets = a.getWindow()
+ return getUIProperty(Bundle::putParcelable, activity -> {
+ WindowInsets insets = activity.getWindow()
.getDecorView().getRootWindowInsets();
return Insets.subtract(
- Insets.max(
- insets.getSystemGestureInsets(),
- insets.getSystemWindowInsets()),
+ insets.getSystemWindowInsets(),
Insets.of(0, 0, 0, mDeviceProfile.nonOverlappingTaskbarInset));
}, this::getCurrentActivity);
}
@@ -126,7 +138,16 @@
case TestProtocol.REQUEST_IS_TWO_PANELS:
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- mDeviceProfile.isTwoPanels);
+ mDeviceProfile.isTwoPanels);
+ return response;
+
+ case TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT:
+ TestProtocol.sForcePauseTimeout = Long.parseLong(arg);
+ return response;
+
+ case TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS:
+ response.putBoolean(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD, TestLogging.sHadEventsNotFromTest);
return response;
default:
diff --git a/src/com/android/launcher3/testing/TestInformationProvider.java b/src/com/android/launcher3/testing/TestInformationProvider.java
index bd177c0..4f2619c 100644
--- a/src/com/android/launcher3/testing/TestInformationProvider.java
+++ b/src/com/android/launcher3/testing/TestInformationProvider.java
@@ -60,7 +60,7 @@
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
TestInformationHandler handler = TestInformationHandler.newInstance(getContext());
handler.init(getContext());
- return handler.call(method);
+ return handler.call(method, arg);
}
return null;
}
diff --git a/src/com/android/launcher3/testing/TestLogging.java b/src/com/android/launcher3/testing/TestLogging.java
index 51e0819..103b565 100644
--- a/src/com/android/launcher3/testing/TestLogging.java
+++ b/src/com/android/launcher3/testing/TestLogging.java
@@ -17,6 +17,8 @@
package com.android.launcher3.testing;
import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import com.android.launcher3.Utilities;
@@ -25,6 +27,7 @@
public final class TestLogging {
private static BiConsumer<String, String> sEventConsumer;
+ public static boolean sHadEventsNotFromTest;
private static void recordEventSlow(String sequence, String event) {
Log.d(TestProtocol.TAPL_EVENTS_TAG, sequence + " / " + event);
@@ -46,9 +49,24 @@
}
}
+ private static void registerEventNotFromTest(InputEvent event) {
+ if (!sHadEventsNotFromTest && event.getDeviceId() != -1) {
+ sHadEventsNotFromTest = true;
+ Log.d(TestProtocol.PERMANENT_DIAG_TAG, "First event not from test: " + event);
+ }
+ }
+
+ public static void recordKeyEvent(String sequence, String message, KeyEvent event) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ recordEventSlow(sequence, message + ": " + event);
+ registerEventNotFromTest(event);
+ }
+ }
+
public static void recordMotionEvent(String sequence, String message, MotionEvent event) {
if (Utilities.IS_RUNNING_IN_TEST_HARNESS && event.getAction() != MotionEvent.ACTION_MOVE) {
recordEventSlow(sequence, message + ": " + event);
+ registerEventNotFromTest(event);
}
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 75c0d03..1c5b31b 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -86,6 +86,7 @@
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
+ public static final String REQUEST_TARGET_INSETS = "target-insets";
public static final String REQUEST_WINDOW_INSETS = "window-insets";
public static final String REQUEST_PID = "pid";
public static final String REQUEST_FORCE_GC = "gc";
@@ -93,11 +94,15 @@
public static final String REQUEST_RECENT_TASKS_LIST = "recent-tasks-list";
public static final String REQUEST_START_EVENT_LOGGING = "start-event-logging";
public static final String REQUEST_GET_TEST_EVENTS = "get-test-events";
+ public static final String REQUEST_GET_HAD_NONTEST_EVENTS = "get-had-nontest-events";
public static final String REQUEST_STOP_EVENT_LOGGING = "stop-event-logging";
public static final String REQUEST_CLEAR_DATA = "clear-data";
public static final String REQUEST_IS_TABLET = "is-tablet";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
+ public static Long sForcePauseTimeout;
+ public static final String REQUEST_SET_FORCE_PAUSE_TIMEOUT = "set-force-pause-timeout";
+
public static boolean sDebugTracing = false;
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
@@ -113,4 +118,5 @@
public static final String WORK_PROFILE_REMOVED = "b/159671700";
public static final String FALLBACK_ACTIVITY_NO_SET = "b/181019015";
public static final String THIRD_PARTY_LAUNCHER_NOT_SET = "b/187080582";
+ public static final String TASK_VIEW_ID_CRASH = "b/195430732";
}
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
index b8554e4..c51f66f 100644
--- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -63,31 +63,37 @@
*
* TODO: do different behavior if it's a live wallpaper?
*/
- private void wallpaperOffsetForScroll(int scroll, int numScrollingPages, final int[] out) {
+ private void wallpaperOffsetForScroll(int scroll, int numScrollableScreens, final int[] out) {
out[1] = 1;
// To match the default wallpaper behavior in the system, we default to either the left
// or right edge on initialization
- if (mLockedToDefaultPage || numScrollingPages <= 1) {
+ if (mLockedToDefaultPage || numScrollableScreens <= 1) {
out[0] = mIsRtl ? 1 : 0;
return;
}
// Distribute the wallpaper parallax over a minimum of MIN_PARALLAX_PAGE_SPAN workspace
// screens, not including the custom screen, and empty screens (if > MIN_PARALLAX_PAGE_SPAN)
- int numPagesForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollingPages :
- Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages);
+ int numScreensForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollableScreens :
+ Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollableScreens);
// Offset by the custom screen
- int leftPageIndex;
- int rightPageIndex;
- if (mIsRtl) {
- rightPageIndex = 0;
- leftPageIndex = rightPageIndex + numScrollingPages - 1;
- } else {
- leftPageIndex = 0;
- rightPageIndex = leftPageIndex + numScrollingPages - 1;
- }
+
+ // Don't confuse screens & pages in this function. In a phone UI, we often use screens &
+ // pages interchangeably. However, in a n-panels UI, where n > 1, the screen in this class
+ // means the scrollable screen. Each screen can consist of at most n panels.
+ // Each panel has at most 1 page. Take 5 pages in 2 panels UI as an example, the Workspace
+ // looks as follow:
+ //
+ // S: scrollable screen, P: page, <E>: empty
+ // S0 S1 S2
+ // _______ _______ ________
+ // |P0|P1| |P2|P3| |P4|<E>|
+ // ¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯
+ int endIndex = getNumPagesExcludingEmpty() - 1;
+ final int leftPageIndex = mIsRtl ? endIndex : 0;
+ final int rightPageIndex = mIsRtl ? 0 : endIndex;
// Calculate the scroll range
int leftPageScrollX = mWorkspace.getScrollForPage(leftPageIndex);
@@ -103,34 +109,56 @@
int adjustedScroll = scroll - leftPageScrollX -
mWorkspace.getLayoutTransitionOffsetForPage(0);
adjustedScroll = Utilities.boundToRange(adjustedScroll, 0, scrollRange);
- out[1] = (numPagesForWallpaperParallax - 1) * scrollRange;
+ out[1] = (numScreensForWallpaperParallax - 1) * scrollRange;
// The offset is now distributed 0..1 between the left and right pages that we care about,
// so we just map that between the pages that we are using for parallax
int rtlOffset = 0;
if (mIsRtl) {
// In RTL, the pages are right aligned, so adjust the offset from the end
- rtlOffset = out[1] - (numScrollingPages - 1) * scrollRange;
+ rtlOffset = out[1] - (numScrollableScreens - 1) * scrollRange;
}
- out[0] = rtlOffset + adjustedScroll * (numScrollingPages - 1);
+ out[0] = rtlOffset + adjustedScroll * (numScrollableScreens - 1);
}
public float wallpaperOffsetForScroll(int scroll) {
- wallpaperOffsetForScroll(scroll, getNumScreensExcludingEmpty(), sTempInt);
+ wallpaperOffsetForScroll(scroll, getNumScrollableScreensExcludingEmpty(), sTempInt);
return ((float) sTempInt[0]) / sTempInt[1];
}
- private int getNumScreensExcludingEmpty() {
- int numScrollingPages = mWorkspace.getChildCount();
- if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
- return numScrollingPages - 1;
+ /**
+ * Returns the number of screens that can be scrolled.
+ *
+ * <p>In an usual phone UI, the number of scrollable screens is equal to the number of
+ * CellLayouts because each screen has exactly 1 CellLayout.
+ *
+ * <p>In a n-panels UI, a screen shows n panels. Each panel has at most 1 CellLayout. Take
+ * 2-panels UI as an example: let's say there are 5 CellLayouts in the Workspace. the number of
+ * scrollable screens will be 3 = ⌈5 / 2⌉.
+ */
+ private int getNumScrollableScreensExcludingEmpty() {
+ float numOfPages = getNumPagesExcludingEmpty();
+ return (int) Math.ceil(numOfPages / mWorkspace.getPanelCount());
+ }
+
+ /**
+ * Returns the number of non-empty pages in the Workspace.
+ *
+ * <p>If a user starts dragging on the rightmost (or leftmost in RTL), an empty CellLayout is
+ * added to the Workspace. This empty CellLayout add as a hover-over target for adding a new
+ * page. To avoid janky motion effect, we ignore this empty CellLayout.
+ */
+ private int getNumPagesExcludingEmpty() {
+ int numOfPages = mWorkspace.getChildCount();
+ if (numOfPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
+ return numOfPages - 1;
} else {
- return numScrollingPages;
+ return numOfPages;
}
}
public void syncWithScroll() {
- int numScreens = getNumScreensExcludingEmpty();
+ int numScreens = getNumScrollableScreensExcludingEmpty();
wallpaperOffsetForScroll(mWorkspace.getScrollX(), numScreens, sTempInt);
Message msg = Message.obtain(mHandler, MSG_UPDATE_OFFSET, sTempInt[0], sTempInt[1],
mWindowToken);
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 92ca8a1..8ac40b8 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -28,6 +28,7 @@
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import com.android.launcher3.AbstractFloatingView;
@@ -68,7 +69,7 @@
protected final SingleAxisSwipeDetector mSwipeDetector;
protected final ObjectAnimator mOpenCloseAnimator;
- protected View mContent;
+ protected ViewGroup mContent;
protected final View mColorScrim;
protected Interpolator mScrollInterpolator;
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 1c2534d..2b0f707 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -40,7 +40,6 @@
import android.view.WindowInsets;
import android.widget.TextView;
-import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.RecyclerView;
@@ -131,7 +130,6 @@
protected BaseRecyclerView mRv;
private RecyclerView.OnScrollListener mOnScrollListener;
- @Nullable private OnFastScrollChangeListener mOnFastScrollChangeListener;
private int mDownX;
private int mDownY;
@@ -208,7 +206,6 @@
int rvCurrentOffsetY = mRv.getCurrentScrollY();
if (mRvOffsetY != rvCurrentOffsetY) {
mRvOffsetY = mRv.getCurrentScrollY();
- notifyScrollChanged();
}
return;
}
@@ -216,7 +213,6 @@
mThumbOffsetY = y;
invalidate();
mRvOffsetY = mRv.getCurrentScrollY();
- notifyScrollChanged();
}
public int getThumbOffsetY() {
@@ -461,23 +457,4 @@
public void setIsRecyclerViewFirstChildInParent(boolean isRecyclerViewFirstChildInParent) {
mIsRecyclerViewFirstChildInParent = isRecyclerViewFirstChildInParent;
}
-
- public void setOnFastScrollChangeListener(
- @Nullable OnFastScrollChangeListener onFastScrollChangeListener) {
- mOnFastScrollChangeListener = onFastScrollChangeListener;
- }
-
- private void notifyScrollChanged() {
- if (mOnFastScrollChangeListener != null) {
- mOnFastScrollChangeListener.onScrollChanged();
- }
- }
-
- /**
- * A callback that is invoked when there is a scroll change in {@link RecyclerViewFastScroller}.
- */
- public interface OnFastScrollChangeListener {
- /** Called when the recycler view scroll has changed. */
- void onScrollChanged();
- }
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 1eb79ad..4c0bfde 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -25,23 +25,27 @@
import android.util.AttributeSet;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.Insettable;
import com.android.launcher3.util.SystemUiController;
+import java.util.ArrayList;
+
/**
* Simple scrim which draws a flat color
*/
public class ScrimView extends View implements Insettable {
private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.9f;
+ private final ArrayList<Runnable> mOpaquenessListeners = new ArrayList<>(1);
private SystemUiController mSystemUiController;
-
private ScrimDrawingController mDrawingController;
private int mBackgroundColor;
private boolean mIsVisible = true;
+ private boolean mLastDispatchedOpaqueness;
public ScrimView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -60,6 +64,7 @@
@Override
protected boolean onSetAlpha(int alpha) {
updateSysUiColors();
+ dispatchVisibilityListenersIfNeeded();
return super.onSetAlpha(alpha);
}
@@ -67,6 +72,7 @@
public void setBackgroundColor(int color) {
mBackgroundColor = color;
updateSysUiColors();
+ dispatchVisibilityListenersIfNeeded();
super.setBackgroundColor(color);
}
@@ -74,6 +80,7 @@
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
mIsVisible = isVisible;
+ dispatchVisibilityListenersIfNeeded();
}
public boolean isFullyOpaque() {
@@ -108,6 +115,17 @@
}
}
+ private void dispatchVisibilityListenersIfNeeded() {
+ boolean fullyOpaque = isFullyOpaque();
+ if (mLastDispatchedOpaqueness == fullyOpaque) {
+ return;
+ }
+ mLastDispatchedOpaqueness = fullyOpaque;
+ for (int i = 0; i < mOpaquenessListeners.size(); i++) {
+ mOpaquenessListeners.get(i).run();
+ }
+ }
+
private SystemUiController getSystemUiController() {
if (mSystemUiController == null) {
mSystemUiController = BaseActivity.fromContext(getContext()).getSystemUiController();
@@ -136,6 +154,22 @@
}
/**
+ * Registers a listener to be notified of whether the scrim is occluding other UI elements.
+ * @see #isFullyOpaque()
+ */
+ public void addOpaquenessListener(@NonNull Runnable listener) {
+ mOpaquenessListeners.add(listener);
+ }
+
+ /**
+ * Removes previously registered listener.
+ * @see #addOpaquenessListener(Runnable)
+ */
+ public void removeOpaquenessListener(@NonNull Runnable listener) {
+ mOpaquenessListeners.remove(listener);
+ }
+
+ /**
* A Utility interface allowing for other surfaces to draw on ScrimView
*/
public interface ScrimDrawingController {
diff --git a/src/com/android/launcher3/views/TopRoundedCornerView.java b/src/com/android/launcher3/views/TopRoundedCornerView.java
deleted file mode 100644
index 92cce92..0000000
--- a/src/com/android/launcher3/views/TopRoundedCornerView.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 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.views;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-
-import com.android.launcher3.util.Themes;
-
-/**
- * View with top rounded corners.
- */
-public class TopRoundedCornerView extends SpringRelativeLayout {
-
- private final RectF mRect = new RectF();
- private final Path mClipPath = new Path();
- private float[] mRadii;
-
- public TopRoundedCornerView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- float radius = Themes.getDialogCornerRadius(context);
- mRadii = new float[] {radius, radius, radius, radius, 0, 0, 0, 0};
- }
-
- public TopRoundedCornerView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- @Override
- public void draw(Canvas canvas) {
- canvas.save();
- canvas.clipPath(mClipPath);
- super.draw(canvas);
- canvas.restore();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
- mClipPath.reset();
- mClipPath.addRoundRect(mRect, mRadii, Path.Direction.CW);
- }
-}
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index d12fe74..241c937 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -49,6 +49,8 @@
*/
private final PointF mTranslationForCentering = new PointF(0, 0);
+ private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
+
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
private float mScaleForReorderBounce = 1f;
@@ -167,9 +169,9 @@
private void updateTranslation() {
super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
- + mTranslationForCentering.x);
+ + mTranslationForCentering.x + mTranslationForMoveFromCenterAnimation.x);
super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
- + mTranslationForCentering.y);
+ + mTranslationForCentering.y + mTranslationForMoveFromCenterAnimation.y);
}
public void setTranslationForCentering(float x, float y) {
@@ -177,6 +179,11 @@
updateTranslation();
}
+ public void setTranslationForMoveFromCenterAnimation(float x, float y) {
+ mTranslationForMoveFromCenterAnimation.set(x, y);
+ updateTranslation();
+ }
+
public void setReorderBounceOffset(float x, float y) {
mTranslationForReorderBounce.set(x, y);
updateTranslation();
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index d3a0190..57a6d3f 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -85,7 +85,7 @@
setBackgroundResource(R.drawable.pending_widget_bg);
setWillNotDraw(false);
- updateAppWidget(null);
+ super.updateAppWidget(null);
setOnClickListener(ItemClickHandler.INSTANCE);
if (info.pendingItemInfo == null) {
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 167eb09..bd444db 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -325,10 +325,10 @@
return;
}
if (drawable != null) {
+ // Scale down the preview size if it's wider than the cell.
float scale = 1f;
- if (getWidth() > 0 && getHeight() > 0) {
- // Scale down the preview size if it's wider than the cell.
- float maxWidth = getWidth();
+ if (mTargetPreviewWidth > 0) {
+ float maxWidth = mTargetPreviewWidth;
float previewWidth = drawable.getIntrinsicWidth() * mPreviewContainerScale;
scale = Math.min(maxWidth / previewWidth, 1);
}
@@ -483,6 +483,20 @@
mAppWidgetHostViewPreview.measure(
makeMeasureSpec(MAX_MEASURE_SPEC_DIMENSION, MeasureSpec.UNSPECIFIED),
makeMeasureSpec(MAX_MEASURE_SPEC_DIMENSION, MeasureSpec.UNSPECIFIED));
+ if (mRemoteViewsPreview != null) {
+ // If RemoteViews contains multiple sizes, the best fit sized RemoteViews will be
+ // selected in onLayout. To work out the right measurement, let's layout and then
+ // measure again.
+ mAppWidgetHostViewPreview.layout(
+ /* left= */ 0,
+ /* top= */ 0,
+ /* right= */ mTargetPreviewWidth,
+ /* bottom= */ mTargetPreviewHeight);
+ mAppWidgetHostViewPreview.measure(
+ makeMeasureSpec(mTargetPreviewWidth, MeasureSpec.UNSPECIFIED),
+ makeMeasureSpec(mTargetPreviewHeight, MeasureSpec.UNSPECIFIED));
+
+ }
View widgetContent = mAppWidgetHostViewPreview.getChildAt(0);
int appWidgetContentWidth = widgetContent.getMeasuredWidth();
int appWidgetContentHeight = widgetContent.getMeasuredHeight();
diff --git a/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java
new file mode 100644
index 0000000..e62425f
--- /dev/null
+++ b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.widget.model;
+
+import com.android.launcher3.model.data.PackageItemInfo;
+
+import java.util.Collections;
+
+/**
+ * Entry representing the top empty space
+ */
+public class WidgetListSpaceEntry extends WidgetsListBaseEntry {
+
+ public WidgetListSpaceEntry() {
+ super(new PackageItemInfo(""), "", Collections.EMPTY_LIST);
+ mPkgItem.title = "";
+ }
+
+ @Override
+ public int getRank() {
+ return RANK_WIDGETS_TOP_SPACE;
+ }
+}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
index abc79ff..1d1c9dc 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
@@ -73,11 +73,13 @@
}
@Retention(SOURCE)
- @IntDef({RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER, RANK_WIDGETS_LIST_CONTENT})
+ @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER,
+ RANK_WIDGETS_LIST_CONTENT})
public @interface Rank {
}
- public static final int RANK_WIDGETS_LIST_HEADER = 1;
- public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 2;
- public static final int RANK_WIDGETS_LIST_CONTENT = 3;
+ public static final int RANK_WIDGETS_TOP_SPACE = 1;
+ public static final int RANK_WIDGETS_LIST_HEADER = 2;
+ public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 3;
+ public static final int RANK_WIDGETS_LIST_CONTENT = 4;
}
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
index 6643779..716dcf3 100644
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -15,297 +15,148 @@
*/
package com.android.launcher3.widget.picker;
-import android.animation.ValueAnimator;
-import android.graphics.Point;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.util.FloatProperty;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.widget.RelativeLayout;
+import android.view.ViewGroup;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.views.RecyclerViewFastScroller;
-import com.android.launcher3.widget.picker.WidgetsFullSheet.SearchAndRecommendationViewHolder;
-import com.android.launcher3.workprofile.PersonalWorkPagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.widget.picker.WidgetsSpaceViewHolderBinder.EmptySpaceView;
+import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
/**
* A controller which measures & updates {@link WidgetsFullSheet}'s views padding, margin and
* vertical displacement upon scrolling.
*/
final class SearchAndRecommendationsScrollController implements
- RecyclerViewFastScroller.OnFastScrollChangeListener, ValueAnimator.AnimatorUpdateListener {
- private final boolean mHasWorkProfile;
- private final SearchAndRecommendationViewHolder mViewHolder;
- private final View mSearchAndRecommendationViewParent;
- private final WidgetsRecyclerView mPrimaryRecyclerView;
- private final WidgetsRecyclerView mSearchRecyclerView;
- private final TextView mNoWidgetsView;
- private final int mTabsHeight;
- private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
- private final Point mTempOffset = new Point();
- private int mBottomInset;
+ RecyclerView.OnChildAttachStateChangeListener {
- // The following are only non null if mHasWorkProfile is true.
- @Nullable private final WidgetsRecyclerView mWorkRecyclerView;
- @Nullable private final View mPrimaryWorkTabsView;
- @Nullable private final PersonalWorkPagedView mPrimaryWorkViewPager;
+ private static final FloatProperty<SearchAndRecommendationsScrollController> SCROLL_OFFSET =
+ new FloatProperty<SearchAndRecommendationsScrollController>("scrollAnimOffset") {
+ @Override
+ public void setValue(SearchAndRecommendationsScrollController controller, float offset) {
+ controller.mScrollOffset = offset;
+ controller.updateHeaderScroll();
+ }
+
+ @Override
+ public Float get(SearchAndRecommendationsScrollController controller) {
+ return controller.mScrollOffset;
+ }
+ };
+
+ private static final MotionEventProxyMethod INTERCEPT_PROXY = ViewGroup::onInterceptTouchEvent;
+ private static final MotionEventProxyMethod TOUCH_PROXY = ViewGroup::onTouchEvent;
+
+ final SearchAndRecommendationsView mContainer;
+ final View mSearchBarContainer;
+ final WidgetsSearchBar mSearchBar;
+ final TextView mHeaderTitle;
+ final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ @Nullable final View mTabBar;
private WidgetsRecyclerView mCurrentRecyclerView;
- private int mCurrentRecyclerViewScrollY = 0;
+ private EmptySpaceView mCurrentEmptySpaceView;
- private OnContentChangeListener mOnContentChangeListener = () -> onScrollChanged();
-
- /**
- * The vertical distance, in pixels, until the search is pinned at the top of the screen when
- * the user scrolls down the recycler view.
- */
- private int mCollapsibleHeightForSearch = 0;
- /**
- * The vertical distance, in pixels, until the recommendation table disappears from the top of
- * the screen when the user scrolls down the recycler view.
- */
- private int mCollapsibleHeightForRecommendation = 0;
- /**
- * The vertical distance, in pixels, until the tabs is pinned at the top of the screen when the
- * user scrolls down the recycler view.
- *
- * <p>Always 0 if there is no work profile.
- */
- private int mCollapsibleHeightForTabs = 0;
+ private float mLastScroll = 0;
+ private float mScrollOffset = 0;
+ private Animator mOffsetAnimator;
private boolean mShouldForwardToRecyclerView = false;
+ private int mHeaderHeight;
+
SearchAndRecommendationsScrollController(
- boolean hasWorkProfile,
- int tabsHeight,
- SearchAndRecommendationViewHolder viewHolder,
- WidgetsRecyclerView primaryRecyclerView,
- @Nullable WidgetsRecyclerView workRecyclerView,
- WidgetsRecyclerView searchRecyclerView,
- @Nullable View personalWorkTabsView,
- @Nullable PersonalWorkPagedView primaryWorkViewPager,
- TextView noWidgetsView) {
- mHasWorkProfile = hasWorkProfile;
- mViewHolder = viewHolder;
- mViewHolder.mContainer.setSearchAndRecommendationScrollController(this);
- mSearchAndRecommendationViewParent = (View) mViewHolder.mContainer.getParent();
- mPrimaryRecyclerView = primaryRecyclerView;
- mWorkRecyclerView = workRecyclerView;
- mSearchRecyclerView = searchRecyclerView;
- mPrimaryWorkTabsView = personalWorkTabsView;
- mPrimaryWorkViewPager = primaryWorkViewPager;
- mTabsHeight = tabsHeight;
- mNoWidgetsView = noWidgetsView;
- setCurrentRecyclerView(mPrimaryRecyclerView, /* animateReset= */ false);
+ SearchAndRecommendationsView searchAndRecommendationContainer) {
+ mContainer = searchAndRecommendationContainer;
+ mSearchBarContainer = mContainer.findViewById(R.id.search_bar_container);
+ mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
+ mHeaderTitle = mContainer.findViewById(R.id.title);
+ mRecommendedWidgetsTable = mContainer.findViewById(R.id.recommended_widget_table);
+ mTabBar = mContainer.findViewById(R.id.tabs);
+
+ mContainer.setSearchAndRecommendationScrollController(this);
}
public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
- setCurrentRecyclerView(currentRecyclerView, /* animateReset= */ true);
- }
-
- /** Sets the current active {@link WidgetsRecyclerView}. */
- private void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView,
- boolean animateReset) {
- if (mCurrentRecyclerView == currentRecyclerView) {
- return;
- }
+ boolean animateReset = mCurrentRecyclerView != null;
if (mCurrentRecyclerView != null) {
- mCurrentRecyclerView.setOnContentChangeListener(null);
+ mCurrentRecyclerView.removeOnChildAttachStateChangeListener(this);
}
mCurrentRecyclerView = currentRecyclerView;
- mCurrentRecyclerView.setOnContentChangeListener(mOnContentChangeListener);
+ mCurrentRecyclerView.addOnChildAttachStateChangeListener(this);
+ findCurrentEmptyView();
reset(animateReset);
}
- /**
- * Updates padding of {@link WidgetsFullSheet} contents to include {@code bottomInset} wherever
- * necessary.
- */
- public boolean updateBottomInset(int bottomInset) {
- mBottomInset = bottomInset;
- return updateMarginAndPadding();
+ public int getHeaderHeight() {
+ return mHeaderHeight;
+ }
+
+ private void updateHeaderScroll() {
+ mLastScroll = getCurrentScroll();
+ mHeaderTitle.setTranslationY(mLastScroll);
+ mRecommendedWidgetsTable.setTranslationY(mLastScroll);
+
+ float searchYDisplacement = Math.max(mLastScroll, -mSearchBarContainer.getTop());
+ mSearchBarContainer.setTranslationY(searchYDisplacement);
+
+ if (mTabBar != null) {
+ float tabsDisplacement = Math.max(mLastScroll, -mTabBar.getTop()
+ + mSearchBarContainer.getHeight());
+ mTabBar.setTranslationY(tabsDisplacement);
+ }
+ }
+
+ private float getCurrentScroll() {
+ return mScrollOffset + (mCurrentEmptySpaceView == null ? 0 : mCurrentEmptySpaceView.getY());
}
/**
- * Updates the margin and padding of {@link WidgetsFullSheet} to accumulate collapsible views.
+ * Updates the scrollable header height
*
- * @return {@code true} if margins or/and padding of views in the search and recommendations
- * container have been updated.
+ * @return {@code true} if the header height or dependent property changed.
*/
- public boolean updateMarginAndPadding() {
- boolean hasMarginOrPaddingUpdated = false;
- mCollapsibleHeightForSearch = measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle);
- mCollapsibleHeightForRecommendation =
- measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle)
- + measureHeightWithVerticalMargins(mViewHolder.mCollapseHandle)
- + measureHeightWithVerticalMargins((View) mViewHolder.mSearchBarContainer)
- + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable);
+ public boolean updateHeaderHeight() {
+ boolean hasSizeUpdated = false;
- int topContainerHeight = measureHeightWithVerticalMargins(mViewHolder.mContainer);
- int noWidgetsViewHeight = topContainerHeight - mBottomInset;
-
- if (mHasWorkProfile) {
- mCollapsibleHeightForTabs = measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle)
- + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable);
- // In a work profile setup, the full widget sheet contains the following views:
- // ------- (pinned) -|
- // Widgets (collapsible) -|---> LinearLayout for search & recommendations
- // Search bar (pinned) -|
- // Widgets recommendation (collapsible)-|
- // Personal | Work (pinned)
- // View Pager
- //
- // Views after the search & recommendations are not bound by RelativelyLayout param.
- // To position them on the expected location, padding & margin are added to these views
-
- // Tabs should have a padding of the height of the search & recommendations container.
- RelativeLayout.LayoutParams tabsLayoutParams =
- (RelativeLayout.LayoutParams) mPrimaryWorkTabsView.getLayoutParams();
- tabsLayoutParams.topMargin = topContainerHeight;
- mPrimaryWorkTabsView.setLayoutParams(tabsLayoutParams);
-
- // Instead of setting the top offset directly, we split the top offset into two values:
- // 1. topOffsetAfterAllViewsCollapsed: this is the top offset after all collapsible
- // views are no longer visible on the screen.
- // This value is set as the margin for the view pager.
- // 2. mMaxCollapsibleDistance
- // This value is set as the padding for the recycler views in order to work with
- // clipToPadding="false", which is an attribute for not showing top / bottom padding
- // when a recycler view has not reached the top or bottom of the list.
- // e.g. a list of 10 entries, only 3 entries are visible at a time.
- // case 1: recycler view is scrolled to the top. Top padding is visible/
- // (top padding)
- // item 1
- // item 2
- // item 3
- //
- // case 2: recycler view is scrolled to the middle. No padding is visible.
- // item 4
- // item 5
- // item 6
- //
- // case 3: recycler view is scrolled to the end. bottom padding is visible.
- // item 8
- // item 9
- // item 10
- // (bottom padding): not set in this case.
- //
- // When the views are first inflated, the sum of topOffsetAfterAllViewsCollapsed and
- // mMaxCollapsibleDistance should equal to the top container height.
- int topOffsetAfterAllViewsCollapsed =
- topContainerHeight + mTabsHeight - mCollapsibleHeightForTabs;
-
- if (mPrimaryWorkTabsView.getVisibility() == View.VISIBLE) {
- noWidgetsViewHeight += mTabsHeight;
- }
-
- RelativeLayout.LayoutParams viewPagerLayoutParams =
- (RelativeLayout.LayoutParams) mPrimaryWorkViewPager.getLayoutParams();
- if (viewPagerLayoutParams.topMargin != topOffsetAfterAllViewsCollapsed) {
- viewPagerLayoutParams.topMargin = topOffsetAfterAllViewsCollapsed;
- mPrimaryWorkViewPager.setLayoutParams(viewPagerLayoutParams);
- hasMarginOrPaddingUpdated = true;
- }
-
- if (mPrimaryRecyclerView.getPaddingTop() != mCollapsibleHeightForTabs) {
- mPrimaryRecyclerView.setPadding(
- mPrimaryRecyclerView.getPaddingLeft(),
- mCollapsibleHeightForTabs,
- mPrimaryRecyclerView.getPaddingRight(),
- mPrimaryRecyclerView.getPaddingBottom());
- hasMarginOrPaddingUpdated = true;
- }
- if (mWorkRecyclerView.getPaddingTop() != mCollapsibleHeightForTabs) {
- mWorkRecyclerView.setPadding(
- mWorkRecyclerView.getPaddingLeft(),
- mCollapsibleHeightForTabs,
- mWorkRecyclerView.getPaddingRight(),
- mWorkRecyclerView.getPaddingBottom());
- hasMarginOrPaddingUpdated = true;
- }
- } else {
- if (mPrimaryRecyclerView.getPaddingTop() != topContainerHeight) {
- mPrimaryRecyclerView.setPadding(
- mPrimaryRecyclerView.getPaddingLeft(),
- topContainerHeight,
- mPrimaryRecyclerView.getPaddingRight(),
- mPrimaryRecyclerView.getPaddingBottom());
- hasMarginOrPaddingUpdated = true;
- }
- }
- if (mSearchRecyclerView.getPaddingTop() != topContainerHeight) {
- mSearchRecyclerView.setPadding(
- mSearchRecyclerView.getPaddingLeft(),
- topContainerHeight,
- mSearchRecyclerView.getPaddingRight(),
- mSearchRecyclerView.getPaddingBottom());
- hasMarginOrPaddingUpdated = true;
- }
- if (mNoWidgetsView.getPaddingTop() != noWidgetsViewHeight) {
- mNoWidgetsView.setPadding(
- mNoWidgetsView.getPaddingLeft(),
- noWidgetsViewHeight,
- mNoWidgetsView.getPaddingRight(),
- mNoWidgetsView.getPaddingBottom());
- hasMarginOrPaddingUpdated = true;
- }
- return hasMarginOrPaddingUpdated;
- }
-
- @Override
- public void onScrollChanged() {
- int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY();
- if (recyclerViewYOffset < 0) return;
- mCurrentRecyclerViewScrollY = recyclerViewYOffset;
- if (mAnimator.isStarted()) {
- mAnimator.cancel();
- }
- applyVerticalTransition();
- }
-
- /**
- * Changes the displacement of collapsible views (e.g. title & widget recommendations) and fixed
- * views (e.g. recycler views, tabs) upon scrolling / content changes in the recycler view.
- */
- private void applyVerticalTransition() {
- if (mCollapsibleHeightForRecommendation > 0) {
- int yDisplacement = Math.max(-mCurrentRecyclerViewScrollY,
- -mCollapsibleHeightForRecommendation);
- mViewHolder.mHeaderTitle.setTranslationY(yDisplacement);
- mViewHolder.mRecommendedWidgetsTable.setTranslationY(yDisplacement);
+ int headerHeight = mContainer.getMeasuredHeight();
+ if (headerHeight != mHeaderHeight) {
+ mHeaderHeight = headerHeight;
+ hasSizeUpdated = true;
}
- if (mCollapsibleHeightForSearch > 0) {
- int searchYDisplacement = Math.max(-mCurrentRecyclerViewScrollY,
- -mCollapsibleHeightForSearch);
- mViewHolder.mSearchBarContainer.setTranslationY(searchYDisplacement);
+ if (mCurrentEmptySpaceView != null
+ && mCurrentEmptySpaceView.setFixedHeight(mHeaderHeight)) {
+ hasSizeUpdated = true;
}
-
- if (mHasWorkProfile && mCollapsibleHeightForTabs > 0) {
- int yDisplacementForTabs = Math.max(-mCurrentRecyclerViewScrollY,
- -mCollapsibleHeightForTabs);
- mPrimaryWorkTabsView.setTranslationY(yDisplacementForTabs);
- }
+ return hasSizeUpdated;
}
/** Resets any previous view translation. */
public void reset(boolean animate) {
- if (mCurrentRecyclerViewScrollY == 0) {
- return;
- }
- if (mAnimator.isStarted()) {
- mAnimator.cancel();
+ if (mOffsetAnimator != null) {
+ mOffsetAnimator.cancel();
+ mOffsetAnimator = null;
}
- if (animate) {
- mAnimator.setIntValues(mCurrentRecyclerViewScrollY, 0);
- mAnimator.addUpdateListener(this);
- mAnimator.setDuration(300);
- mAnimator.start();
+ mScrollOffset = 0;
+ if (!animate) {
+ updateHeaderScroll();
} else {
- mCurrentRecyclerViewScrollY = 0;
- applyVerticalTransition();
+ float startValue = mLastScroll - getCurrentScroll();
+ mOffsetAnimator = ObjectAnimator.ofFloat(this, SCROLL_OFFSET, startValue, 0);
+ mOffsetAnimator.addListener(forEndCallback(() -> mOffsetAnimator = null));
+ mOffsetAnimator.start();
}
}
@@ -313,61 +164,60 @@
* Returns {@code true} if a touch event should be intercepted by this controller.
*/
public boolean onInterceptTouchEvent(MotionEvent event) {
- calculateMotionEventOffset(mTempOffset);
- event.offsetLocation(mTempOffset.x, mTempOffset.y);
- try {
- mShouldForwardToRecyclerView = mCurrentRecyclerView.onInterceptTouchEvent(event);
- return mShouldForwardToRecyclerView;
- } finally {
- event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
- }
+ return (mShouldForwardToRecyclerView = proxyMotionEvent(event, INTERCEPT_PROXY));
}
/**
* Returns {@code true} if this controller has intercepted and consumed a touch event.
*/
public boolean onTouchEvent(MotionEvent event) {
- if (mShouldForwardToRecyclerView) {
- calculateMotionEventOffset(mTempOffset);
- event.offsetLocation(mTempOffset.x, mTempOffset.y);
- try {
- return mCurrentRecyclerView.onTouchEvent(event);
- } finally {
- event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
- }
- }
- return false;
+ return mShouldForwardToRecyclerView && proxyMotionEvent(event, TOUCH_PROXY);
}
- private void calculateMotionEventOffset(Point p) {
- p.x = mViewHolder.mContainer.getLeft() - mCurrentRecyclerView.getLeft()
- - mSearchAndRecommendationViewParent.getLeft();
- p.y = mViewHolder.mContainer.getTop() - mCurrentRecyclerView.getTop()
- - mSearchAndRecommendationViewParent.getTop();
- }
-
- /** private the height, in pixel, + the vertical margins of a given view. */
- private static int measureHeightWithVerticalMargins(View view) {
- if (view.getVisibility() != View.VISIBLE) {
- return 0;
+ private boolean proxyMotionEvent(MotionEvent event, MotionEventProxyMethod method) {
+ float dx = mCurrentRecyclerView.getLeft() - mContainer.getLeft();
+ float dy = mCurrentRecyclerView.getTop() - mContainer.getTop();
+ event.offsetLocation(dx, dy);
+ try {
+ return method.proxyEvent(mCurrentRecyclerView, event);
+ } finally {
+ event.offsetLocation(-dx, -dy);
}
- MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
- return view.getMeasuredHeight() + marginLayoutParams.bottomMargin
- + marginLayoutParams.topMargin;
}
@Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mCurrentRecyclerViewScrollY = (Integer) animation.getAnimatedValue();
- applyVerticalTransition();
+ public void onChildViewAttachedToWindow(@NonNull View view) {
+ if (view instanceof EmptySpaceView) {
+ findCurrentEmptyView();
+ }
}
- /**
- * A listener to be notified when there is a content change in the recycler view that may affect
- * the relative position of the search and recommendation container.
- */
- public interface OnContentChangeListener {
- /** Notifies a content change in the recycler view. */
- void onContentChanged();
+ @Override
+ public void onChildViewDetachedFromWindow(@NonNull View view) {
+ if (view == mCurrentEmptySpaceView) {
+ findCurrentEmptyView();
+ }
+ }
+
+ private void findCurrentEmptyView() {
+ if (mCurrentEmptySpaceView != null) {
+ mCurrentEmptySpaceView.setOnYChangeCallback(null);
+ mCurrentEmptySpaceView = null;
+ }
+ int childCount = mCurrentRecyclerView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View view = mCurrentRecyclerView.getChildAt(i);
+ if (view instanceof EmptySpaceView) {
+ mCurrentEmptySpaceView = (EmptySpaceView) view;
+ mCurrentEmptySpaceView.setFixedHeight(getHeaderHeight());
+ mCurrentEmptySpaceView.setOnYChangeCallback(this::updateHeaderScroll);
+ return;
+ }
+ }
+ }
+
+ private interface MotionEventProxyMethod {
+
+ boolean proxyEvent(ViewGroup view, MotionEvent event);
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index be83f9a..9dbfa87 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -57,13 +57,12 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
-import com.android.launcher3.views.TopRoundedCornerView;
+import com.android.launcher3.views.SpringRelativeLayout;
import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
-import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.util.WidgetsTableUtils;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -79,7 +78,6 @@
public class WidgetsFullSheet extends BaseWidgetSheet
implements ProviderChangedListener, OnActivePageChangedListener,
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
- private static final String TAG = WidgetsFullSheet.class.getSimpleName();
private static final long DEFAULT_OPEN_DURATION = 267;
private static final long FADE_IN_DURATION = 150;
@@ -149,8 +147,6 @@
};
private final int mTabsHeight;
- private final int mViewPagerTopPadding;
- private final int mSearchAndRecommendationContainerBottomMargin;
private final int mWidgetSheetContentHorizontalPadding;
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
@@ -158,10 +154,8 @@
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
private int mMaxSpansPerRow = DEFAULT_MAX_HORIZONTAL_SPANS;
- private View mTabsView;
private TextView mNoWidgetsView;
- private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
- private SearchAndRecommendationsScrollController mSearchAndRecommendationsScrollController;
+ private SearchAndRecommendationsScrollController mSearchScrollController;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -174,14 +168,6 @@
mTabsHeight = mHasWorkProfile
? resources.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
: 0;
- mViewPagerTopPadding = mHasWorkProfile
- ? getContext().getResources()
- .getDimensionPixelSize(R.dimen.widget_picker_view_pager_top_padding)
- : 0;
- mSearchAndRecommendationContainerBottomMargin = resources.getDimensionPixelSize(
- mHasWorkProfile
- ? R.dimen.search_and_recommended_widgets_container_small_bottom_margin
- : R.dimen.search_and_recommended_widgets_container_bottom_margin);
mWidgetSheetContentHorizontalPadding = 2 * resources.getDimensionPixelSize(
R.dimen.widget_cell_horizontal_padding);
}
@@ -194,12 +180,11 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContent = findViewById(R.id.container);
- TopRoundedCornerView springLayout = (TopRoundedCornerView) mContent;
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
: R.layout.widgets_full_sheet_recyclerview;
- layoutInflater.inflate(contentLayoutRes, springLayout, true);
+ layoutInflater.inflate(contentLayoutRes, mContent, true);
RecyclerViewFastScroller fastScroller = findViewById(R.id.fast_scroller);
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
@@ -209,7 +194,6 @@
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.PRIMARY);
- mTabsView = findViewById(R.id.tabs);
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> mViewPager.snapToPage(0));
findViewById(R.id.tab_work)
@@ -220,33 +204,18 @@
mViewPager = null;
}
- layoutInflater.inflate(R.layout.widgets_full_sheet_search_and_recommendations, springLayout,
- true);
mNoWidgetsView = findViewById(R.id.no_widgets_text);
- mSearchAndRecommendationViewHolder = new SearchAndRecommendationViewHolder(
+ mSearchScrollController = new SearchAndRecommendationsScrollController(
findViewById(R.id.search_and_recommendations_container));
- TopRoundedCornerView.LayoutParams layoutParams =
- (TopRoundedCornerView.LayoutParams)
- mSearchAndRecommendationViewHolder.mContainer.getLayoutParams();
- layoutParams.bottomMargin = mSearchAndRecommendationContainerBottomMargin;
- mSearchAndRecommendationViewHolder.mContainer.setLayoutParams(layoutParams);
- mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController(
- mHasWorkProfile,
- mTabsHeight,
- mSearchAndRecommendationViewHolder,
- findViewById(R.id.primary_widgets_list_view),
- mHasWorkProfile ? findViewById(R.id.work_widgets_list_view) : null,
- findViewById(R.id.search_widgets_list_view),
- mTabsView,
- mViewPager,
- mNoWidgetsView);
- fastScroller.setOnFastScrollChangeListener(mSearchAndRecommendationsScrollController);
-
+ mSearchScrollController.setCurrentRecyclerView(
+ findViewById(R.id.primary_widgets_list_view));
+ mSearchScrollController.mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
+ mSearchScrollController.mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
onRecommendedWidgetsBound();
onWidgetsBound();
- mSearchAndRecommendationViewHolder.mSearchBar.initialize(
+ mSearchScrollController.mSearchBar.initialize(
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
setUpEducationViewsIfNeeded();
@@ -270,12 +239,13 @@
reset();
resetExpandedHeaders();
mCurrentWidgetsRecyclerView = recyclerView;
- mSearchAndRecommendationsScrollController.setCurrentRecyclerView(recyclerView);
+ mSearchScrollController.setCurrentRecyclerView(recyclerView);
}
}
private void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
- boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.getItemCount() > 0;
+ // The first item is always an empty space entry. Look for any more items.
+ boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
mNoWidgetsView.setText(
@@ -291,7 +261,7 @@
mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
}
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
- mSearchAndRecommendationsScrollController.reset(/* animate= */ true);
+ mSearchScrollController.reset(/* animate= */ true);
}
@VisibleForTesting
@@ -340,7 +310,8 @@
if (mHasWorkProfile) {
setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, insets.bottom);
}
- mSearchAndRecommendationsScrollController.updateBottomInset(insets.bottom);
+ ((MarginLayoutParams) mNoWidgetsView.getLayoutParams()).bottomMargin = insets.bottom;
+
if (insets.bottom > 0) {
setupNavBarColor();
} else {
@@ -360,7 +331,7 @@
@Override
protected void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx) {
- setContentViewChildHorizontalMargin(mSearchAndRecommendationViewHolder.mContainer,
+ setContentViewChildHorizontalMargin(mSearchScrollController.mContainer,
contentHorizontalMarginInPx);
if (mViewPager == null) {
setContentViewChildHorizontalMargin(
@@ -385,14 +356,14 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mSearchAndRecommendationsScrollController.updateMarginAndPadding()) {
+ if (mSearchScrollController.updateHeaderHeight()) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
}
if (updateMaxSpansPerRow()) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mSearchAndRecommendationsScrollController.updateMarginAndPadding()) {
+ if (mSearchScrollController.updateHeaderHeight()) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@@ -455,7 +426,7 @@
if (mHasWorkProfile) {
mViewPager.setVisibility(VISIBLE);
- mTabsView.setVisibility(VISIBLE);
+ mSearchScrollController.mTabBar.setVisibility(VISIBLE);
AdapterHolder workUserAdapterHolder = mAdapters.get(AdapterHolder.WORK);
workUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
onActivePageChanged(mViewPager.getCurrentPage());
@@ -465,9 +436,9 @@
// Update recommended widgets section so that it occupies appropriate space on screen to
// leave enough space for presence/absence of mNoWidgetsView.
boolean isNoWidgetsViewNeeded =
- mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.getItemCount() == 0
+ !mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.hasVisibleEntries()
|| (mHasWorkProfile && mAdapters.get(AdapterHolder.WORK)
- .mWidgetsListAdapter.getItemCount() == 0);
+ .mWidgetsListAdapter.hasVisibleEntries());
if (mIsNoWidgetsViewNeeded != isNoWidgetsViewNeeded) {
mIsNoWidgetsViewNeeded = isNoWidgetsViewNeeded;
onRecommendedWidgetsBound();
@@ -491,8 +462,6 @@
mViewPager.snapToPage(AdapterHolder.PRIMARY);
}
attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView);
-
- mSearchAndRecommendationsScrollController.updateMarginAndPadding();
}
@Override
@@ -505,10 +474,10 @@
private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
- mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.setVisibility(GONE);
+ mSearchScrollController.mRecommendedWidgetsTable.setVisibility(GONE);
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
- mTabsView.setVisibility(GONE);
+ mSearchScrollController.mTabBar.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.setVisibility(GONE);
}
@@ -536,8 +505,7 @@
}
List<WidgetItem> recommendedWidgets =
mActivityContext.getPopupDataProvider().getRecommendedWidgets();
- WidgetsRecommendationTableLayout table =
- mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable;
+ WidgetsRecommendationTableLayout table = mSearchScrollController.mRecommendedWidgetsTable;
if (recommendedWidgets.size() > 0) {
float noWidgetsViewHeight = 0;
if (mIsNoWidgetsViewNeeded) {
@@ -554,7 +522,7 @@
makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
MeasureSpec.EXACTLY));
float maxTableHeight = (mContent.getMeasuredHeight()
- - mTabsHeight - mViewPagerTopPadding - getHeaderViewHeight()
+ - mTabsHeight - getHeaderViewHeight()
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
@@ -617,10 +585,10 @@
mNoIntercept = !getRecyclerView().shouldContainerScroll(ev, getPopupContainer());
}
- if (mSearchAndRecommendationViewHolder.mSearchBar.isSearchBarFocused()
+ if (mSearchScrollController.mSearchBar.isSearchBarFocused()
&& !getPopupContainer().isEventOverView(
- mSearchAndRecommendationViewHolder.mSearchBarContainer, ev)) {
- mSearchAndRecommendationViewHolder.mSearchBar.clearSearchBarFocus();
+ mSearchScrollController.mSearchBarContainer, ev)) {
+ mSearchScrollController.mSearchBar.clearSearchBarFocus();
}
}
return super.onControllerInterceptTouchEvent(ev);
@@ -661,10 +629,8 @@
@Override
public int getHeaderViewHeight() {
- return measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mCollapseHandle)
- + measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mHeaderTitle)
- + measureHeightWithVerticalMargins(
- (View) mSearchAndRecommendationViewHolder.mSearchBarContainer);
+ return measureHeightWithVerticalMargins(mSearchScrollController.mHeaderTitle)
+ + measureHeightWithVerticalMargins(mSearchScrollController.mSearchBarContainer);
}
/** private the height, in pixel, + the vertical margins of a given view. */
@@ -681,14 +647,14 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mIsInSearchMode) {
- mSearchAndRecommendationViewHolder.mSearchBar.reset();
+ mSearchScrollController.mSearchBar.reset();
}
}
@Override
public boolean onBackPressed() {
if (mIsInSearchMode) {
- mSearchAndRecommendationViewHolder.mSearchBar.reset();
+ mSearchScrollController.mSearchBar.reset();
return true;
}
return super.onBackPressed();
@@ -701,11 +667,10 @@
}
@Nullable private View getViewToShowEducationTip() {
- if (mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.getVisibility() == VISIBLE
- && mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.getChildCount() > 0
- ) {
- return ((ViewGroup) mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable
- .getChildAt(0)).getChildAt(0);
+ if (mSearchScrollController.mRecommendedWidgetsTable.getVisibility() == VISIBLE
+ && mSearchScrollController.mRecommendedWidgetsTable.getChildCount() > 0) {
+ return ((ViewGroup) mSearchScrollController.mRecommendedWidgetsTable.getChildAt(0))
+ .getChildAt(0);
}
AdapterHolder adapterHolder = mAdapters.get(mIsInSearchMode
@@ -782,6 +747,7 @@
LayoutInflater.from(context),
apps.getWidgetCache(),
apps.getIconCache(),
+ this::getEmptySpaceHeight,
/* iconClickListener= */ WidgetsFullSheet.this,
/* iconLongClickListener= */ WidgetsFullSheet.this);
mWidgetsListAdapter.setHasStableIds(true);
@@ -801,13 +767,17 @@
mWidgetsListItemAnimator.setSupportsChangeAnimations(false);
}
+ private int getEmptySpaceHeight() {
+ return mSearchScrollController.getHeaderHeight();
+ }
+
void setup(WidgetsRecyclerView recyclerView) {
mWidgetsRecyclerView = recyclerView;
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
mWidgetsRecyclerView.setEdgeEffectFactory(
- ((TopRoundedCornerView) mContent).createEdgeEffectFactory());
+ ((SpringRelativeLayout) mContent).createEdgeEffectFactory());
// Recycler view binds to fast scroller when it is attached to screen. Make sure
// search recycler view is bound to fast scroller if user is in search mode at the time
// of attachment.
@@ -818,29 +788,4 @@
mWidgetsListAdapter.setMaxHorizontalSpansPerRow(mMaxSpansPerRow);
}
}
-
- final class SearchAndRecommendationViewHolder {
- final SearchAndRecommendationsView mContainer;
- final View mCollapseHandle;
- final View mSearchBarContainer;
- final WidgetsSearchBar mSearchBar;
- final TextView mHeaderTitle;
- final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
-
- SearchAndRecommendationViewHolder(
- SearchAndRecommendationsView searchAndRecommendationContainer) {
- mContainer = searchAndRecommendationContainer;
- mCollapseHandle = mContainer.findViewById(R.id.collapse_handle);
- mSearchBarContainer = mContainer.findViewById(R.id.search_bar_container);
- mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
- mHeaderTitle = mContainer.findViewById(R.id.title);
- mRecommendedWidgetsTable = mContainer.findViewById(R.id.recommended_widget_table);
- mRecommendedWidgetsTable.setWidgetCellOnTouchListener((view, event) -> {
- getRecyclerView().onTouchEvent(event);
- return false;
- });
- mRecommendedWidgetsTable.setWidgetCellLongClickListener(WidgetsFullSheet.this);
- mRecommendedWidgetsTable.setWidgetCellOnClickListener(WidgetsFullSheet.this);
- }
- }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 1125b82..1ad1f7a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -16,6 +16,9 @@
package com.android.launcher3.widget.picker;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_APP_EXPANDED;
+import static com.android.launcher3.recyclerview.ViewHolderBinder.POSITION_DEFAULT;
+import static com.android.launcher3.recyclerview.ViewHolderBinder.POSITION_FIRST;
+import static com.android.launcher3.recyclerview.ViewHolderBinder.POSITION_LAST;
import android.content.Context;
import android.graphics.Rect;
@@ -52,6 +55,7 @@
import com.android.launcher3.widget.DatabaseWidgetPreviewLoader;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.WidgetPreviewLoader.WidgetPreviewLoadedCallback;
+import com.android.launcher3.widget.model.WidgetListSpaceEntry;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
@@ -64,6 +68,7 @@
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
+import java.util.function.IntSupplier;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -84,6 +89,7 @@
private static final boolean DEBUG = false;
/** Uniquely identifies widgets list view type within the app. */
+ private static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
private static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
@@ -97,7 +103,7 @@
private final WidgetListBaseRowEntryComparator mRowComparator =
new WidgetListBaseRowEntryComparator();
- private List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
+ private final List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
@Nullable private PackageUserKey mWidgetsContentVisiblePackageUserKey = null;
@@ -118,6 +124,7 @@
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
DatabaseWidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
+ IntSupplier emptySpaceHeightProvider,
OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
mContext = context;
mLauncher = Launcher.getLauncher(context);
@@ -126,22 +133,23 @@
WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(
layoutInflater, iconClickListener, iconLongClickListener,
- mCachingPreviewLoader, listDrawableFactory, /* listAdapter= */ this);
+ mCachingPreviewLoader, listDrawableFactory);
mViewHolderBinders.put(VIEW_TYPE_WIDGETS_LIST, mWidgetsListTableViewHolderBinder);
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_HEADER,
new WidgetsListHeaderViewHolderBinder(
layoutInflater,
/* onHeaderClickListener= */ this,
- listDrawableFactory,
- /* listAdapter= */ this));
+ listDrawableFactory));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SEARCH_HEADER,
new WidgetsListSearchHeaderViewHolderBinder(
layoutInflater,
/* onHeaderClickListener= */ this,
- listDrawableFactory,
- /* listAdapter= */ this));
+ listDrawableFactory));
+ mViewHolderBinders.put(
+ VIEW_TYPE_WIDGETS_SPACE,
+ new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
mShortcutPreviewPadding =
2 * context.getResources()
.getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
@@ -205,6 +213,14 @@
return mVisibleEntries.size();
}
+ /**
+ * Returns true if the adapter has entries which will be visible to the user
+ */
+ public boolean hasVisibleEntries() {
+ // Account for the 1st space entry
+ return getItemCount() > 1;
+ }
+
/** Returns all items that will be drawn in a recycler view. */
public List<WidgetsListBaseEntry> getItems() {
return mVisibleEntries;
@@ -218,8 +234,9 @@
/** Updates the widget list based on {@code tempEntries}. */
public void setWidgets(List<WidgetsListBaseEntry> tempEntries) {
mCachingPreviewLoader.clearAll();
- mAllEntries = tempEntries.stream().sorted(mRowComparator)
- .collect(Collectors.toList());
+ mAllEntries.clear();
+ mAllEntries.add(new WidgetListSpaceEntry());
+ tempEntries.stream().sorted(mRowComparator).forEach(mAllEntries::add);
if (shouldClearVisibleEntries()) {
mVisibleEntries.clear();
}
@@ -247,8 +264,9 @@
getOffsetForPosition(previousPositionForPackageUserKey);
List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
- .filter(entry -> (mFilter == null || mFilter.test(entry))
+ .filter(entry -> ((mFilter == null || mFilter.test(entry))
&& mHeaderAndSelectedContentFilter.test(entry))
+ || entry instanceof WidgetListSpaceEntry)
.map(entry -> {
if (entry instanceof WidgetsListBaseEntry.Header<?>
&& matchesKey(entry, mWidgetsContentVisiblePackageUserKey)) {
@@ -352,7 +370,13 @@
public void onBindViewHolder(ViewHolder holder, int pos) {
ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos));
WidgetsListBaseEntry entry = mVisibleEntries.get(pos);
- viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), pos);
+
+ // The first entry has an empty space, count from second entries.
+ int listPos = (pos > 1) ? POSITION_DEFAULT : POSITION_FIRST;
+ if (pos == (getItemCount() - 1)) {
+ listPos |= POSITION_LAST;
+ }
+ viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), listPos);
holder.itemView.setTag(R.id.tag_widget_entry, entry);
}
@@ -395,6 +419,8 @@
return VIEW_TYPE_WIDGETS_HEADER;
} else if (entry instanceof WidgetsListSearchHeaderEntry) {
return VIEW_TYPE_WIDGETS_SEARCH_HEADER;
+ } else if (entry instanceof WidgetListSpaceEntry) {
+ return VIEW_TYPE_WIDGETS_SPACE;
}
throw new UnsupportedOperationException("ViewHolderBinder not found for " + entry);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
index 2f8f1ba..00750bd 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
@@ -31,16 +31,13 @@
private final LayoutInflater mLayoutInflater;
private final OnHeaderClickListener mOnHeaderClickListener;
private final WidgetsListDrawableFactory mListDrawableFactory;
- private final WidgetsListAdapter mWidgetsListAdapter;
public WidgetsListHeaderViewHolderBinder(LayoutInflater layoutInflater,
OnHeaderClickListener onHeaderClickListener,
- WidgetsListDrawableFactory listDrawableFactory,
- WidgetsListAdapter listAdapter) {
+ WidgetsListDrawableFactory listDrawableFactory) {
mLayoutInflater = layoutInflater;
mOnHeaderClickListener = onHeaderClickListener;
mListDrawableFactory = listDrawableFactory;
- mWidgetsListAdapter = listAdapter;
}
@Override
@@ -53,14 +50,14 @@
@Override
public void bindViewHolder(WidgetsListHeaderHolder viewHolder, WidgetsListHeaderEntry data,
- int position) {
+ @ListPosition int position) {
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
widgetsListHeader.applyFromItemInfoWithIcon(data);
widgetsListHeader.setExpanded(data.isWidgetListShown());
widgetsListHeader.setListDrawableState(
WidgetsListDrawableState.obtain(
- /* isFirst= */ position == 0,
- /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
+ (position & POSITION_FIRST) != 0,
+ (position & POSITION_LAST) != 0,
/* isExpanded= */ data.isWidgetListShown()));
widgetsListHeader.setOnExpandChangeListener(isExpanded ->
mOnHeaderClickListener.onHeaderClicked(
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java b/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java
deleted file mode 100644
index 2b7f544..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker;
-
-import android.content.Context;
-
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.launcher3.widget.picker.SearchAndRecommendationsScrollController.OnContentChangeListener;
-
-/**
- * A layout manager for the {@link WidgetsRecyclerView}.
- *
- * {@link #setOnContentChangeListener(OnContentChangeListener)} can be used to register a callback
- * for when the content of the layout manager has changed, following measurement and animation.
- */
-public final class WidgetsListLayoutManager extends LinearLayoutManager {
- @Nullable
- private OnContentChangeListener mOnContentChangeListener;
-
- public WidgetsListLayoutManager(Context context) {
- super(context);
- }
-
- @Override
- public void onLayoutCompleted(RecyclerView.State state) {
- super.onLayoutCompleted(state);
- if (mOnContentChangeListener != null) {
- mOnContentChangeListener.onContentChanged();
- }
- }
-
- public void setOnContentChangeListener(@Nullable OnContentChangeListener listener) {
- mOnContentChangeListener = listener;
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
index 31dd9ee..1e2a3bf 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
@@ -32,16 +32,13 @@
private final LayoutInflater mLayoutInflater;
private final OnHeaderClickListener mOnHeaderClickListener;
private final WidgetsListDrawableFactory mListDrawableFactory;
- private final WidgetsListAdapter mWidgetsListAdapter;
public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
OnHeaderClickListener onHeaderClickListener,
- WidgetsListDrawableFactory listDrawableFactory,
- WidgetsListAdapter listAdapter) {
+ WidgetsListDrawableFactory listDrawableFactory) {
mLayoutInflater = layoutInflater;
mOnHeaderClickListener = onHeaderClickListener;
mListDrawableFactory = listDrawableFactory;
- mWidgetsListAdapter = listAdapter;
}
@Override
@@ -54,14 +51,14 @@
@Override
public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
- WidgetsListSearchHeaderEntry data, int position) {
+ WidgetsListSearchHeaderEntry data, @ListPosition int position) {
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
widgetsListHeader.applyFromItemInfoWithIcon(data);
widgetsListHeader.setExpanded(data.isWidgetListShown());
widgetsListHeader.setListDrawableState(
WidgetsListDrawableState.obtain(
- /* isFirst= */ position == 0,
- /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
+ (position & POSITION_FIRST) != 0,
+ (position & POSITION_LAST) != 0,
/* isExpanded= */ data.isWidgetListShown()));
widgetsListHeader.setOnExpandChangeListener(isExpanded ->
mOnHeaderClickListener.onHeaderClicked(isExpanded,
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 9c06558..804b0ae 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -54,7 +54,6 @@
private final OnLongClickListener mIconLongClickListener;
private final WidgetsListDrawableFactory mListDrawableFactory;
private final CachingWidgetPreviewLoader mWidgetPreviewLoader;
- private final WidgetsListAdapter mWidgetsListAdapter;
private boolean mApplyBitmapDeferred = false;
public WidgetsListTableViewHolderBinder(
@@ -62,14 +61,12 @@
OnClickListener iconClickListener,
OnLongClickListener iconLongClickListener,
CachingWidgetPreviewLoader widgetPreviewLoader,
- WidgetsListDrawableFactory listDrawableFactory,
- WidgetsListAdapter listAdapter) {
+ WidgetsListDrawableFactory listDrawableFactory) {
mLayoutInflater = layoutInflater;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
mWidgetPreviewLoader = widgetPreviewLoader;
mListDrawableFactory = listDrawableFactory;
- mWidgetsListAdapter = listAdapter;
}
/**
@@ -97,15 +94,13 @@
@Override
public void bindViewHolder(WidgetsRowViewHolder holder, WidgetsListContentEntry entry,
- int position) {
+ @ListPosition int position) {
WidgetsListTableView table = holder.mTableContainer;
if (DEBUG) {
Log.d(TAG, String.format("onBindViewHolder [widget#=%d, table.getChildCount=%d]",
entry.mWidgets.size(), table.getChildCount()));
}
-
- table.setListDrawableState(
- position == mWidgetsListAdapter.getItemCount() - 1 ? LAST : MIDDLE);
+ table.setListDrawableState(((position & POSITION_LAST) != 0) ? LAST : MIDDLE);
List<ArrayList<WidgetItem>> widgetItemsTable =
WidgetsTableUtils.groupWidgetItemsIntoTable(
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 0b8ca34..60dfebe 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -53,7 +53,6 @@
private float mRecommendationTableMaxHeight = Float.MAX_VALUE;
@Nullable private OnLongClickListener mWidgetCellOnLongClickListener;
@Nullable private OnClickListener mWidgetCellOnClickListener;
- @Nullable private OnTouchListener mWidgetCellOnTouchListener;
public WidgetsRecommendationTableLayout(Context context) {
this(context, /* attrs= */ null);
@@ -79,11 +78,6 @@
mWidgetCellOnClickListener = widgetCellOnClickListener;
}
- /** Sets a {@link android.view.View.OnTouchListener} for all widget cells in this table. */
- public void setWidgetCellOnTouchListener(OnTouchListener widgetCellOnTouchListener) {
- mWidgetCellOnTouchListener = widgetCellOnTouchListener;
- }
-
/**
* Sets a list of recommended widgets that would like to be displayed in this table within the
* desired {@code recommendationTableMaxHeight}.
@@ -129,7 +123,6 @@
WidgetCell widget = (WidgetCell) LayoutInflater.from(
getContext()).inflate(R.layout.widget_cell, parent, false);
- widget.setOnTouchListener(mWidgetCellOnTouchListener);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
previewContainer.setOnClickListener(mWidgetCellOnClickListener);
previewContainer.setOnLongClickListener(mWidgetCellOnLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 7671841..f780f03 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -23,7 +23,6 @@
import android.view.View;
import android.widget.TableLayout;
-import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
@@ -32,11 +31,12 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.widget.model.WidgetListSpaceEntry;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-import com.android.launcher3.widget.picker.SearchAndRecommendationsScrollController.OnContentChangeListener;
+import com.android.launcher3.widget.picker.WidgetsSpaceViewHolderBinder.EmptySpaceView;
/**
* The widgets recycler view.
@@ -50,10 +50,13 @@
private final Point mFastScrollerOffset = new Point();
private boolean mTouchDownOnScroller;
private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
+
+ // Cached sizes
private int mLastVisibleWidgetContentTableHeight = 0;
private int mWidgetHeaderHeight = 0;
+ private int mWidgetEmptySpaceHeight = 0;
+
private final int mSpacingBetweenEntries;
- @Nullable private OnContentChangeListener mOnContentChangeListener;
public WidgetsRecyclerView(Context context) {
this(context, null);
@@ -82,9 +85,7 @@
super.onFinishInflate();
// create a layout manager with Launcher's context so that scroll position
// can be preserved during screen rotation.
- WidgetsListLayoutManager layoutManager = new WidgetsListLayoutManager(getContext());
- layoutManager.setOnContentChangeListener(mOnContentChangeListener);
- setLayoutManager(layoutManager);
+ setLayoutManager(new LinearLayoutManager(getContext()));
}
@Override
@@ -169,10 +170,12 @@
// This assumes there is ever only one content shown in this recycler view.
mLastVisibleWidgetContentTableHeight = view.getMeasuredHeight();
} else if (view instanceof WidgetsListHeader
- && mLastVisibleWidgetContentTableHeight == 0
+ && mWidgetHeaderHeight == 0
&& view.getMeasuredHeight() > 0) {
// This assumes all header views are of the same height.
mWidgetHeaderHeight = view.getMeasuredHeight();
+ } else if (view instanceof EmptySpaceView && view.getMeasuredHeight() > 0) {
+ mWidgetEmptySpaceHeight = view.getMeasuredHeight();
}
}
@@ -251,14 +254,6 @@
scrollToPosition(0);
}
- public void setOnContentChangeListener(@Nullable OnContentChangeListener listener) {
- mOnContentChangeListener = listener;
- WidgetsListLayoutManager layoutManager = (WidgetsListLayoutManager) getLayoutManager();
- if (layoutManager != null) {
- layoutManager.setOnContentChangeListener(listener);
- }
- }
-
/**
* Returns the sum of the height, in pixels, of this list adapter's items from index 0 until
* {@code untilIndex}.
@@ -283,6 +278,8 @@
}
} else if (entry instanceof WidgetsListContentEntry) {
totalItemsHeight += mLastVisibleWidgetContentTableHeight;
+ } else if (entry instanceof WidgetListSpaceEntry) {
+ totalItemsHeight += mWidgetEmptySpaceHeight;
} else {
throw new UnsupportedOperationException("Can't estimate height for " + entry);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java
new file mode 100644
index 0000000..f33c2fa
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsSpaceViewHolderBinder.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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.widget.picker;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+
+import com.android.launcher3.recyclerview.ViewHolderBinder;
+import com.android.launcher3.widget.model.WidgetListSpaceEntry;
+
+import java.util.function.IntSupplier;
+
+/**
+ * {@link ViewHolderBinder} for binding the top empty space
+ */
+public class WidgetsSpaceViewHolderBinder
+ implements ViewHolderBinder<WidgetListSpaceEntry, ViewHolder> {
+
+ private final IntSupplier mEmptySpaceHeightProvider;
+
+ public WidgetsSpaceViewHolderBinder(IntSupplier emptySpaceHeightProvider) {
+ mEmptySpaceHeightProvider = emptySpaceHeightProvider;
+ }
+
+ @Override
+ public ViewHolder newViewHolder(ViewGroup parent) {
+ return new ViewHolder(new EmptySpaceView(parent.getContext())) { };
+ }
+
+ @Override
+ public void bindViewHolder(ViewHolder holder, WidgetListSpaceEntry data, int position) {
+ ((EmptySpaceView) holder.itemView).setFixedHeight(mEmptySpaceHeightProvider.getAsInt());
+ }
+
+ /**
+ * Empty view which allows listening for 'Y' changes
+ */
+ public static class EmptySpaceView extends View {
+
+ private Runnable mOnYChangeCallback;
+ private int mHeight = 0;
+
+ private EmptySpaceView(Context context) {
+ super(context);
+ animate().setUpdateListener(v -> notifyYChanged());
+ }
+
+ /**
+ * Sets the height for the empty view
+ * @return true if the height changed, false otherwise
+ */
+ public boolean setFixedHeight(int height) {
+ if (mHeight != height) {
+ mHeight = height;
+ requestLayout();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, makeMeasureSpec(mHeight, EXACTLY));
+ }
+
+ public void setOnYChangeCallback(Runnable callback) {
+ mOnYChangeCallback = callback;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ notifyYChanged();
+ }
+
+ @Override
+ public void offsetTopAndBottom(int offset) {
+ super.offsetTopAndBottom(offset);
+ notifyYChanged();
+ }
+
+ @Override
+ public void setTranslationY(float translationY) {
+ super.setTranslationY(translationY);
+ notifyYChanged();
+ }
+
+ private void notifyYChanged() {
+ if (mOnYChangeCallback != null) {
+ mOnYChangeCallback.run();
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index bf4eba0..0d5b9ad 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -153,6 +153,8 @@
public static String dumpHprofData() {
String result;
if (sDumpWasGenerated) {
+ Log.d("b/195319692", "dump has already been generated by another test",
+ new Exception());
result = "dump has already been generated by another test";
} else {
try {
@@ -167,6 +169,7 @@
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
sDumpWasGenerated = true;
+ Log.d("b/195319692", "sDumpWasGenerated := true", new Exception());
result = "memory dump filename: " + fileName;
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);
@@ -251,26 +254,12 @@
return mDevice;
}
- private boolean hasSystemUiObject(String resId) {
- return mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, resId));
- }
-
@Before
public void setUp() throws Exception {
mLauncher.onTestStart();
- Log.d(TAG, "Before disabling battery defender");
- mDevice.executeShellCommand("setprop vendor.battery.defender.disable 1");
- Log.d(TAG, "Before enabling stay awake");
- mDevice.executeShellCommand("settings put global stay_on_while_plugged_in 3");
- for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
- Log.d(TAG, "Before unlocking the phone");
- mDevice.executeShellCommand("input keyevent 82");
- mDevice.waitForIdle();
- }
- Assert.assertTrue("Keyguard still visible",
+ Assert.assertTrue("Keyguard is visible, which is likely caused by a crash in SysUI",
TestHelpers.wait(
Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
- Log.d(TAG, "Keyguard is not visible");
final String launcherPackageName = mDevice.getLauncherPackageName();
try {
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 4beb617..881f50c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -36,7 +36,6 @@
import com.android.launcher3.tapl.AppIconMenuItem;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
@@ -97,7 +96,6 @@
}
@Test
- @ScreenRecord //b/187080582
public void testDevicePressMenu() throws Exception {
mDevice.pressMenu();
mDevice.waitForIdle();
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 2e8048a..dad4f2b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -27,7 +27,6 @@
import com.android.launcher3.tapl.Widget;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -81,7 +80,6 @@
*/
@Test
@PortraitLandscape
- @ScreenRecord //b/195263971
public void testDragCustomShortcut() throws Throwable {
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 5fbf847..0b60ffc 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -13,6 +13,7 @@
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
import java.io.File;
import java.io.FileOutputStream;
@@ -38,6 +39,26 @@
}
@Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ FailureWatcher.super.apply(base, description).evaluate();
+ } finally {
+ if (mLauncher.hadNontestEvents()) {
+ throw new AssertionError(
+ "Launcher received events not sent by the test. This may mean "
+ + "that the touch screen of the lab device has sent false"
+ + " events. See the logcat for TaplEvents tag and look "
+ + "for events with deviceId != -1");
+ }
+ }
+ }
+ };
+ }
+
+ @Override
protected void failed(Throwable e, Description description) {
onError(mDevice, description, e);
}
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index 2b2fef4..08953fc 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -21,7 +21,6 @@
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
-import android.util.Log;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -103,8 +102,6 @@
*/
public static ShellCommandRule setDefaultLauncher() {
final ActivityInfo launcher = getLauncherInMyProcess();
- Log.d("b/187080582", "Launcher: " + new ComponentName(launcher.packageName, launcher.name)
- .flattenToString());
return new ShellCommandRule(getLauncherCommand(launcher), null, true, () ->
Assert.assertEquals("Setting default launcher failed",
new ComponentName(launcher.packageName, launcher.name)
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index c24fc8e..de36d5f 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -41,7 +41,7 @@
Pattern.compile("^("
+ "(?<local>(BuildFromAndroidStudio|"
+ "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|"
- + "(?<platform>[A-Z][a-z]*)"
+ + "(?<platform>[A-Z]([a-z]|[0-9])*)"
+ ")$");
private static final Pattern PLATFORM_BUILD =
Pattern.compile("^("
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 49934f7..8d05b70 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -80,6 +80,7 @@
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -96,6 +97,7 @@
private static final String TAG = "Tapl";
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
private static final int GESTURE_STEP_MS = 16;
+ private static final long FORCE_PAUSE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2);
static final Pattern EVENT_TOUCH_DOWN = getTouchEventPattern("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP = getTouchEventPattern("ACTION_UP");
@@ -105,6 +107,7 @@
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
+
private final String mLauncherPackage;
private Boolean mIsLauncher3;
private long mTestStartTime = -1;
@@ -123,8 +126,6 @@
OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE
}
- ;
-
// Base class for launcher containers.
static abstract class VisibleContainer {
protected final LauncherInstrumentation mLauncher;
@@ -272,9 +273,13 @@
}
Bundle getTestInfo(String request) {
+ return getTestInfo(request, /*arg=*/ null);
+ }
+
+ Bundle getTestInfo(String request, String arg) {
try (ContentProviderClient client = getContext().getContentResolver()
.acquireContentProviderClient(mTestProviderUri)) {
- return client.call(request, null, null);
+ return client.call(request, arg, null);
} catch (DeadObjectException e) {
fail("Launcher crashed");
return null;
@@ -284,6 +289,11 @@
}
Insets getTargetInsets() {
+ return getTestInfo(TestProtocol.REQUEST_TARGET_INSETS)
+ .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
+ Insets getWindowInsets() {
return getTestInfo(TestProtocol.REQUEST_WINDOW_INSETS)
.getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@@ -298,6 +308,15 @@
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ private void setForcePauseTimeout(long timeout) {
+ getTestInfo(TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT, Long.toString(timeout));
+ }
+
+ public boolean hadNontestEvents() {
+ return getTestInfo(TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS)
+ .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
void setActiveContainer(VisibleContainer container) {
sActiveContainer = new WeakReference<>(container);
}
@@ -730,6 +749,7 @@
final String action;
if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
checkForAnomaly();
+ setForcePauseTimeout(FORCE_PAUSE_TIMEOUT_MS);
final Point displaySize = getRealDisplaySize();
boolean gestureStartFromLauncher = isTablet()
@@ -748,9 +768,6 @@
try (LauncherInstrumentation.Closable c1 = addContextLayer(
"Swiped up from context menu to home")) {
waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID);
- // Swiping up can temporarily bring Nexus Launcher if the current
- // Launcher is a Launcher3 one. Wait for the current launcher to reappear.
- SystemClock.sleep(5000); // b/187080582
waitForLauncherObject(getAnyObjectSelector());
}
}
@@ -1119,7 +1136,7 @@
}
int getBottomGestureSize() {
- return Math.max(getTargetInsets().bottom, ResourceUtils.getNavbarSize(
+ return Math.max(getWindowInsets().bottom, ResourceUtils.getNavbarSize(
ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources())) + 1;
}
@@ -1315,13 +1332,6 @@
}
final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
- // b/190748682
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_UP:
- log("b/190748682: injecting " + event);
- break;
- }
assertTrue("injectInputEvent failed",
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
event.recycle();