Merge "Add error handling to prevent IllegalArgumentException" into udc-qpr-dev
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index f99155f..29b24b7 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -25,7 +25,6 @@
import android.os.Binder;
import android.os.Bundle;
import android.system.Os;
-import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
@@ -62,7 +61,6 @@
public void onActivityCreated(Activity activity, Bundle bundle) {
sActivities.put(activity, true);
++sActivitiesCreatedCount;
- Log.d(TestProtocol.FLAKY_ACTIVITY_COUNT, "onActivityCreated", new Exception());
}
@Override
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index f5a8253..638ce27 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -42,5 +42,6 @@
"tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
"tests/src/com/android/quickstep/AbstractQuickStepTest.java",
"tests/src/com/android/quickstep/TaplTestsQuickstep.java",
+ "tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
]
}
diff --git a/quickstep/res/drawable/taskbar_divider_bg.xml b/quickstep/res/drawable/taskbar_divider_bg.xml
deleted file mode 100644
index 52e230d..0000000
--- a/quickstep/res/drawable/taskbar_divider_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle" >
- <solid android:color="@color/taskbar_divider_background"/>
- <corners android:radius="1dp" />
-</shape>
diff --git a/quickstep/res/drawable/taskbar_divider_button.xml b/quickstep/res/drawable/taskbar_divider_button.xml
new file mode 100644
index 0000000..cb116cf
--- /dev/null
+++ b/quickstep/res/drawable/taskbar_divider_button.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="52dp"
+ android:height="52dp"
+ android:viewportHeight="52"
+ android:viewportWidth="52">
+ <group>
+ <path
+ android:fillColor="@color/taskbar_divider_background"
+ android:pathData="M26,11L26,41"
+ android:strokeColor="@color/taskbar_divider_background"
+ android:strokeLineCap="round"
+ android:strokeWidth="2" />
+ </group>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 73f3811..0a92fa9 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -13,16 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout
+<com.android.launcher3.views.IconButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/taskbar_icon_min_touch_size"
android:layout_height="@dimen/taskbar_icon_min_touch_size"
android:contentDescription="@string/taskbar_divider_a11y_title"
- android:backgroundTint="@android:color/transparent">
-
- <View
- android:layout_height="32dp"
- android:layout_width="2dp"
- android:layout_gravity="center"
- android:background="@drawable/taskbar_divider_bg" />
-</FrameLayout>
\ No newline at end of file
+ android:backgroundTint="@android:color/transparent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 195443e..00e47c9 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -32,7 +32,7 @@
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
- android:background="@drawable/top_rounded_popup_ripple"
+ android:background="@drawable/rounded_popup_ripple"
android:paddingEnd="10dp"
android:paddingStart="10dp"
android:theme="@style/PopupItem">
@@ -59,40 +59,4 @@
android:text="@string/always_show_taskbar" />
</LinearLayout>
-
- <LinearLayout
- android:id="@+id/navigation_mode_switch_option"
- android:layout_width="match_parent"
- android:layout_height="52dp"
- android:layout_gravity="center_vertical"
- android:elevation="2dp"
- android:clickable="true"
- android:focusable="true"
- android:background="@drawable/bottom_rounded_popup_ripple"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingEnd="10dp"
- android:paddingStart="10dp"
- android:theme="@style/PopupItem">
-
- <View
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_margin="4dp"
- android:background="@drawable/ic_touch"
- android:backgroundTint="?android:attr/textColorPrimary" />
-
- <com.android.launcher3.BubbleTextView
- style="@style/BaseIcon"
- android:id="@+id/change_navigation_mode_text"
- android:gravity="start|center_vertical"
- android:textAlignment="viewStart"
- android:paddingStart="12dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textSize="14sp"
- android:textColor="?android:attr/textColorPrimary"
- android:text="@string/change_navigation_mode" />
-
- </LinearLayout>
</com.android.launcher3.taskbar.TaskbarDividerPopupView>
\ No newline at end of file
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index d9e9691..a678b3f 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -92,7 +92,7 @@
<string name="default_device_name" msgid="6660656727127422487">"መሣሪያ"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"የስርዓት አሰሳ ቅንብሮች"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
- <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገፅ እይታ"</string>
+ <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገፅ ዕይታ"</string>
<string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ከተከፈለ ማያ ገፅ ምርጫ ይውጡ"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index b48e5d6..828b85f 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -60,12 +60,12 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Wische vom unteren Displayrand nach oben"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Achte darauf, nicht innezuhalten, bevor du loslässt"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Wische gerade nach oben"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du hast den Schritt für die „Startbildschirm“-Geste abgeschlossen. Jetzt lernst du, wie du zurückgehst."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du hast den Schritt für die „Zum Startbildschirm“-Geste abgeschlossen. Jetzt lernst du, wie du zurückgehst."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Du hast den Schritt für die „Startbildschirm“-Touch-Geste abgeschlossen"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Den Startbildschirm aufrufen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Wische mit zwei Fingern vom unteren Displayrand nach oben. So gelangst du immer zum Startbildschirm."</string>
- <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum Startbildschirm"</string>
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum StartU+00ADbildschirm"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Wische vom unteren Displayrand nach oben"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Gut gemacht!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Wische vom unteren Displayrand nach oben"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index b737129..cf5d6e9 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -70,7 +70,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"¡Bien hecho!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Asegúrate de deslizar hacia arriba desde el borde inferior de la pantalla"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Intenta mantener presionada la ventana más tiempo antes de soltarla"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y, luego, detenerte"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y detenerte"</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="2903050864432331629">"Completaste el gesto para cambiar de app"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza para cambiar de app"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 7a681b1..d40780c 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -65,12 +65,12 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza para ir a la pantalla de inicio"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza hacia arriba desde la parte inferior de la pantalla. Este gesto siempre te lleva a la pantalla de inicio."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Desliza dos dedos hacia arriba desde la parte inferior de la pantalla. Si haces este gesto, siempre irás a la pantalla de inicio."</string>
- <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a Inicio"</string>
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a inicio"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Desliza hacia arriba desde la parte inferior de la pantalla"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"¡Bien hecho!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Asegúrate de deslizar hacia arriba desde el borde inferior de la pantalla"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prueba a mantener pulsada la ventana durante más tiempo antes de soltarla"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y, luego, detenerte"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y luego detenerte"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ya sabes cómo utilizar gestos. Para desactivarlos, ve a Ajustes."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Has completado el gesto para cambiar de aplicación"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza el dedo para cambiar de aplicación"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 6de4e90..85b4862 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -72,7 +72,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"قبلاز رها کردن پنجره، آن را برای مدت طولانیتری نگه دارید"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"دقت کنید که مستقیماً تند به بالا بکشید و سپس توقف کنید"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"با نحوه استفاده از اشارهها آشنا شدید. برای خاموش کردن اشارهها، به «تنظیمات» بروید."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"اشاره جابهجا شدن بین برنامهها را تکمیل کردید"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"اشاره جابهجایی بین برنامهها را تکمیل کردید"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"برای جابهجا شدن بین برنامهها، تند بهبالا بکشید"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"برای جابهجا شدن بین برنامهها، از پایین صفحه تند بهبالا بکشید، نگه دارید، و سپس رها کنید."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"برای جابهجایی بین برنامهها، با ۲ انگشت از پایین صفحه تند بهبالا بکشید، نگه دارید، و سپس رها کنید."</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 2ec3cbf..e07d338 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -83,7 +83,7 @@
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"סיום"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"הגדרות"</string>
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"ניסיון חוזר"</string>
- <string name="gesture_tutorial_nice" msgid="2936275692616928280">"איזה יופי!"</string>
+ <string name="gesture_tutorial_nice" msgid="2936275692616928280">"יפה!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"מדריך <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"הכול מוכן!"</string>
<string name="allset_hint" msgid="459504134589971527">"כדי לחזור לדף הבית, מחליקים כלפי מעלה"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 6c84e6f..b7cdd15 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -116,7 +116,7 @@
<string name="taskbar_button_back" msgid="8558862226461164514">"ಹಿಂದೆ"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ಪರಿವರ್ತಕ"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"ಇತ್ತೀಚಿನವು"</string>
- <string name="taskbar_button_notifications" msgid="7471740351507357318">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="taskbar_button_notifications" msgid="7471740351507357318">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string>
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ಟಾಸ್ಕ್ಬಾರ್"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ಟಾಸ್ಕ್ಬಾರ್ ತೋರಿಸಲಾಗಿದೆ"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 91b5551..6a7efe5 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -46,7 +46,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Voorspelde app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Het apparaat draaien"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Draai het apparaat om de tutorial voor navigatie met gebaren af te ronden"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe helemaal vanaf de rechter- of linkerrand"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe vanaf de rechter- of linkerrand"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Je weet nu hoe je vanaf rechts kunt swipen om terug te gaan. Ontdek nu hoe je tussen apps schakelt."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Je weet nu hoe je het gebaar Terug maakt"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 81d69f9..c943da5 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -72,7 +72,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Mantenha a janela pressionada por mais tempo antes de soltar"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pare"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Você aprendeu. Para desativar os gestos, acesse as Configurações."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para trocar de app"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para mudar de app"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslizar para trocar de app"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Para mudar de app, deslize de baixo para cima, mantenha a tela pressionada por um tempo e solte."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Para mudar de app, deslize de baixo para cima na tela com dois dedos, segure por um tempo e solte."</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index e436ec1..3980b21 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -72,7 +72,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"尝试按住窗口较长时间,然后再松开手指"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"确保笔直向上滑动,然后停住"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"您已了解如何使用手势了。如要关闭手势,请前往“设置”。"</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"您完成了“切换应用”手势"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"您完成了应用切换手势"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"滑动即可切换应用"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"如需在应用之间切换,请从屏幕底部向上滑动,按住,然后松开。"</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"如需在应用之间切换,请从屏幕底部向上滑动,按住,然后松开。"</string>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index 67be0dd..860abc1 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -27,6 +27,8 @@
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
+ <string name="assist_utils_class" translatable="false"></string>
+
<string name="secondary_display_predictions_class" translatable="false">com.android.launcher3.secondarydisplay.SecondaryDisplayPredictionsImpl</string>
<string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 28bd701..f64b5cf 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -15,23 +15,16 @@
*/
package com.android.launcher3;
-import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.os.Build;
-import android.os.CancellationSignal;
-import android.view.RemoteAnimationTarget;
-import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.ActivityInitListener;
-import com.android.quickstep.util.RemoteAnimationProvider;
import java.util.function.BiPredicate;
@TargetApi(Build.VERSION_CODES.P)
public class LauncherInitListener extends ActivityInitListener<Launcher> {
- private RemoteAnimationProvider mRemoteAnimationProvider;
-
/**
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
@@ -43,37 +36,7 @@
@Override
public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
- if (mRemoteAnimationProvider != null) {
- QuickstepTransitionManager appTransitionManager =
- ((QuickstepLauncher) launcher).getAppTransitionManager();
-
- // Set a one-time animation provider. After the first call, this will get cleared.
- // TODO: Probably also check the intended target id.
- CancellationSignal cancellationSignal = new CancellationSignal();
- appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
- @Override
- public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets) {
-
- // On the first call clear the reference.
- cancellationSignal.cancel();
- RemoteAnimationProvider provider = mRemoteAnimationProvider;
- mRemoteAnimationProvider = null;
-
- if (provider != null && launcher.getStateManager().getState().overviewUi) {
- return provider.createWindowAnimation(appTargets, wallpaperTargets);
- }
- return null;
- }
- }, cancellationSignal);
- }
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
return super.handleInit(launcher, alreadyOnHome);
}
-
- @Override
- public void unregister() {
- mRemoteAnimationProvider = null;
- super.unregister();
- }
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 1df4ac8..3113cc2 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -60,6 +60,8 @@
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
+import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
+import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME_FALLBACK;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -82,7 +84,6 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -140,7 +141,6 @@
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
import com.android.quickstep.util.RectFSpringAnim.TaskbarHotseatSpringConfig;
-import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransaction;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
@@ -230,7 +230,6 @@
private DeviceProfile mDeviceProfile;
- private RemoteAnimationProvider mRemoteAnimationProvider;
// Strong refs to runners which are cleared when the launcher activity is destroyed
private RemoteAnimationFactory mWallpaperOpenRunner;
private RemoteAnimationFactory mAppLaunchRunner;
@@ -469,16 +468,6 @@
return bounds;
}
- public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider,
- CancellationSignal cancellationSignal) {
- mRemoteAnimationProvider = animationProvider;
- cancellationSignal.setOnCancelListener(() -> {
- if (animationProvider == mRemoteAnimationProvider) {
- mRemoteAnimationProvider = null;
- }
- });
- }
-
/** Dump debug logs to bug report. */
public void dump(@NonNull String prefix, @NonNull PrintWriter printWriter) {}
@@ -1235,7 +1224,7 @@
* ie. pressing home, swiping up from nav bar.
*/
RemoteAnimationFactory createWallpaperOpenRunner(boolean fromUnlock) {
- return new WallpaperOpenLauncherAnimationRunner(mHandler, fromUnlock);
+ return new WallpaperOpenLauncherAnimationRunner(fromUnlock);
}
/**
@@ -1353,7 +1342,7 @@
/**
* Closing animator that animates the window into its final location on the workspace.
*/
- private RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
+ protected RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
RemoteAnimationTarget[] targets, View launcherView, PointF velocityPxPerS,
RectF closingWindowStartRect, float startWindowCornerRadius) {
FloatingIconView floatingIconView = null;
@@ -1593,89 +1582,80 @@
RectF startRect,
float startWindowCornerRadius,
boolean fromPredictiveBack) {
- AnimatorSet anim = null;
+ AnimatorSet anim = new AnimatorSet();
RectFSpringAnim rectFSpringAnim = null;
- RemoteAnimationProvider provider = mRemoteAnimationProvider;
- if (provider != null) {
- anim = provider.createWindowAnimation(appTargets, wallpaperTargets);
+ final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
+ || launcherIsATargetWithMode(appTargets, MODE_OPENING);
+
+ View launcherView = findLauncherView(appTargets);
+ boolean playFallBackAnimation = (launcherView == null
+ && launcherIsForceInvisibleOrOpening)
+ || mLauncher.getWorkspace().isOverlayShown()
+ || shouldPlayFallbackClosingAnimation(appTargets);
+
+ boolean playWorkspaceReveal = true;
+ boolean skipAllAppsScale = false;
+ if (fromUnlock) {
+ anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
+ } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
+ && !playFallBackAnimation) {
+ // Use a fixed velocity to start the animation.
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
+ .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+ PointF velocity = new PointF(0, -velocityPxPerS);
+ rectFSpringAnim = getClosingWindowAnimators(
+ anim, appTargets, launcherView, velocity, startRect,
+ startWindowCornerRadius);
+ if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+ // Skip scaling all apps, otherwise FloatingIconView will get wrong
+ // layout bounds.
+ skipAllAppsScale = true;
+ } else if (!fromPredictiveBack) {
+ anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+ true /* animateOverviewScrim */, launcherView).getAnimators());
+
+ if (!areAllTargetsTranslucent(appTargets)) {
+ anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
+ MULTI_PROPERTY_VALUE,
+ BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher)));
+ }
+
+ // We play StaggeredWorkspaceAnim as a part of the closing window animation.
+ playWorkspaceReveal = false;
+ }
+ } else {
+ anim.play(getFallbackClosingWindowAnimators(appTargets));
}
- if (anim == null) {
- anim = new AnimatorSet();
+ // Normally, we run the launcher content animation when we are transitioning
+ // home, but if home is already visible, then we don't want to animate the
+ // contents of launcher unless we know that we are animating home as a result
+ // of the home button press with quickstep, which will result in launcher being
+ // started on touch down, prior to the animation home (and won't be in the
+ // targets list because it is already visible). In that case, we force
+ // invisibility on touch down, and only reset it after the animation to home
+ // is initialized.
+ if (launcherIsForceInvisibleOrOpening) {
+ addCujInstrumentation(anim, playFallBackAnimation
+ ? CUJ_APP_CLOSE_TO_HOME_FALLBACK : CUJ_APP_CLOSE_TO_HOME);
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(anim);
- final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
- || launcherIsATargetWithMode(appTargets, MODE_OPENING);
-
- View launcherView = findLauncherView(appTargets);
- boolean playFallBackAnimation = (launcherView == null
- && launcherIsForceInvisibleOrOpening)
- || mLauncher.getWorkspace().isOverlayShown()
- || shouldPlayFallbackClosingAnimation(appTargets);
-
- boolean playWorkspaceReveal = true;
- boolean skipAllAppsScale = false;
- if (fromUnlock) {
- anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
- } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
- && !playFallBackAnimation) {
- // Use a fixed velocity to start the animation.
- float velocityPxPerS = DynamicResource.provider(mLauncher)
- .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
- PointF velocity = new PointF(0, -velocityPxPerS);
- rectFSpringAnim = getClosingWindowAnimators(
- anim, appTargets, launcherView, velocity, startRect,
- startWindowCornerRadius);
- if (mLauncher.isInState(LauncherState.ALL_APPS)) {
- // Skip scaling all apps, otherwise FloatingIconView will get wrong
- // layout bounds.
- skipAllAppsScale = true;
- } else if (!fromPredictiveBack) {
- anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
- true /* animateOverviewScrim */, launcherView).getAnimators());
-
- if (!areAllTargetsTranslucent(appTargets)) {
- anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
- MULTI_PROPERTY_VALUE,
- BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher)));
+ if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+ Pair<AnimatorSet, Runnable> contentAnimator =
+ getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
+ skipAllAppsScale);
+ anim.play(contentAnimator.first);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ contentAnimator.second.run();
}
-
- // We play StaggeredWorkspaceAnim as a part of the closing window animation.
- playWorkspaceReveal = false;
- }
+ });
} else {
- anim.play(getFallbackClosingWindowAnimators(appTargets));
- }
-
- // Normally, we run the launcher content animation when we are transitioning
- // home, but if home is already visible, then we don't want to animate the
- // contents of launcher unless we know that we are animating home as a result
- // of the home button press with quickstep, which will result in launcher being
- // started on touch down, prior to the animation home (and won't be in the
- // targets list because it is already visible). In that case, we force
- // invisibility on touch down, and only reset it after the animation to home
- // is initialized.
- if (launcherIsForceInvisibleOrOpening) {
- addCujInstrumentation(
- anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
- // Only register the content animation for cancellation when state changes
- mLauncher.getStateManager().setCurrentAnimation(anim);
-
- if (mLauncher.isInState(LauncherState.ALL_APPS)) {
- Pair<AnimatorSet, Runnable> contentAnimator =
- getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
- skipAllAppsScale);
- anim.play(contentAnimator.first);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- contentAnimator.second.run();
- }
- });
- } else {
- if (playWorkspaceReveal) {
- anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
- }
+ if (playWorkspaceReveal) {
+ anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
}
}
}
@@ -1688,11 +1668,9 @@
*/
protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory {
- private final Handler mHandler;
private final boolean mFromUnlock;
- public WallpaperOpenLauncherAnimationRunner(Handler handler, boolean fromUnlock) {
- mHandler = handler;
+ public WallpaperOpenLauncherAnimationRunner(boolean fromUnlock) {
mFromUnlock = fromUnlock;
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 85d0ab5..87a9ecb 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -27,6 +27,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
+import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.ViewGroup;
@@ -74,6 +75,7 @@
SystemShortcut.Factory<QuickstepLauncher>, DeviceProfile.OnDeviceProfileChangeListener,
DragSource, ViewGroup.OnHierarchyChangeListener {
+ private static final String TAG = "HotseatPredictionController";
private static final int FLAG_UPDATE_PAUSED = 1 << 0;
private static final int FLAG_DRAG_IN_PROGRESS = 1 << 1;
private static final int FLAG_FILL_IN_PROGRESS = 1 << 2;
@@ -114,8 +116,7 @@
WorkspaceItemInfo dragItem = new WorkspaceItemInfo((WorkspaceItemInfo) v.getTag());
v.setVisibility(View.INVISIBLE);
mLauncher.getWorkspace().beginDragShared(
- v, null, this, dragItem, new DragPreviewProvider(v),
- mLauncher.getDefaultWorkspaceDragOptions());
+ v, null, this, dragItem, new DragPreviewProvider(v), new DragOptions());
return true;
};
@@ -184,6 +185,7 @@
}
private void fillGapsWithPrediction(boolean animate) {
+ Log.d(TAG, "fillGapsWithPrediction");
if (mPauseFlags != 0) {
return;
}
@@ -208,12 +210,16 @@
View child = mHotseat.getChildAt(
mHotseat.getCellXFromOrder(rank),
mHotseat.getCellYFromOrder(rank));
+ Log.d(TAG, "Hotseat app child is: " + child + " and isPredictedIcon() evaluates to"
+ + ": " + isPredictedIcon(child));
if (child != null && !isPredictedIcon(child)) {
continue;
}
if (mPredictedItems.size() <= predictionIndex) {
// Remove predicted apps from the past
+ Log.d(TAG, "Remove predicted apps from the past\nPrediction Index: "
+ + predictionIndex);
if (isPredictedIcon(child)) {
mHotseat.removeView(child);
}
@@ -221,6 +227,11 @@
}
WorkspaceItemInfo predictedItem =
(WorkspaceItemInfo) mPredictedItems.get(predictionIndex++);
+ Log.d(TAG, "Predicted item is: " + predictedItem);
+ if (child != null) {
+ Log.d(TAG, "Predicted item is enabled: " + child.isEnabled());
+ }
+
if (isPredictedIcon(child) && child.isEnabled()) {
PredictedAppIcon icon = (PredictedAppIcon) child;
boolean animateIconChange = icon.shouldAnimateIconChange(predictedItem);
@@ -240,6 +251,7 @@
}
private void bindItems(List<WorkspaceItemInfo> itemsToAdd, boolean animate) {
+ Log.d(TAG, "bindItems to hotseat: " + itemsToAdd);
AnimatorSet animationSet = new AnimatorSet();
for (WorkspaceItemInfo item : itemsToAdd) {
PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
@@ -293,8 +305,10 @@
public void setPredictedItems(FixedContainerItems items) {
mPredictedItems = new ArrayList(items.items);
if (mPredictedItems.isEmpty()) {
+ Log.d(TAG, "Predicted items is initially empty");
HotseatRestoreHelper.restoreBackup(mLauncher);
}
+ Log.d(TAG, "Predicted items: " + mPredictedItems);
fillGapsWithPrediction();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9fe0c00..0b83a88 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -306,6 +306,9 @@
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
+ // This may not be necessary and can be reverted once we move towards recreating all
+ // controllers without re-creating the window
+ mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
sharedState.disableNavBarState2, false /* animate */);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a347908..b0d2c3c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -17,7 +17,6 @@
import android.annotation.SuppressLint
import android.content.Context
-import android.content.Intent
import android.graphics.Rect
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
@@ -44,9 +43,6 @@
companion object {
private const val TAG = "TaskbarDividerPopupView"
private const val DIVIDER_POPUP_CLOSING_DELAY = 500L
- private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
- private const val CHANGE_NAVIGATION_MODE_ACTION =
- "com.android.settings.NAVIGATION_MODE_SETTINGS"
@JvmStatic
fun createAndPopulate(
@@ -103,21 +99,12 @@
super.onFinishInflate()
val taskbarSwitchOption = findViewById<LinearLayout>(R.id.taskbar_switch_option)
val alwaysShowTaskbarSwitch = findViewById<Switch>(R.id.taskbar_pinning_switch)
- val navigationModeChangeOption =
- findViewById<LinearLayout>(R.id.navigation_mode_switch_option)
alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
taskbarSwitchOption.setOnClickListener {
alwaysShowTaskbarSwitch.isClickable = true
alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
onClickAlwaysShowTaskbarSwitchOption()
}
- navigationModeChangeOption.setOnClickListener {
- context.startActivity(
- Intent(CHANGE_NAVIGATION_MODE_ACTION)
- .setPackage(SETTINGS_PACKAGE_NAME)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- )
- }
}
/** Orient object as usual and then center object horizontally. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index a935bac..c51a7ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar
+import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
import android.graphics.Insets
import android.graphics.Region
import android.os.Binder
@@ -43,6 +44,7 @@
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.DisplayController
import java.io.PrintWriter
+import kotlin.jvm.optionals.getOrNull
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -198,16 +200,22 @@
val imeInsetsSize = getInsetsForGravity(taskbarHeightForIme, gravity)
val imeInsetsSizeOverride =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
- )
+ if (!ENABLE_HIDE_IME_CAPTION_BAR) {
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(
+ TYPE_INPUT_METHOD,
+ imeInsetsSize
+ ),
+ )
+ } else {
+ arrayOf()
+ }
// Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
val visInsetsSizeForTappableElement =
if (context.isGestureNav) getInsetsForGravity(0, gravity)
else getInsetsForGravity(tappableHeight, gravity)
val insetsSizeOverrideForTappableElement =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ imeInsetsSizeOverride + arrayOf(
InsetsFrameProvider.InsetsSizeOverride(
TYPE_VOICE_INTERACTION,
visInsetsSizeForTappableElement
@@ -216,7 +224,7 @@
if ((context.isGestureNav || TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
&& provider.type == tappableElement()) {
provider.insetsSizeOverrides = insetsSizeOverrideForTappableElement
- } else if (provider.type != systemGestures()) {
+ } else if (provider.type != systemGestures() && imeInsetsSizeOverride.isNotEmpty()) {
// We only override insets at the bottom of the screen
provider.insetsSizeOverrides = imeInsetsSizeOverride
}
@@ -283,9 +291,24 @@
controllers.uiController.isInOverview &&
DisplayController.isTransientTaskbar(context)
) {
- insetsInfo.touchableRegion.set(
+ val region =
controllers.taskbarActivityContext.dragLayer.lastDrawnTransientRect.toRegion()
- )
+ val bubbleBarBounds =
+ controllers.bubbleControllers.getOrNull()?.let { bubbleControllers ->
+ if (!bubbleControllers.bubbleStashController.isBubblesShowingOnOverview) {
+ return@let null
+ }
+ if (!bubbleControllers.bubbleBarViewController.isBubbleBarVisible) {
+ return@let null
+ }
+ bubbleControllers.bubbleBarViewController.bubbleBarBounds
+ }
+
+ // Include the bounds of the bubble bar in the touchable region if they exist.
+ if (bubbleBarBounds != null) {
+ region.op(bubbleBarBounds, Region.Op.UNION)
+ }
+ insetsInfo.touchableRegion.set(region)
} else {
insetsInfo.touchableRegion.set(touchableRegion)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index c423fb3..81cff57 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -64,6 +64,7 @@
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.AssistUtils;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
@@ -176,7 +177,8 @@
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
mNavButtonController = new TaskbarNavButtonController(service,
- SystemUiProxy.INSTANCE.get(mContext), new Handler());
+ SystemUiProxy.INSTANCE.get(mContext), new Handler(),
+ AssistUtils.newInstance(mContext));
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 0f8de34..03df036 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -51,6 +51,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.AssistUtils;
import com.android.quickstep.views.DesktopTaskView;
import java.io.PrintWriter;
@@ -108,15 +109,17 @@
private final TouchInteractionService mService;
private final SystemUiProxy mSystemUiProxy;
private final Handler mHandler;
+ private final AssistUtils mAssistUtils;
@Nullable private StatsLogManager mStatsLogManager;
private final Runnable mResetLongPress = this::resetScreenUnpin;
public TaskbarNavButtonController(TouchInteractionService service,
- SystemUiProxy systemUiProxy, Handler handler) {
+ SystemUiProxy systemUiProxy, Handler handler, AssistUtils assistUtils) {
mService = service;
mSystemUiProxy = systemUiProxy;
mHandler = handler;
+ mAssistUtils = assistUtils;
}
public void onButtonClick(@TaskbarButton int buttonType, View view) {
@@ -158,7 +161,7 @@
switch (buttonType) {
case BUTTON_HOME:
logEvent(LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS);
- startAssistant();
+ onLongPressHome();
return true;
case BUTTON_A11Y:
logEvent(LAUNCHER_TASKBAR_A11Y_BUTTON_LONGPRESS);
@@ -307,13 +310,16 @@
}
}
- private void startAssistant() {
+ private void onLongPressHome() {
if (mScreenPinned || !mAssistantLongPressEnabled) {
return;
}
- Bundle args = new Bundle();
- args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
- mSystemUiProxy.startAssistant(args);
+ // Attempt to start Assist with AssistUtils, otherwise fall back to SysUi's implementation.
+ if (!mAssistUtils.tryStartAssistOverride(INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS)) {
+ Bundle args = new Bundle();
+ args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
+ mSystemUiProxy.startAssistant(args);
+ }
}
private void showQuickSettings() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 074cbe1..fa5a1ae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -88,7 +88,7 @@
private @Nullable IconButtonView mAllAppsButton;
// Only non-null when device supports having an All Apps button.
- private @Nullable View mTaskbarDivider;
+ private @Nullable IconButtonView mTaskbarDivider;
private View mQsb;
@@ -158,8 +158,12 @@
mActivityContext.getColor(R.color.all_apps_button_color));
if (FeatureFlags.ENABLE_TASKBAR_PINNING.get()) {
- mTaskbarDivider = LayoutInflater.from(context).inflate(R.layout.taskbar_divider,
+ mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
+ R.layout.taskbar_divider,
this, false);
+ mTaskbarDivider.setIconDrawable(
+ resources.getDrawable(R.drawable.taskbar_divider_button));
+ mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
}
}
@@ -382,11 +386,6 @@
int count = getChildCount();
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int spaceNeeded = getIconLayoutWidth();
- // We are removing the margin from taskbar divider item in taskbar,
- // so remove it from spacing also.
- if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && count > 1) {
- spaceNeeded -= mIconTouchSize;
- }
int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
boolean layoutRtl = isLayoutRtl();
int centerAlignIconEnd = right - (right - left - spaceNeeded) / 2;
@@ -507,7 +506,15 @@
if (deviceProfile.isQsbInline) {
countExcludingQsb--;
}
- return countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
+ int iconLayoutBoundsWidth =
+ countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
+
+ if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && countExcludingQsb > 1) {
+ // We are removing 4 * mItemMarginLeftRight as there should be no space between
+ // All Apps icon, divider icon, and first app icon in taskbar
+ iconLayoutBoundsWidth -= mItemMarginLeftRight * 4;
+ }
+ return iconLayoutBoundsWidth;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 544f9bf..d786d94 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -15,8 +15,11 @@
*/
package com.android.launcher3.taskbar.allapps;
+import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
+
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -33,7 +36,6 @@
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
-
/**
* Handles the all apps overlay window initialization, updates, and its data.
* <p>
@@ -54,9 +56,9 @@
private @Nullable TaskbarSearchSessionController mSearchSessionController;
// Application data models.
- private AppInfo[] mApps;
+ private @NonNull AppInfo[] mApps = EMPTY_ARRAY;
private int mAppsModelFlags;
- private List<ItemInfo> mPredictedApps;
+ private @NonNull List<ItemInfo> mPredictedApps = Collections.emptyList();
private @Nullable List<ItemInfo> mZeroStateSearchSuggestions;
private boolean mDisallowGlobalDrag;
private boolean mDisallowLongClick;
@@ -82,8 +84,8 @@
}
/** Updates the current {@link AppInfo} instances. */
- public void setApps(AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
- mApps = apps;
+ public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
+ mApps = apps == null ? EMPTY_ARRAY : apps;
mAppsModelFlags = flags;
mPackageUserKeytoUidMap = map;
if (mAppsView != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 537d2c6..001c3bc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -21,12 +21,16 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.window.OnBackInvokedDispatcher;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -40,8 +44,11 @@
/** Wrapper for taskbar all apps with slide-in behavior. */
public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverlayContext>
implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
+ private final Handler mHandler;
+
private TaskbarAllAppsContainerView mAppsView;
private float mShiftRange;
+ private @Nullable Runnable mShowOnFullyAttachedToWindowRunnable;
// Initialized in init.
private TaskbarAllAppsCallbacks mAllAppsCallbacks;
@@ -53,6 +60,7 @@
public TaskbarAllAppsSlideInView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mHandler = new Handler(Looper.myLooper());
}
void init(TaskbarAllAppsCallbacks callbacks) {
@@ -65,14 +73,14 @@
return;
}
mIsOpen = true;
- attachToContainer();
addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
removeOnAttachStateChangeListener(this);
// Wait for view and its descendants to be fully attached before starting open.
- post(() -> showOnFullyAttachedToWindow(animate));
+ mShowOnFullyAttachedToWindowRunnable = () -> showOnFullyAttachedToWindow(animate);
+ mHandler.post(mShowOnFullyAttachedToWindowRunnable);
}
@Override
@@ -80,6 +88,7 @@
removeOnAttachStateChangeListener(this);
}
});
+ attachToContainer();
}
private void showOnFullyAttachedToWindow(boolean animate) {
@@ -114,6 +123,10 @@
@Override
protected void handleClose(boolean animate) {
+ if (mShowOnFullyAttachedToWindowRunnable != null) {
+ mHandler.removeCallbacks(mShowOnFullyAttachedToWindowRunnable);
+ mShowOnFullyAttachedToWindowRunnable = null;
+ }
if (mIsOpen) {
mAllAppsCallbacks.onAllAppsTransitionStart(false);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index ffe077b..c482911 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -280,7 +280,7 @@
// the position of the bubble when the bar is fully expanded
final float expandedX = i * (mIconSize + mIconSpacing);
// the position of the bubble when the bar is fully collapsed
- final float collapsedX = i * mIconOverlapAmount;
+ final float collapsedX = i == 0 ? 0 : mIconOverlapAmount;
if (mIsBarExpanded) {
// where the bubble will end up when the animation ends
@@ -292,12 +292,22 @@
}
// When we're expanded, we're not stacked so we're not behind the stack
bv.setBehindStack(false, animate);
+ bv.setAlpha(1);
} else {
final float targetX = currentWidth - collapsedWidth + collapsedX;
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
// If we're not the first bubble we're behind the stack
bv.setBehindStack(i > 0, animate);
+ // If we're fully collapsed, hide all bubbles except for the first 2. If there are
+ // only 2 bubbles, hide the second bubble as well because it's the overflow.
+ if (widthState == 0) {
+ if (i > 1) {
+ bv.setAlpha(0);
+ } else if (i == 1 && bubbleCount == 2) {
+ bv.setAlpha(0);
+ }
+ }
}
}
@@ -458,7 +468,11 @@
private float collapsedWidth() {
final int childCount = getChildCount();
final int horizontalPadding = getPaddingStart() + getPaddingEnd();
- return mIconSize + ((childCount - 1) * mIconOverlapAmount) + horizontalPadding;
+ // If there are more than 2 bubbles, the first 2 should be visible when collapsed.
+ // Otherwise just the first bubble should be visible because we don't show the overflow.
+ return childCount > 2
+ ? mIconSize + mIconOverlapAmount + horizontalPadding
+ : mIconSize + horizontalPadding;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 0ff0469..41c3dec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -17,7 +17,6 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import android.os.SystemProperties;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -43,10 +42,6 @@
public class BubbleDismissController {
private static final String TAG = BubbleDismissController.class.getSimpleName();
private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
- // LINT.IfChange
- private static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
- SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
- // LINT.ThenChange(com/android/wm/shell/bubbles/BubbleStackView.java)
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mDragLayer;
@Nullable
@@ -182,7 +177,6 @@
};
mMagnetizedObject.setHapticsEnabled(true);
- mMagnetizedObject.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
mMagnetizedObject.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
if (mMagneticTarget != null) {
mMagnetizedObject.addTarget(mMagneticTarget);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 00c2ca1..a5ea5a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -197,6 +197,11 @@
}
}
+ /** Whether bubbles are showing on Overview. */
+ public boolean isBubblesShowingOnOverview() {
+ return mBubblesShowingOnOverview;
+ }
+
/** Called when sysui locked state changes, when locked, bubble bar is stashed. */
public void onSysuiLockedStateChange(boolean isSysuiLocked) {
if (isSysuiLocked != mIsSysuiLocked) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index a53dc15..475f465 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -16,13 +16,16 @@
package com.android.launcher3.uioverrides;
+import android.app.ActivityOptions;
import android.app.Person;
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.window.RemoteTransition;
import com.android.launcher3.Utilities;
+import com.android.quickstep.util.FadeOutRemoteTransition;
import java.util.Map;
@@ -41,4 +44,13 @@
public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
return context.getSystemService(LauncherApps.class).getActivityOverrides();
}
+
+ /**
+ * Creates an ActivityOptions to play fade-out animation on closing targets
+ */
+ public static ActivityOptions createFadeOutAnimOptions(Context context) {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setRemoteTransition(new RemoteTransition(new FadeOutRemoteTransition()));
+ return options;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 08ce794..24bc58f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -33,9 +33,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
-import static com.android.launcher3.config.FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -59,8 +57,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -70,19 +66,16 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.hardware.SensorManager;
-import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.media.permission.SafeCloseable;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.SystemProperties;
import android.os.Trace;
+import android.util.Log;
import android.view.Display;
import android.view.HapticFeedbackConstants;
-import android.view.RemoteAnimationTarget;
import android.view.View;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -110,7 +103,6 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
@@ -162,10 +154,7 @@
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LauncherUnfoldAnimationController;
-import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
-import com.android.quickstep.util.RemoteAnimationProvider;
-import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SplitToWorkspaceController;
import com.android.quickstep.util.SplitWithKeyboardShortcutController;
@@ -178,14 +167,11 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.unfold.RemoteUnfoldSharedComponent;
-import com.android.systemui.unfold.UnfoldSharedComponent;
import com.android.systemui.unfold.UnfoldTransitionFactory;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
-import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider;
-import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider;
import com.android.systemui.unfold.updates.RotationChangeProvider;
import java.io.FileDescriptor;
@@ -200,9 +186,12 @@
import java.util.stream.Stream;
public class QuickstepLauncher extends Launcher {
+ private static final boolean TRACE_LAYOUTS =
+ SystemProperties.getBoolean("persist.debug.trace_layouts", false);
+ private static final String TRACE_RELAYOUT_CLASS =
+ SystemProperties.get("persist.debug.trace_request_layout_class", null);
- public static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
- SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
+ private static final String TAG = "QuickstepLauncher";
public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
@@ -217,7 +206,6 @@
private TISBindHelper mTISBindHelper;
private @Nullable LauncherTaskbarUIController mTaskbarUIController;
// Will be updated when dragging from taskbar.
- private @Nullable DragOptions mNextWorkspaceDragOptions = null;
private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
@@ -439,12 +427,8 @@
boolean visible = (state == NORMAL || state == OVERVIEW)
&& (willUserBeActive || isUserActive())
&& !profile.isVerticalBarLayout();
- if (ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
- SystemUiProxy.INSTANCE.get(this)
- .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx);
- } else {
- SystemUiProxy.INSTANCE.get(this).setShelfHeight(visible, profile.hotseatBarSizePx);
- }
+ SystemUiProxy.INSTANCE.get(this)
+ .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx);
}
if (state == NORMAL && !inTransition) {
((RecentsView) getOverviewPanel()).setSwipeDownShouldLaunchApp(false);
@@ -453,6 +437,7 @@
@Override
public void bindExtraContainerItems(FixedContainerItems item) {
+ Log.d(TAG, "Bind extra container items");
if (item.containerId == Favorites.CONTAINER_PREDICTION) {
mAllAppsPredictions = item;
PredictionRowView<?> predictionRowView =
@@ -460,6 +445,7 @@
PredictionRowView.class);
predictionRowView.setPredictedApps(item.items);
} else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
+ Log.d(TAG, "Bind extra container item is hotseat prediction");
mHotseatPredictionController.setPredictedItems(item);
} else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) {
getPopupDataProvider().setRecommendedWidgets(item.items);
@@ -476,10 +462,7 @@
public void onDestroy() {
mAppTransitionManager.onActivityDestroyed();
if (mUnfoldTransitionProgressProvider != null) {
- if (FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
- SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
- }
-
+ SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
mUnfoldTransitionProgressProvider.destroy();
}
@@ -493,6 +476,10 @@
mDesktopVisibilityController.unregisterSystemUiListener();
}
+ if (mSplitSelectStateController != null) {
+ mSplitSelectStateController.onDestroy();
+ }
+
super.onDestroy();
mHotseatPredictionController.destroy();
mSplitWithKeyboardShortcutController.onDestroy();
@@ -615,6 +602,8 @@
mViewCapture = SettingsAwareViewCapture.getInstance(this).startCapture(getWindow());
}
getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE);
+ View.setTraceLayoutSteps(TRACE_LAYOUTS);
+ View.setTracedRequestLayoutClassClass(TRACE_RELAYOUT_CLASS);
}
@Override
@@ -914,43 +903,10 @@
private void initUnfoldTransitionProgressProvider() {
final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
if (config.isEnabled()) {
- if (RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
- initRemotelyCalculatedUnfoldAnimation(config);
- } else {
- initLocallyCalculatedUnfoldAnimation(config);
- }
-
+ initRemotelyCalculatedUnfoldAnimation(config);
}
}
- /** Registers hinge angle listener and calculates the animation progress in this process. */
- private void initLocallyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
- UnfoldSharedComponent unfoldComponent =
- UnfoldTransitionFactory.createUnfoldSharedComponent(
- /* context= */ this,
- config,
- ProxyScreenStatusProvider.INSTANCE,
- new DeviceStateManagerFoldProvider(
- getSystemService(DeviceStateManager.class), /* context= */ this),
- new ActivityManagerActivityTypeProvider(
- getSystemService(ActivityManager.class)),
- getSystemService(SensorManager.class),
- getMainThreadHandler(),
- getMainExecutor(),
- /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
- /* tracingTagPrefix= */ "launcher",
- getSystemService(DisplayManager.class)
- );
-
- mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider()
- .orElseThrow(() -> new IllegalStateException(
- "Trying to create UnfoldTransitionProgressProvider when the "
- + "transition is disabled"));
-
- initUnfoldAnimationController(mUnfoldTransitionProgressProvider,
- unfoldComponent.getRotationChangeProvider());
- }
-
/** Receives animation progress from sysui process. */
private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
RemoteUnfoldSharedComponent unfoldComponent =
@@ -1043,41 +999,6 @@
}
@Override
- public DragOptions getDefaultWorkspaceDragOptions() {
- if (mNextWorkspaceDragOptions != null) {
- DragOptions options = mNextWorkspaceDragOptions;
- mNextWorkspaceDragOptions = null;
- return options;
- }
- return super.getDefaultWorkspaceDragOptions();
- }
-
- public void setNextWorkspaceDragOptions(DragOptions dragOptions) {
- mNextWorkspaceDragOptions = dragOptions;
- }
-
- @Override
- public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
- QuickstepTransitionManager appTransitionManager = getAppTransitionManager();
- appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
- @Override
- public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets) {
-
- // On the first call clear the reference.
- signal.cancel();
-
- ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
- fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets,
- wallpaperTargets));
- AnimatorSet anim = new AnimatorSet();
- anim.play(fadeAnimation);
- return anim;
- }
- }, signal);
- }
-
- @Override
public float[] getNormalOverviewScaleAndOffset() {
return DisplayController.getNavigationMode(this).hasGestures
? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 4075388..ca598c8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -119,9 +119,6 @@
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
if (fromState == NORMAL && mDidTouchStartInNavBar) {
return HINT_STATE;
- } else if (fromState == OVERVIEW && isDragTowardPositive) {
- // Don't allow swiping up to all apps.
- return OVERVIEW;
}
return super.getTargetState(fromState, isDragTowardPositive);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 454a1f5..e30fe66 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -96,8 +96,6 @@
return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
? mLauncher.getStateManager().getLastState()
: NORMAL;
- } else if (fromState == OVERVIEW) {
- return isDragTowardPositive ? OVERVIEW : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) {
return ALL_APPS;
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 796840d..1ef4039 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -34,7 +34,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.uioverrides.QuickstepLauncher.ENABLE_PIP_KEEP_CLEAR_ALGORITHM;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -194,6 +193,7 @@
ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
mRecentsView = null;
mActivity = null;
+ mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
}
};
@@ -518,20 +518,22 @@
// Set up a entire animation lifecycle callback to notify the current recents view when
// the animation is canceled
mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
- HashMap<Integer, ThumbnailData> snapshots =
- mGestureState.consumeRecentsAnimationCanceledSnapshot();
- if (snapshots != null) {
- mRecentsView.switchToScreenshot(snapshots, () -> {
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.cleanupScreenshot();
- } else if (mDeferredCleanupRecentsAnimationController != null) {
- mDeferredCleanupRecentsAnimationController.cleanupScreenshot();
- mDeferredCleanupRecentsAnimationController = null;
- }
- });
- mRecentsView.onRecentsAnimationComplete();
- }
- });
+ if (mRecentsView == null) return;
+
+ HashMap<Integer, ThumbnailData> snapshots =
+ mGestureState.consumeRecentsAnimationCanceledSnapshot();
+ if (snapshots != null) {
+ mRecentsView.switchToScreenshot(snapshots, () -> {
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.cleanupScreenshot();
+ } else if (mDeferredCleanupRecentsAnimationController != null) {
+ mDeferredCleanupRecentsAnimationController.cleanupScreenshot();
+ mDeferredCleanupRecentsAnimationController = null;
+ }
+ });
+ mRecentsView.onRecentsAnimationComplete();
+ }
+ });
setupRecentsViewUi();
mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll);
@@ -1753,11 +1755,6 @@
private Rect getKeepClearAreaForHotseat() {
Rect keepClearArea;
- if (!ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
- // make the height equal to hotseatBarSizePx only
- keepClearArea = new Rect(0, 0, 0, mDp.hotseatBarSizePx);
- return keepClearArea;
- }
// the keep clear area in global screen coordinates, in pixels
if (mDp.isPhone) {
if (mDp.isSeascape()) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 2e1a62c..72439de 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -37,6 +37,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Trace;
+import android.util.Log;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
@@ -59,7 +60,6 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
@@ -67,6 +67,7 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.FallbackTaskbarUIController;
import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.RunnableList;
@@ -393,7 +394,7 @@
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
mActivityLaunchAnimationRunner = null;
-
+ mSplitSelectStateController.onDestroy();
mTISBindHelper.onDestroy();
}
@@ -404,6 +405,7 @@
}
public void startHome() {
+ Log.d(TestProtocol.INCORRECT_HOME_STATE, "start home from recents activity");
RecentsView recentsView = getOverviewPanel();
recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
this::startHomeInternal));
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index e73b525..fae929a 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -62,6 +62,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.quickstep.util.AssistUtils;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -250,6 +251,8 @@
setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
setUnfoldAnimationListener(mUnfoldAnimationListener);
setDesktopTaskListener(mDesktopTaskListener);
+ setAssistantOverridesRequested(
+ AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
}
/**
@@ -374,6 +377,17 @@
}
@Override
+ public void setAssistantOverridesRequested(int[] invocationTypes) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.setAssistantOverridesRequested(invocationTypes);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call setAssistantOverridesRequested", e);
+ }
+ }
+ }
+
+ @Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (mSystemUiProxy != null) {
try {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 6dbb5bf..0de4ffc 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -38,6 +38,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.ActiveGestureLog;
@@ -124,13 +125,14 @@
// If mCallbacks still != null, that means we are getting this startRecentsAnimation()
// before the previous one got onRecentsAnimationStart(). In that case, cleanup the
// previous animation so it doesn't mess up/listen to state changes in this animation.
- cleanUpRecentsAnimation();
+ cleanUpRecentsAnimation(mCallbacks);
}
final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
mLastGestureState = gestureState;
- mCallbacks = new RecentsAnimationCallbacks(SystemUiProxy.INSTANCE.get(mCtx),
- activityInterface.allowMinimizeSplitScreen());
+ RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
+ SystemUiProxy.INSTANCE.get(mCtx), activityInterface.allowMinimizeSplitScreen());
+ mCallbacks = newCallbacks;
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
@@ -156,12 +158,12 @@
@Override
public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
- cleanUpRecentsAnimation();
+ cleanUpRecentsAnimation(newCallbacks);
}
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- cleanUpRecentsAnimation();
+ cleanUpRecentsAnimation(newCallbacks);
}
@Override
@@ -179,6 +181,9 @@
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
if (recentsView != null) {
+ Log.d(TestProtocol.INCORRECT_HOME_STATE,
+ "finish recents animation on "
+ + compat.taskInfo.description);
recentsView.finishRecentsAnimation(true, null);
}
return;
@@ -330,7 +335,6 @@
if (mController != null) {
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "finishRunningRecentsAnimation", toHome);
- mCallbacks.notifyAnimationCanceled();
if (forceFinish) {
mController.finishController(toHome, null, false /* sendUserLeaveHint */,
true /* forceFinish */);
@@ -339,7 +343,6 @@
? mController::finishAnimationToHome
: mController::finishAnimationToApp);
}
- cleanUpRecentsAnimation();
}
}
@@ -366,7 +369,12 @@
/**
* Cleans up the recents animation entirely.
*/
- private void cleanUpRecentsAnimation() {
+ private void cleanUpRecentsAnimation(RecentsAnimationCallbacks targetCallbacks) {
+ if (mCallbacks != targetCallbacks) {
+ ActiveGestureLog.INSTANCE.addLog(
+ /* event= */ "cleanUpRecentsAnimation skipped due to wrong callbacks");
+ return;
+ }
ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation");
if (mLiveTileCleanUpHandler != null) {
mLiveTileCleanUpHandler.run();
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 06f1f9a..076f4b1 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -122,6 +122,12 @@
public void removeListeners() {
}
+ /**
+ * Clears any active state outside of the TaskOverlay lifecycle which might have built
+ * up over time
+ */
+ public void clearAllActiveState() { }
+
/** Note that these will be shown in order from top to bottom, if available for the task. */
private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{
TaskShortcutFactory.APP_INFO,
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 2d5b8db..af49774 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -413,20 +413,14 @@
}
/**
- * TODO: This doesn't animate at present. Feel free to blow out everyhing in this method
- * if needed
+ * If {@param launchingTaskView} is not null, then this will play the tasks launch animation
+ * from the position of the GroupedTaskView (when user taps on the TaskView to start it).
+ * Technically this case should be taken care of by
+ * {@link #composeRecentsSplitLaunchAnimatorLegacy} below, but the way we launch tasks whether
+ * it's a single task or multiple tasks results in different entry-points.
*
- * We could manually try to animate the just the bounds for the leashes we get back, but we try
- * to do it through TaskViewSimulator(TVS) since that handles a lot of the recents UI stuff for
- * us.
- *
- * First you have to call TVS#setPreview() to indicate which leash it will operate one
- * Then operations happen in TVS#apply() on each frame callback.
- *
- * TVS uses DeviceProfile to try to figure out things like task height and such based on if the
- * device is in multiWindowMode or not. It's unclear given the two calls to startTask() when the
- * device is considered in multiWindowMode and things like insets and stuff change
- * and calculations have to be adjusted in the animations for that
+ * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
+ * case where launcher handles animating starting split tasks from app icon)
*/
public static void composeRecentsSplitLaunchAnimator(GroupedTaskView launchingTaskView,
@NonNull StateManager stateManager, @Nullable DepthController depthController,
@@ -461,9 +455,9 @@
return;
}
- // TODO: consider initialTaskPendingIntent
TransitionInfo.Change splitRoot1 = null;
TransitionInfo.Change splitRoot2 = null;
+ final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
if (change.getTaskInfo() == null) {
@@ -484,32 +478,48 @@
if (taskId == initialTaskId) {
splitRoot1 = change.getParent() == null ? change :
transitionInfo.getChange(change.getParent());
+ openingTargets.add(splitRoot1.getLeash());
}
if (taskId == secondTaskId) {
splitRoot2 = change.getParent() == null ? change :
transitionInfo.getChange(change.getParent());
+ openingTargets.add(splitRoot2.getLeash());
}
}
- // This is where we should animate the split roots. For now, though, just make them visible.
- animateSplitRoot(t, splitRoot1);
- animateSplitRoot(t, splitRoot2);
+ SurfaceControl.Transaction animTransaction = new SurfaceControl.Transaction();
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(SPLIT_LAUNCH_DURATION);
+ animator.addUpdateListener(valueAnimator -> {
+ float progress = valueAnimator.getAnimatedFraction();
+ for (SurfaceControl leash: openingTargets) {
+ animTransaction.setAlpha(leash, progress);
+ }
+ animTransaction.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ for (SurfaceControl leash: openingTargets) {
+ animTransaction.show(leash)
+ .setAlpha(leash, 0.0f);
+ }
+ animTransaction.apply();
+ }
- // This contains the initial state (before animation), so apply this at the beginning of
- // the animation.
- t.apply();
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishCallback.run();
+ }
+ });
- // Once there is an animation, this should be called AFTER the animation completes.
- finishCallback.run();
- }
-
- private static void animateSplitRoot(SurfaceControl.Transaction t,
- TransitionInfo.Change splitRoot) {
- testLogD(LAUNCH_SPLIT_PAIR, "animateSplitRoot: " + splitRoot);
- if (splitRoot != null) {
- t.show(splitRoot.getLeash());
- t.setAlpha(splitRoot.getLeash(), 1.f);
+ if (splitRoot1 != null && splitRoot1.getParent() != null) {
+ // Set the highest level split root alpha; we could technically use the parent of either
+ // splitRoot1 or splitRoot2
+ t.setAlpha(transitionInfo.getChange(splitRoot1.getParent()).getLeash(), 1f);
}
+ t.apply();
+ animator.start();
}
/**
@@ -522,7 +532,9 @@
* it's a single task or multiple tasks results in different entry-points.
*
* If it is null, then it will simply fade in the starting apps and fade out launcher (for the
- * case where launcher handles animating starting split tasks from app icon) */
+ * case where launcher handles animating starting split tasks from app icon)
+ * @deprecated with shell transitions
+ */
public static void composeRecentsSplitLaunchAnimatorLegacy(
@Nullable GroupedTaskView launchingTaskView, int initialTaskId, int secondTaskId,
@NonNull RemoteAnimationTarget[] appTargets,
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7a9f88a..c1680de 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -70,6 +70,7 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.Choreographer;
+import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -116,7 +117,7 @@
import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
-import com.android.quickstep.util.ProxyScreenStatusProvider;
+import com.android.quickstep.util.AssistUtils;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -280,6 +281,20 @@
}));
}
+ /**
+ * Sent when the assistant has been invoked with the given type (defined in AssistManager)
+ * and should be shown. This method is used if SystemUiProxy#setAssistantOverridesRequested
+ * was previously called including this invocation type.
+ */
+ @Override
+ public void onAssistantOverrideInvoked(int invocationType) {
+ executeForTouchInteractionService(tis -> {
+ if (!AssistUtils.newInstance(tis).tryStartAssistOverride(invocationType)) {
+ Log.w(TAG, "Failed to invoke Assist override");
+ }
+ });
+ }
+
@Override
public void onNavigationBarSurface(SurfaceControl surface) {
// TODO: implement
@@ -302,24 +317,6 @@
@BinderThread
@Override
- public void onScreenTurnedOn() {
- MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurnedOn);
- }
-
- @BinderThread
- @Override
- public void onScreenTurningOn() {
- MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOn);
- }
-
- @BinderThread
- @Override
- public void onScreenTurningOff() {
- MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOff);
- }
-
- @BinderThread
- @Override
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
executeForTouchInteractionService(tis -> {
StatefulActivity activity =
@@ -771,7 +768,7 @@
if (mGestureState.isTrackpadGesture() && (action == ACTION_POINTER_DOWN
|| action == ACTION_POINTER_UP)) {
// Skip ACTION_POINTER_DOWN and ACTION_POINTER_UP events from trackpad.
- } else if (event.isHoverEvent()) {
+ } else if (isCursorHoverEvent(event)) {
mUncheckedConsumer.onHoverEvent(event);
} else {
mUncheckedConsumer.onMotionEvent(event);
@@ -783,6 +780,11 @@
traceToken.close();
}
+ // Talkback generates hover events on touch, which we do not want to consume.
+ private boolean isCursorHoverEvent(MotionEvent event) {
+ return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
+ }
+
private InputConsumer tryCreateAssistantInputConsumer(
GestureState gestureState, MotionEvent motionEvent) {
return tryCreateAssistantInputConsumer(
@@ -914,7 +916,8 @@
base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
mOverviewCommandHelper);
}
- } else if (canStartSystemGesture && FeatureFlags.ENABLE_LONG_PRESS_NAV_HANDLE.get()) {
+ } else if (canStartSystemGesture && FeatureFlags.ENABLE_LONG_PRESS_NAV_HANDLE.get()
+ && !previousGestureState.isRecentsAnimationRunning()) {
base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 5c5b9ca..7a2b343 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -33,12 +35,15 @@
}
/**
- * Called when nav handle is long pressed.
- *
- * @return if the long press was consumed, meaning other input consumers should receive a
- * cancel event
+ * Called when nav handle is long pressed to get the Runnable that should be executed by the
+ * caller to invoke long press behavior. If null is returned that means long press couldn't be
+ * handled.
+ * <p>
+ * A Runnable is returned here to ensure the InputConsumer can call
+ * {@link android.view.InputMonitor#pilferPointers()} before invoking the long press behavior
+ * since pilfering can break the long press behavior.
*/
- public boolean onLongPress() {
- return false;
+ public @Nullable Runnable getLongPressRunnable() {
+ return null;
}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 542dea1..a9accb7 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -38,8 +38,8 @@
public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor) {
super(delegate, inputMonitor);
- mNavHandleWidth = context.getResources()
- .getDimensionPixelSize(R.dimen.navigation_home_handle_width);
+ mNavHandleWidth = context.getResources().getDimensionPixelSize(
+ R.dimen.navigation_home_handle_width);
mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);
@@ -48,8 +48,11 @@
@Override
public void onLongPress(MotionEvent motionEvent) {
if (isInArea(motionEvent.getRawX())) {
- if (mNavHandleLongPressHandler.onLongPress()) {
+ Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
+ if (longPressRunnable != null) {
setActive(motionEvent);
+
+ longPressRunnable.run();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 2816228..4c66504 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -278,7 +278,8 @@
if (!mIsDeferredDownTarget) {
// Normal gesture, ensure we pass the drag slop before we start tracking
// the gesture
- if (Math.abs(displacement) > mTouchSlop) {
+ if (mGestureState.isTrackpadGesture() || Math.abs(displacement)
+ > mTouchSlop) {
mPassedWindowMoveSlop = true;
mStartDisplacement = Math.min(displacement, -mTouchSlop);
}
@@ -287,8 +288,8 @@
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
- boolean passedSlop = squaredHypot(displacementX, displacementY)
- >= mSquaredTouchSlop;
+ boolean passedSlop = mGestureState.isTrackpadGesture() || squaredHypot(
+ displacementX, displacementY) >= mSquaredTouchSlop;
if (!mPassedSlopOnThisGesture && passedSlop) {
mPassedSlopOnThisGesture = true;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 4b13cd1..0e90e50 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.inputconsumers;
-import static android.view.MotionEvent.ACTION_BUTTON_RELEASE;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
@@ -29,6 +28,7 @@
import android.graphics.Rect;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.InputDevice;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -130,8 +130,8 @@
public void onMotionEvent(MotionEvent ev) {
mLongPressDetector.onTouchEvent(ev);
if (mState != STATE_ACTIVE) {
- boolean isStashedTaskbarHovered =
- isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
+ boolean isStashedTaskbarHovered = isMouseEvent(ev)
+ && isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
if (!isStashedTaskbarHovered) {
mDelegate.onMotionEvent(ev);
}
@@ -229,7 +229,7 @@
mHasPassedTaskbarNavThreshold = false;
mIsInBubbleBarArea = false;
break;
- case ACTION_BUTTON_RELEASE:
+ case MotionEvent.ACTION_BUTTON_RELEASE:
if (isStashedTaskbarHovered) {
mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
}
@@ -342,4 +342,8 @@
dp.heightPx);
return mStashedTaskbarHandleBounds.contains(x, y);
}
+
+ private boolean isMouseEvent(MotionEvent event) {
+ return event.getSource() == InputDevice.SOURCE_MOUSE;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index ed2d18a..545a94d 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -226,13 +226,11 @@
return;
}
Matrix scaleMatrix = new Matrix();
- float pivotX = mScreenWidth / 2f;
- float pivotY = mScreenHeight;
float scaleFactor = mScreenWidth / animationBoundsRect.width();
+ float heightTranslate = (mScreenHeight - (scaleFactor * animationBoundsRect.height()));
- scaleMatrix.postScale(scaleFactor, scaleFactor, pivotX, pivotY);
- scaleMatrix.postTranslate(0,
- mTutorialFragment.getDeviceProfile().heightPx - animationBoundsRect.height());
+ scaleMatrix.postScale(scaleFactor, scaleFactor);
+ scaleMatrix.postTranslate(0, heightTranslate);
mAnimatedGestureDemonstration.setImageMatrix(scaleMatrix);
}
diff --git a/quickstep/src/com/android/quickstep/util/AssistUtils.java b/quickstep/src/com/android/quickstep/util/AssistUtils.java
new file mode 100644
index 0000000..11b6ea7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/AssistUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.content.Context;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+/** Utilities to work with Assistant functionality. */
+public class AssistUtils implements ResourceBasedOverride {
+
+ public AssistUtils() {}
+
+ /** Creates AssistUtils as specified by overrides */
+ public static AssistUtils newInstance(Context context) {
+ return Overrides.getObject(AssistUtils.class, context, R.string.assist_utils_class);
+ }
+
+ /** @return Array of AssistUtils.INVOCATION_TYPE_* that we want to handle instead of SysUI. */
+ public int[] getSysUiAssistOverrideInvocationTypes() {
+ return new int[0];
+ }
+
+ /**
+ * @return {@code true} if the override was handled, i.e. an assist surface was shown or the
+ * request should be ignored. {@code false} means the caller should start assist another way.
+ */
+ public boolean tryStartAssistOverride(int invocationType) {
+ return false;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
new file mode 100644
index 0000000..59ff81d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import android.animation.ValueAnimator
+import android.os.IBinder
+import android.os.RemoteException
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.TransitionInfo
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.Executors
+import com.android.wm.shell.util.TransitionUtil
+
+/** Remote animation which fades out the closing targets */
+class FadeOutRemoteTransition : IRemoteTransition.Stub() {
+
+ override fun mergeAnimation(
+ iBinder: IBinder,
+ transitionInfo: TransitionInfo,
+ transaction: Transaction,
+ mergeTarget: IBinder,
+ finishCB: IRemoteTransitionFinishedCallback
+ ) {
+
+ try {
+ finishCB.onTransitionFinished(null, Transaction())
+ } catch (e: RemoteException) {
+ // Ignore
+ }
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startT: Transaction,
+ finishCB: IRemoteTransitionFinishedCallback
+ ) {
+ val anim = ValueAnimator.ofFloat(1f, 0f)
+
+ val closingControls: MutableList<SurfaceControl> = mutableListOf()
+ for (chg in info.changes) {
+ startT.show(chg.leash)
+ if (TransitionUtil.isClosingType(chg.mode)) {
+ closingControls.add(chg.leash)
+ }
+ }
+ startT.apply()
+
+ anim.addUpdateListener {
+ val t = Transaction()
+ closingControls.forEach { t.setAlpha(it, anim.animatedValue as Float) }
+ t.apply()
+ }
+ anim.addListener(
+ forEndCallback(
+ Runnable {
+ val t = Transaction()
+ closingControls.forEach { t.hide(it) }
+ try {
+ finishCB.onTransitionFinished(null, t)
+ } catch (e: RemoteException) {
+ // Ignore
+ }
+ }
+ )
+ )
+
+ Executors.MAIN_EXECUTOR.execute { anim.start() }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
deleted file mode 100644
index 8f79ccf..0000000
--- a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
+++ /dev/null
@@ -1,61 +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.quickstep.util;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.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);
- }
-
- /** Called when the screen is starting to turn on. */
- public void onScreenTurningOn() {
- mListeners.forEach(ScreenListener::onScreenTurningOn);
- }
-
- /** Called when the screen is starting to turn off. */
- public void onScreenTurningOff() {
- mListeners.forEach(ScreenListener::onScreenTurningOff);
- }
-
- @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/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
deleted file mode 100644
index 10f2eaa..0000000
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ /dev/null
@@ -1,47 +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.quickstep.util;
-
-import android.animation.AnimatorSet;
-import android.view.RemoteAnimationTarget;
-
-public abstract class RemoteAnimationProvider {
-
- public abstract AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets);
-
- /**
- * @return the target with the lowest opaque layer for a certain app animation, or null.
- */
- public static RemoteAnimationTarget findLowestOpaqueLayerTarget(
- RemoteAnimationTarget[] appTargets, int mode) {
- int lowestLayer = Integer.MAX_VALUE;
- int lowestLayerIndex = -1;
- for (int i = appTargets.length - 1; i >= 0; i--) {
- RemoteAnimationTarget target = appTargets[i];
- if (target.mode == mode && !target.isTranslucent) {
- int layer = target.prefixOrderIndex;
- if (layer < lowestLayer) {
- lowestLayer = layer;
- lowestLayerIndex = i;
- }
- }
- }
- return lowestLayerIndex != -1
- ? appTargets[lowestLayerIndex]
- : null;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
deleted file mode 100644
index 382cf79..0000000
--- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
+++ /dev/null
@@ -1,57 +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.quickstep.util;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl.Transaction;
-
-import com.android.quickstep.RemoteAnimationTargets;
-
-/**
- * Animation listener which fades out the closing targets
- */
-public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener {
-
- private final RemoteAnimationTargets mTarget;
- private boolean mFirstFrame = true;
-
- public RemoteFadeOutAnimationListener(RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets) {
- mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets,
- new RemoteAnimationTarget[0], MODE_CLOSING);
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- Transaction t = new Transaction();
- if (mFirstFrame) {
- for (RemoteAnimationTarget target : mTarget.unfilteredApps) {
- t.show(target.leash);
- }
- mFirstFrame = false;
- }
-
- float alpha = 1 - valueAnimator.getAnimatedFraction();
- for (RemoteAnimationTarget app : mTarget.apps) {
- t.setAlpha(app.leash, alpha);
- }
- t.apply();
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 5565139..d4ddf76 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCH_SPLIT_PAIR;
import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
@@ -113,7 +114,7 @@
public class SplitSelectStateController {
private static final String TAG = "SplitSelectStateCtor";
- private final Context mContext;
+ private Context mContext;
private final Handler mHandler;
private final RecentsModel mRecentTasksModel;
private final SplitAnimationController mSplitAnimationController;
@@ -157,6 +158,10 @@
mSplitSelectDataHolder = new SplitSelectDataHolder(mContext);
}
+ public void onDestroy() {
+ mContext = null;
+ }
+
/**
* @param alreadyRunningTask if set to {@link android.app.ActivityTaskManager#INVALID_TASK_ID}
* then @param intent will be used to launch the initial task
@@ -504,10 +509,6 @@
mSplitFromDesktopController = new SplitFromDesktopController(launcher);
}
- public void enterSplitFromDesktop(ActivityManager.RunningTaskInfo taskInfo) {
- mSplitFromDesktopController.enterSplitSelect(taskInfo);
- }
-
private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
@Nullable Consumer<Boolean> callback, String transitionName) {
final RemoteSplitLaunchTransitionRunner animationRunner =
@@ -592,9 +593,8 @@
if (mSuccessCallback != null) {
mSuccessCallback.accept(true);
}
+ resetState();
});
- // After successful launch, call resetState
- resetState();
});
}
@@ -742,9 +742,11 @@
R.dimen.split_placeholder_inset);
mSplitSelectListener = new ISplitSelectListener.Stub() {
@Override
- public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo) {
+ public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
+ int splitPosition, Rect taskBounds) {
if (!ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE.get()) return false;
- MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo));
+ MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
+ taskBounds));
return true;
}
};
@@ -754,8 +756,11 @@
/**
* Enter split select from desktop mode.
* @param taskInfo the desktop task to move to split stage
+ * @param splitPosition the stage position used for this transition
+ * @param taskBounds the bounds of the task, used for {@link FloatingTaskView} animation
*/
- public void enterSplitSelect(ActivityManager.RunningTaskInfo taskInfo) {
+ public void enterSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
+ int splitPosition, Rect taskBounds) {
mTaskInfo = taskInfo;
String packageName = mTaskInfo.realActivity.getPackageName();
PackageManager pm = mLauncher.getApplicationContext().getPackageManager();
@@ -771,7 +776,7 @@
false /* allowMinimizeSplitScreen */);
DesktopSplitRecentsAnimationListener listener =
- new DesktopSplitRecentsAnimationListener();
+ new DesktopSplitRecentsAnimationListener(splitPosition, taskBounds);
MAIN_EXECUTOR.execute(() -> {
callbacks.addListener(listener);
@@ -787,12 +792,23 @@
private class DesktopSplitRecentsAnimationListener implements
RecentsAnimationCallbacks.RecentsAnimationListener {
private final Rect mTempRect = new Rect();
+ private final RectF mTaskBounds = new RectF();
+ private final int mSplitPosition;
+
+ DesktopSplitRecentsAnimationListener(int splitPosition, Rect taskBounds) {
+ mSplitPosition = splitPosition;
+ mTaskBounds.set(taskBounds);
+ }
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
- setInitialTaskSelect(mTaskInfo, STAGE_POSITION_BOTTOM_OR_RIGHT,
- null, LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM);
+ StatsLogManager.LauncherEvent launcherDesktopSplitEvent =
+ mSplitPosition == STAGE_POSITION_BOTTOM_OR_RIGHT ?
+ LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM :
+ LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP;
+ setInitialTaskSelect(mTaskInfo, mSplitPosition,
+ null, launcherDesktopSplitEvent);
RecentsView recentsView = mLauncher.getOverviewPanel();
recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
@@ -801,14 +817,12 @@
PendingAnimation anim = new PendingAnimation(
SplitAnimationTimings.TABLET_HOME_TO_SPLIT.getDuration());
- RectF startingTaskRect = new RectF(mTaskInfo.configuration.windowConfiguration
- .getBounds());
final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(
mLauncher, mLauncher.getDragLayer(),
null /* thumbnail */,
mAppIcon, new RectF());
floatingTaskView.setAlpha(1);
- floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
+ floatingTaskView.addStagingAnimation(anim, mTaskBounds, mTempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
setFirstFloatingTaskView(floatingTaskView);
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
index 441f88d..5fd86c0 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
@@ -166,5 +166,10 @@
this.shadowRadius = radius;
return this;
}
+
+ @Override
+ public SurfaceProperties setShow() {
+ return this;
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 1112f4d..7cc2c46 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -26,7 +26,6 @@
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.SystemProperties;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -153,14 +152,9 @@
// Create a new overlay layer. We do not call detach on this instance, it's propagated
// to other classes like PipTaskOrganizer / RecentsAnimationController to complete
// the cleanup.
- if (SystemProperties.getBoolean(
- "persist.wm.debug.enable_pip_app_icon_overlay", true)) {
- mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
- mAppBounds, new IconProvider(context).getIcon(mActivityInfo),
- appIconSizePx);
- } else {
- mPipContentOverlay = new PipContentOverlay.PipColorOverlay(view.getContext());
- }
+ mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
+ mAppBounds, new IconProvider(context).getIcon(mActivityInfo),
+ appIconSizePx);
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
mPipContentOverlay.attach(tx, mLeash);
} else {
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 83e9945..dfd4390 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -43,6 +44,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
@@ -107,9 +109,17 @@
public DesktopTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mSnapshotDrawParams = new FullscreenDrawParams(
- QuickStepContract.getWindowCornerRadius(context),
- QuickStepContract.getWindowCornerRadius(context));
+ mSnapshotDrawParams = new FullscreenDrawParams(context) {
+ @Override
+ public float computeTaskCornerRadius(Context context) {
+ return QuickStepContract.getWindowCornerRadius(context);
+ }
+
+ @Override
+ public float computeWindowCornerRadius(Context context) {
+ return QuickStepContract.getWindowCornerRadius(context);
+ }
+ };
}
@Override
@@ -220,7 +230,22 @@
private TaskIdAttributeContainer createAttributeContainer(Task task,
TaskThumbnailView thumbnailView) {
- return new TaskIdAttributeContainer(task, thumbnailView, null, STAGE_POSITION_UNDEFINED);
+ return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
+ STAGE_POSITION_UNDEFINED);
+ }
+
+ private IconView createIconView(Task task) {
+ IconView iconView = new IconView(mContext);
+ PackageManager pm = mContext.getApplicationContext().getPackageManager();
+ try {
+ IconProvider provider = new IconProvider(mContext);
+ Drawable appIcon = provider.getIcon(pm.getActivityInfo(task.topActivity,
+ PackageManager.ComponentInfoFlags.of(0)));
+ iconView.setDrawable(appIcon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Package not found: " + task.topActivity.getPackageName(), e);
+ }
+ return iconView;
}
@Nullable
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4b8741d..76f9c2c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1396,6 +1396,7 @@
// its thumbnail
mTmpRunningTasks = null;
mSplitBoundsConfig = null;
+ mTaskOverlayFactory.clearAllActiveState();
}
updateLocusId();
}
@@ -4793,8 +4794,9 @@
} else {
resetFromSplitSelectionState();
}
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
});
- InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
});
mSecondSplitHiddenView = containerTaskView;
@@ -5296,6 +5298,8 @@
cleanupRemoteTargets();
if (mRecentsAnimationController == null) {
+ Log.d(TestProtocol.INCORRECT_HOME_STATE, "finish recents animation but recents "
+ + "animation controller was null. returning.");
if (onFinishComplete != null) {
onFinishComplete.run();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 854c3c7..a2976a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -71,6 +71,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
@@ -133,15 +134,17 @@
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
+ public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
- public static final int FLAG_UPDATE_ALL = FLAG_UPDATE_ICON | FLAG_UPDATE_THUMBNAIL;
+ public static final int FLAG_UPDATE_ALL = FLAG_UPDATE_ICON | FLAG_UPDATE_THUMBNAIL
+ | FLAG_UPDATE_CORNER_RADIUS;
/**
* Used in conjunction with {@link #onTaskListVisibilityChanged(boolean, int)}, providing more
* granularity on which components of this task require an update
*/
@Retention(SOURCE)
- @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
+ @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL, FLAG_UPDATE_CORNER_RADIUS})
public @interface TaskDataChanges {}
/**
@@ -1079,6 +1082,9 @@
mDigitalWellBeingToast.initialize(task);
});
}
+ if (needsUpdate(changes, FLAG_UPDATE_CORNER_RADIUS)) {
+ mCurrentFullscreenParams.updateCornerRadius(getContext());
+ }
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mSnapshotView.setThumbnail(null, null);
@@ -1859,19 +1865,29 @@
*/
public static class FullscreenDrawParams {
- private final float mCornerRadius;
- private final float mWindowCornerRadius;
+ private float mCornerRadius;
+ private float mWindowCornerRadius;
public float mCurrentDrawnCornerRadius;
public FullscreenDrawParams(Context context) {
- this(TaskCornerRadius.get(context), QuickStepContract.getWindowCornerRadius(context));
+ updateCornerRadius(context);
}
- FullscreenDrawParams(float cornerRadius, float windowCornerRadius) {
- mCornerRadius = cornerRadius;
- mWindowCornerRadius = windowCornerRadius;
- mCurrentDrawnCornerRadius = mCornerRadius;
+ /** Recomputes the start and end corner radius for the given Context. */
+ public void updateCornerRadius(Context context) {
+ mCornerRadius = computeTaskCornerRadius(context);
+ mWindowCornerRadius = computeWindowCornerRadius(context);
+ }
+
+ @VisibleForTesting
+ public float computeTaskCornerRadius(Context context) {
+ return TaskCornerRadius.get(context);
+ }
+
+ @VisibleForTesting
+ public float computeWindowCornerRadius(Context context) {
+ return QuickStepContract.getWindowCornerRadius(context);
}
/**
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 9622619..58be345 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -17,6 +17,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -26,12 +27,14 @@
import android.os.Handler;
import android.view.View;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.AssistUtils;
import org.junit.Before;
import org.junit.Test;
@@ -53,6 +56,8 @@
@Mock
Handler mockHandler;
@Mock
+ AssistUtils mockAssistUtils;
+ @Mock
StatsLogManager mockStatsLogManager;
@Mock
StatsLogManager.StatsLogger mockStatsLogger;
@@ -70,12 +75,15 @@
MockitoAnnotations.initMocks(this);
when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
+ when(mockService.getApplicationContext())
+ .thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getApplicationContext());
when(mockStatsLogManager.logger()).thenReturn(mockStatsLogger);
when(mockTaskbarControllers.getTaskbarActivityContext())
.thenReturn(mockTaskbarActivityContext);
doReturn(mockStatsLogManager).when(mockTaskbarActivityContext).getStatsLogManager();
mNavButtonController = new TaskbarNavButtonController(mockService,
- mockSystemUiProxy, mockHandler);
+ mockSystemUiProxy, mockHandler, mockAssistUtils);
}
@Test
@@ -104,16 +112,42 @@
}
@Test
- public void testLongPressHome_enabled() {
+ public void testLongPressHome_enabled_withoutOverride() {
mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
+ when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(false);
+
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+ verify(mockAssistUtils, times(1)).tryStartAssistOverride(anyInt());
verify(mockSystemUiProxy, times(1)).startAssistant(any());
}
@Test
- public void testLongPressHome_disabled() {
- mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
+ public void testLongPressHome_enabled_withOverride() {
+ mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
+ when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(true);
+
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+ verify(mockAssistUtils, times(1)).tryStartAssistOverride(anyInt());
+ verify(mockSystemUiProxy, never()).startAssistant(any());
+ }
+
+ @Test
+ public void testLongPressHome_disabled_withoutOverride() {
+ mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
+ when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(false);
+
+ mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+ verify(mockAssistUtils, never()).tryStartAssistOverride(anyInt());
+ verify(mockSystemUiProxy, never()).startAssistant(any());
+ }
+
+ @Test
+ public void testLongPressHome_disabled_withOverride() {
+ mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
+ when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(true);
+
+ mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+ verify(mockAssistUtils, never()).tryStartAssistOverride(anyInt());
verify(mockSystemUiProxy, never()).startAssistant(any());
}
diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index a9dc043..bb1afdf 100644
--- a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.quickstep
+import android.content.Context
import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -29,7 +30,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
/** Test for FullscreenDrawParams class. */
@SmallTest
@@ -186,4 +189,76 @@
val expectedRadius = QuickStepContract.getWindowCornerRadius(context)
assertThat(params.mCurrentDrawnCornerRadius).isEqualTo(expectedRadius)
}
+
+ @Test
+ fun setStartProgress_correctCornerRadiusForMultiDisplay() {
+ val display1Context = context
+ val display2Context = mock(Context::class.java)
+ val spyParams = spy(params)
+
+ val display1TaskRadius = TaskCornerRadius.get(display1Context)
+ val display1WindowRadius = QuickStepContract.getWindowCornerRadius(display1Context)
+ val display2TaskRadius = display1TaskRadius * 2 + 1 // Arbitrarily different.
+ val display2WindowRadius = display1WindowRadius * 2 + 1 // Arbitrarily different.
+ doReturn(display2TaskRadius).`when`(spyParams).computeTaskCornerRadius(display2Context)
+ doReturn(display2WindowRadius).`when`(spyParams).computeWindowCornerRadius(display2Context)
+
+ spyParams.updateCornerRadius(display1Context)
+ spyParams.setProgress(
+ /* fullscreenProgress= */ 0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* unused previewWidth= */ -1,
+ /* unusedDp= */ null,
+ /* unused previewPositionHelper= */ null
+ )
+ assertThat(spyParams.mCurrentDrawnCornerRadius).isEqualTo(display1TaskRadius)
+
+ spyParams.updateCornerRadius(display2Context)
+ spyParams.setProgress(
+ /* fullscreenProgress= */ 0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* unused previewWidth= */ -1,
+ /* unusedDp= */ null,
+ /* unused previewPositionHelper= */ null
+ )
+ assertThat(spyParams.mCurrentDrawnCornerRadius).isEqualTo(display2TaskRadius)
+ }
+
+ @Test
+ fun setFullProgress_correctCornerRadiusForMultiDisplay() {
+ val display1Context = context
+ val display2Context = mock(Context::class.java)
+ val spyParams = spy(params)
+
+ val display1TaskRadius = TaskCornerRadius.get(display1Context)
+ val display1WindowRadius = QuickStepContract.getWindowCornerRadius(display1Context)
+ val display2TaskRadius = display1TaskRadius * 2 + 1 // Arbitrarily different.
+ val display2WindowRadius = display1WindowRadius * 2 + 1 // Arbitrarily different.
+ doReturn(display2TaskRadius).`when`(spyParams).computeTaskCornerRadius(display2Context)
+ doReturn(display2WindowRadius).`when`(spyParams).computeWindowCornerRadius(display2Context)
+
+ spyParams.updateCornerRadius(display1Context)
+ spyParams.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* unused previewWidth= */ -1,
+ /* unusedDp= */ null,
+ /* unused previewPositionHelper= */ null
+ )
+ assertThat(spyParams.mCurrentDrawnCornerRadius).isEqualTo(display1WindowRadius)
+
+ spyParams.updateCornerRadius(display2Context)
+ spyParams.setProgress(
+ /* fullscreenProgress= */ 1.0f,
+ /* parentScale= */ 1.0f,
+ /* taskViewScale= */ 1.0f,
+ /* unused previewWidth= */ -1,
+ /* unusedDp= */ null,
+ /* unused previewPositionHelper= */ null
+ )
+ assertThat(spyParams.mCurrentDrawnCornerRadius).isEqualTo(display2WindowRadius)
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 5127190..20aa410 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -16,14 +16,17 @@
package com.android.quickstep;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,9 +47,9 @@
startTestActivity(2);
}
- @Ignore
@Test
@NavigationModeSwitch
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/187761685
public void testStressPressHome() {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
@@ -57,9 +60,9 @@
}
}
- @Ignore
@Test
@NavigationModeSwitch
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/187761685
public void testStressSwipeToOverview() {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9d188ed..25f90ca 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -18,6 +18,8 @@
import static com.android.launcher3.testing.shared.TestProtocol.FLAKY_QUICK_SWITCH_TO_PREVIOUS_APP;
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import static org.junit.Assert.assertEquals;
@@ -50,6 +52,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import com.android.quickstep.views.RecentsView;
@@ -182,7 +185,6 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord // b/195673272
@PlatinumTest(focusArea = "launcher")
public void testOverviewActions() throws Exception {
// Experimenting for b/165029151:
@@ -320,6 +322,7 @@
@Test
@ScreenRecord // b/242163205
@PlatinumTest(focusArea = "launcher")
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/286084688
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 3317ce1..92b598b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,26 +16,40 @@
package com.android.quickstep;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.content.Intent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+@LargeTest
+@RunWith(AndroidJUnit4.class)
public class TaplTestsSplitscreen extends AbstractQuickStepTest {
private static final String CALCULATOR_APP_NAME = "Calculator";
private static final String CALCULATOR_APP_PACKAGE =
resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
+ private static final String READ_DEVICE_CONFIG_PERMISSION =
+ "android.permission.READ_DEVICE_CONFIG";
+
@Override
@Before
public void setUp() throws Exception {
@@ -46,6 +60,8 @@
mLauncher.enableBlockTimeout(true);
mLauncher.showTaskbarIfHidden();
}
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ READ_DEVICE_CONFIG_PERMISSION);
}
@After
@@ -64,6 +80,7 @@
@Test
@PortraitLandscape
@TaskbarModeSwitch
+ @TestStabilityRule.Stability(flavors = PLATFORM_POSTSUBMIT | LOCAL) // b/295225524
public void testSplitAppFromHomeWithItself() throws Exception {
// Currently only tablets have Taskbar in Overview, so test is only active on tablets
assumeTrue(mLauncher.isTablet());
diff --git a/res/drawable/all_apps_tabs_background.xml b/res/drawable/all_apps_tabs_background.xml
index 8471cd4..1e7cff2 100644
--- a/res/drawable/all_apps_tabs_background.xml
+++ b/res/drawable/all_apps_tabs_background.xml
@@ -30,7 +30,7 @@
android:state_selected="false">
<shape android:shape="rectangle">
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="@color/all_apps_tabs_background" />
+ <solid android:color="@color/material_color_surface_bright" />
</shape>
</item>
@@ -39,7 +39,7 @@
android:state_selected="true">
<shape android:shape="rectangle">
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="@color/all_apps_tab_background_selected" />
+ <solid android:color="@color/material_color_primary" />
</shape>
</item>
</selector>
diff --git a/res/drawable/bottom_rounded_popup_ripple.xml b/res/drawable/bottom_rounded_popup_ripple.xml
deleted file mode 100644
index 739833a..0000000
--- a/res/drawable/bottom_rounded_popup_ripple.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <solid android:color="#FFFFFFFF"/>
- <corners android:bottomLeftRadius="@dimen/dialogCornerRadius"
- android:bottomRightRadius="@dimen/dialogCornerRadius"
- android:topLeftRadius="0dp"
- android:topRightRadius="0dp"/>
- </shape>
- </item>
-</ripple>
\ No newline at end of file
diff --git a/res/drawable/top_rounded_popup_ripple.xml b/res/drawable/rounded_popup_ripple.xml
similarity index 80%
rename from res/drawable/top_rounded_popup_ripple.xml
rename to res/drawable/rounded_popup_ripple.xml
index 7468480..b0dcc80 100644
--- a/res/drawable/top_rounded_popup_ripple.xml
+++ b/res/drawable/rounded_popup_ripple.xml
@@ -18,10 +18,7 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#FFFFFFFF"/>
- <corners android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- android:topLeftRadius="@dimen/dialogCornerRadius"
- android:topRightRadius="@dimen/dialogCornerRadius"/>
+ <corners android:radius="@dimen/dialogCornerRadius" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 52c5a49..695270e 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -15,7 +15,7 @@
<com.android.launcher3.allapps.WorkPausedCard xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/work_edu_card_margin"
+ android:padding="@dimen/all_apps_tabs_margin_top"
android:orientation="vertical"
android:gravity="center_horizontal">
@@ -25,7 +25,6 @@
android:id="@+id/work_apps_paused_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="40dp"
android:text="@string/work_apps_paused_title"
android:textAlignment="center"
android:textSize="18sp" />
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 72ab9b2..a35a70b 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -61,7 +61,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
<string name="label_application" msgid="8531721983832654978">"ಆ್ಯಪ್"</string>
<string name="all_apps_label" msgid="5015784846527570951">"ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳು"</string>
- <string name="notifications_header" msgid="1404149926117359025">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="notifications_header" msgid="1404149926117359025">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"ಶಾರ್ಟ್ಕಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"ಶಾರ್ಟ್ಕಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="out_of_space" msgid="6455557115204099579">"ಈ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1695c58..4cb6414 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -32,7 +32,8 @@
<style name="LauncherTheme" parent="@style/BaseLauncherTheme">
<item name="android:textColorSecondary">#DE000000</item>
<item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
- <item name="allappsHeaderProtectionColor">@color/popup_color_tertiary_light</item>
+ <item name="allappsHeaderProtectionColor">
+ @color/material_color_surface_container_highest</item>
<item name="allAppsNavBarScrimColor">#66FFFFFF</item>
<item name="popupColorPrimary">@color/popup_color_primary_light</item>
<item name="popupColorSecondary">@color/popup_color_secondary_light</item>
@@ -149,6 +150,7 @@
<item name="android:colorControlHighlight">#19FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
<item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
+ <item name="allappsHeaderProtectionColor">@color/material_color_surface_container_low</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="popupColorPrimary">@color/popup_color_primary_dark</item>
<item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 8876a1b..808cf70 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -17,12 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.app.WallpaperManager.OnColorsChangedListener;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
@@ -32,6 +27,7 @@
import android.view.Display;
import android.view.View;
+import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -41,9 +37,11 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.OnColorHintListener;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.WallpaperColorHints;
import com.android.launcher3.util.WindowBounds;
/**
@@ -51,7 +49,7 @@
*/
@SuppressWarnings("NewApi")
public abstract class BaseDraggingActivity extends BaseActivity
- implements OnColorsChangedListener, DisplayInfoChangeListener {
+ implements OnColorHintListener, DisplayInfoChangeListener {
private static final String TAG = "BaseDraggingActivity";
@@ -63,8 +61,7 @@
protected boolean mIsSafeModeEnabled;
private Runnable mOnStartCallback;
- private RunnableList mOnResumeCallbacks = new RunnableList();
-
+ private final RunnableList mOnResumeCallbacks = new RunnableList();
private int mThemeRes = R.style.AppTheme;
@Override
@@ -76,10 +73,7 @@
DisplayController.INSTANCE.get(this).addChangeListener(this);
// Update theme
- if (Utilities.ATLEAST_P) {
- THREAD_POOL_EXECUTOR.execute(() -> getSystemService(WallpaperManager.class)
- .addOnColorsChangedListener(this, MAIN_EXECUTOR.getHandler()));
- }
+ WallpaperColorHints.get(this).registerOnColorHintsChangedListener(this);
int themeRes = Themes.getActivityThemeRes(this);
if (themeRes != mThemeRes) {
mThemeRes = themeRes;
@@ -97,8 +91,9 @@
mOnResumeCallbacks.add(callback);
}
+ @MainThread
@Override
- public void onColorsChanged(WallpaperColors wallpaperColors, int which) {
+ public void onColorHintsChanged(int colorHints) {
updateTheme();
}
@@ -175,10 +170,8 @@
@Override
protected void onDestroy() {
super.onDestroy();
- if (Utilities.ATLEAST_P) {
- getSystemService(WallpaperManager.class).removeOnColorsChangedListener(this);
- }
DisplayController.INSTANCE.get(this).removeChangeListener(this);
+ WallpaperColorHints.get(this).unregisterOnColorsChangedListener(this);
}
public void runOnceOnStart(Runnable action) {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 360e060..abf84dd 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
@@ -152,7 +153,7 @@
private final CheckLongPressHelper mLongPressHelper;
- private final boolean mLayoutHorizontal;
+ private boolean mLayoutHorizontal;
private final boolean mIsRtl;
private final int mIconSize;
@@ -197,6 +198,7 @@
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mActivity = ActivityContext.lookupContext(context);
+ FastBitmapDrawable.setFlagHoverEnabled(ENABLE_CURSOR_HOVER_STATES.get());
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
@@ -666,6 +668,18 @@
}
/**
+ * Sets whether the layout is horizontal.
+ */
+ public void setLayoutHorizontal(boolean layoutHorizontal) {
+ if (mLayoutHorizontal == layoutHorizontal) {
+ return;
+ }
+
+ mLayoutHorizontal = layoutHorizontal;
+ applyCompoundDrawables(getIconOrTransparentColor());
+ }
+
+ /**
* Sets whether to vertically center the content.
*/
public void setCenterVertically(boolean centerVertically) {
@@ -991,10 +1005,14 @@
if (!mIsIconVisible) {
resetIconScale();
}
- Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
+ Drawable icon = getIconOrTransparentColor();
applyCompoundDrawables(icon);
}
+ private Drawable getIconOrTransparentColor() {
+ return mIsIconVisible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
+ }
+
/** Sets the icon visual state to disabled or not. */
public void setIconDisabled(boolean isDisabled) {
if (mIcon != null) {
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 4674401..08e5def 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -245,6 +245,7 @@
// the user where a dragged item will land when dropped.
setWillNotDraw(false);
setClipToPadding(false);
+ setClipChildren(false);
mActivity = ActivityContext.lookupContext(context);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7ece9a4..be43e6c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -294,6 +294,7 @@
public final int taskbarIconSize;
// If true, used to layout taskbar in 3 button navigation mode.
public final boolean startAlignTaskbar;
+ public final boolean isTransientTaskbar;
// DragController
public int flingToDeleteThresholdVelocity;
@@ -361,7 +362,8 @@
}
}
- if (DisplayController.isTransientTaskbar(context)) {
+ isTransientTaskbar = DisplayController.isTransientTaskbar(context);
+ if (isTransientTaskbar) {
float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
taskbarHeight = Math.round((taskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
@@ -1134,10 +1136,11 @@
* This method calculates the space between the icons to achieve a certain width.
*/
private int calculateHotseatBorderSpace(float hotseatWidthPx, int numExtraBorder) {
+ int numBorders = (numShownHotseatIcons - 1 + numExtraBorder);
+ if (numBorders <= 0) return 0;
+
float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons;
- int hotseatBorderSpacePx =
- (int) (hotseatWidthPx - hotseatIconsTotalPx)
- / (numShownHotseatIcons - 1 + numExtraBorder);
+ int hotseatBorderSpacePx = (int) (hotseatWidthPx - hotseatIconsTotalPx) / numBorders;
return Math.min(hotseatBorderSpacePx, mMaxHotseatIconSpacePx);
}
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index f94a3c5..8ec5c18 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
@@ -37,6 +38,8 @@
* Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
*/
public class ExtendedEditText extends EditText {
+ private static final String TAG = "ExtendedEditText";
+
private final Set<OnFocusChangeListener> mOnFocusChangeListeners = new HashSet<>();
private boolean mForceDisableSuggestions = false;
@@ -71,14 +74,9 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
// If this is a back key, propagate the key back to the listener
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
- if (TextUtils.isEmpty(getText())) {
- hideKeyboard();
- }
- if (mBackKeyListener != null) {
- return mBackKeyListener.onBackKey();
- }
- return false;
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP
+ && mBackKeyListener != null) {
+ return mBackKeyListener.onBackKey();
}
return super.onKeyPreIme(keyCode, event);
}
@@ -89,9 +87,17 @@
return false;
}
- public void showKeyboard() {
+ /**
+ * Synchronously shows the soft input method.
+ *
+ * @param shouldFocus whether this EditText should also request focus.
+ * @return true if the keyboard is shown correctly and focus is given to this view (if
+ * applicable).
+ */
+ public boolean showKeyboard(boolean shouldFocus) {
onKeyboardShown();
- showSoftInput();
+ boolean focusResult = !shouldFocus || requestFocus();
+ return focusResult && showSoftInputInternal();
}
public void hideKeyboard() {
@@ -104,10 +110,15 @@
.keyboardStateManager().setKeyboardState(SHOW);
}
- private boolean showSoftInput() {
- return requestFocus() &&
- getContext().getSystemService(InputMethodManager.class)
- .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
+ private boolean showSoftInputInternal() {
+ boolean result = false;
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
+ if (imm != null) {
+ result = imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
+ } else {
+ Log.w(TAG, "Failed to retrieve InputMethodManager from the system.");
+ }
+ return result;
}
public void dispatchBackKey() {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index be14844..e3de79e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -50,6 +50,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.testing.shared.ResourceUtils;
@@ -287,12 +288,13 @@
* Reinitialize the current grid after a restore, where some grids might now be disabled.
*/
public void reinitializeAfterRestore(Context context) {
+ FileLog.d(TAG, "Reinitializing grid after restore");
String currentGridName = getCurrentGridName(context);
String currentDbFile = dbFile;
String newGridName = initGrid(context, currentGridName);
String newDbFile = dbFile;
if (!newDbFile.equals(currentDbFile)) {
- Log.d(TAG, "Restored grid is disabled : " + currentGridName
+ FileLog.d(TAG, "Restored grid is disabled : " + currentGridName
+ ", migrating to: " + newGridName
+ ", removing all other grid db files");
for (String gridDbFile : LauncherFiles.GRID_DB_FILES) {
@@ -300,7 +302,7 @@
continue;
}
if (context.getDatabasePath(gridDbFile).delete()) {
- Log.d(TAG, "Removed old grid db file: " + gridDbFile);
+ FileLog.d(TAG, "Removed old grid db file: " + gridDbFile);
}
}
setCurrentGrid(context, newGridName);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d0a2576..ffb8b82 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,7 +100,6 @@
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Parcelable;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -155,7 +154,6 @@
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.LauncherDragController;
import com.android.launcher3.folder.Folder;
@@ -200,6 +198,7 @@
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ActivityTracker;
+import com.android.launcher3.util.CannedAnimationCoordinator;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -423,6 +422,9 @@
private StartupLatencyLogger mStartupLatencyLogger;
private CellPosMapper mCellPosMapper = CellPosMapper.DEFAULT;
+ private final CannedAnimationCoordinator mAnimationCoordinator =
+ new CannedAnimationCoordinator(this);
+
@Override
@TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
@@ -2327,6 +2329,7 @@
@Override
public void bindScreens(IntArray orderedScreenIds) {
+ mWorkspace.mPageIndicator.setAreScreensBinding(true);
int firstScreenPosition = 0;
if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != firstScreenPosition) {
@@ -2344,13 +2347,37 @@
mWorkspace.unlockWallpaperFromDefaultPageOnNextLayout();
}
+ /**
+ * Remove odd number because they are already included when isTwoPanels and add the pair screen
+ * if not present.
+ */
+ private IntArray filterTwoPanelScreenIds(IntArray orderedScreenIds) {
+ IntSet screenIds = IntSet.wrap(orderedScreenIds);
+ orderedScreenIds.forEach(screenId -> {
+ if (screenId % 2 == 1) {
+ screenIds.remove(screenId);
+ // In case the pair is not added, add it
+ if (!mWorkspace.containsScreenId(screenId - 1)) {
+ screenIds.add(screenId - 1);
+ }
+ }
+ });
+ return screenIds.getArray();
+ }
+
private void bindAddScreens(IntArray orderedScreenIds) {
+
if (mDeviceProfile.isTwoPanels) {
- // Some empty pages might have been removed while the phone was in a single panel
- // mode, so we want to add those empty pages back.
- IntSet screenIds = IntSet.wrap(orderedScreenIds);
- orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
- orderedScreenIds = screenIds.getArray();
+ if (FOLDABLE_SINGLE_PAGE.get()) {
+ orderedScreenIds = filterTwoPanelScreenIds(orderedScreenIds);
+ } else {
+ // Some empty pages might have been removed while the phone was in a single panel
+ // mode, so we want to add those empty pages back.
+ IntSet screenIds = IntSet.wrap(orderedScreenIds);
+ orderedScreenIds.forEach(
+ screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
+ orderedScreenIds = screenIds.getArray();
+ }
}
int count = orderedScreenIds.size();
@@ -2824,8 +2851,8 @@
getViewCache().setCacheSize(R.layout.folder_page, 2);
TraceHelper.INSTANCE.endSection();
-
- mWorkspace.removeExtraEmptyScreen(true);
+ mWorkspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true);
+ mWorkspace.mPageIndicator.setAreScreensBinding(false);
}
private boolean canAnimatePageChange() {
@@ -3250,8 +3277,6 @@
return new TouchController[] {getDragController(), new AllAppsSwipeController(this)};
}
- public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { }
-
public void onDragLayerHierarchyChanged() {
updateDisallowBack();
}
@@ -3317,10 +3342,6 @@
return false;
}
- public DragOptions getDefaultWorkspaceDragOptions() {
- return new DragOptions();
- }
-
/**
* Animates Launcher elements during a transition to the All Apps page.
*
@@ -3405,4 +3426,11 @@
public void launchAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
// Overridden
}
+
+ /**
+ * Returns the animation coordinator for playing one-off animations
+ */
+ public CannedAnimationCoordinator getAnimationCoordinator() {
+ return mAnimationCoordinator;
+ }
}
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index 3d2700d..2617b93 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -34,7 +34,7 @@
// Remove old files which might contain obsolete attributes like idp_grid_name in shared
// preference that will obstruct backup's attribute from writing to shared preferences.
if (destination.delete()) {
- FileLog.d("LauncherBackupAgent", "Removed obsolete file: " + destination);
+ FileLog.d(TAG, "onRestoreFile: Removed obsolete file " + destination);
}
super.onRestoreFile(data, size, destination, type, mode, mtime);
}
@@ -47,6 +47,7 @@
@Override
public void onRestoreFinished() {
+ FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
RestoreDbTask.setPending(this);
}
}
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index aaccb7d..d460ba8 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -32,6 +32,8 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.util.Executors;
+import java.util.Locale;
+
/**
* BroadcastReceiver to handle session commit intent.
*/
@@ -63,9 +65,20 @@
}
InstallSessionHelper packageInstallerCompat = InstallSessionHelper.INSTANCE.get(context);
+ boolean alreadyAddedPromiseIcon =
+ packageInstallerCompat.promiseIconAddedForId(info.getSessionId());
if (TextUtils.isEmpty(info.getAppPackageName())
|| info.getInstallReason() != PackageManager.INSTALL_REASON_USER
- || packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
+ || alreadyAddedPromiseIcon) {
+ FileLog.d(LOG,
+ String.format(Locale.ENGLISH,
+ "Removing PromiseIcon for package: %s, install reason: %d,"
+ + " alreadyAddedPromiseIcon: %s",
+ info.getAppPackageName(),
+ info.getInstallReason(),
+ alreadyAddedPromiseIcon
+ )
+ );
packageInstallerCompat.removePromiseIconId(info.getSessionId());
return;
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 07b71b3..f0fea61 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -66,6 +66,7 @@
mActivity = ActivityContext.lookupContext(context);
mWallpaperManager = WallpaperManager.getInstance(context);
mContainerType = containerType;
+ setClipChildren(false);
}
public void setCellDimensions(int cellWidth, int cellHeight, int countX, int countY,
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index adaf20f..8be8fed 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -731,6 +731,14 @@
});
}
+
+ /**
+ * Returns if the given screenId is already in the Workspace
+ */
+ public boolean containsScreenId(int screenId) {
+ return this.mWorkspaceScreens.containsKey(screenId);
+ }
+
/**
* Inserts extra empty pages to the end of the existing workspaces.
* Usually we add one extra empty screen, but when two panel home is enabled we add
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index 4768773..c6c38fc 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -55,6 +55,7 @@
int y = presenterPos.cellY;
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
|| info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
+ Log.d(TAG, "add predicted icon " + child.getTag().toString() + " to home screen");
int screenId = presenterPos.screenId;
x = getHotseat().getCellXFromOrder(screenId);
y = getHotseat().getCellYFromOrder(screenId);
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index c3d0e6b..e724858 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -61,7 +61,7 @@
private PackageUserKey mTempKey = new PackageUserKey(null, null);
private AppInfo mTempInfo = new AppInfo();
- private AppInfo[] mApps = EMPTY_ARRAY;
+ private @NonNull AppInfo[] mApps = EMPTY_ARRAY;
private final List<OnUpdateListener> mUpdateListeners = new CopyOnWriteArrayList<>();
private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
@@ -85,8 +85,8 @@
* Sets the current set of apps and sets mapping for {@link PackageUserKey} to Uid for
* the current set of apps.
*/
- public void setApps(AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
- mApps = apps;
+ public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
+ mApps = apps == null ? EMPTY_ARRAY : apps;
mModelFlags = flags;
notifyUpdate();
mPackageUserKeytoUidMap = map;
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 4427a49..ecbc7a9 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -160,7 +160,7 @@
* Focuses the search field to handle key events.
*/
public void focusSearchField() {
- mInput.showKeyboard();
+ mInput.showKeyboard(true /* shouldFocus */);
}
/**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 83431dc..9bc2a0a 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -83,11 +83,11 @@
*/
// TODO(Block 1): Clean up flags
public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag(
- 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", TEAMFOOD,
+ 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", ENABLED,
"Enable option to replace decorator-based search result backgrounds with drawables");
public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag(
- 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", TEAMFOOD,
+ 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", ENABLED,
"Enable option to launch search results using the new view container transitions");
// TODO(Block 2): Clean up flags
@@ -238,7 +238,7 @@
"COLLECT_SEARCH_HISTORY", DISABLED, "Allow launcher to collect search history for log");
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
- "ENABLE_TWOLINE_ALLAPPS", ENABLED, "Enables two line label inside all apps.");
+ "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
"IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
@@ -289,7 +289,7 @@
"Enables home animation to icon when user swipes back.");
public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473,
- "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", TEAMFOOD,
+ "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
"Enables taskbar thresholds that scale based on screen size.");
// TODO(Block 21): Clean up flags
@@ -297,11 +297,6 @@
"ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut");
// TODO(Block 22): Clean up flags
- public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag(270397209,
- "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", ENABLED,
- "Enables receiving unfold animation events from sysui instead of calculating "
- + "them in launcher process using hinge sensor values.");
-
public static final BooleanFlag ENABLE_WIDGET_TRANSITION_FOR_RESIZING = getDebugFlag(268553314,
"ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
"Enable widget transition animation when resizing the widgets");
@@ -374,11 +369,11 @@
// TODO(Block 28): Clean up flags
public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS =
- getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", TEAMFOOD,
+ getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", DISABLED,
"Enable splitting from fullscreen app with keyboard shortcuts");
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
- 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", TEAMFOOD,
+ 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
"Enable initiating split screen from workspace to workspace.");
public static final BooleanFlag ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE = getDebugFlag(
@@ -414,12 +409,12 @@
// TODO(Block 33): Clean up flags
public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
- "ENABLE_ALL_APPS_RV_PREINFLATION", DISABLED,
+ "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
"Enables preinflating all apps icons to avoid scrolling jank.");
// TODO(Block 34): Clean up flags
public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
- "ALL_APPS_GONE_VISIBILITY", DISABLED,
+ "ALL_APPS_GONE_VISIBILITY", ENABLED,
"Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
// TODO(Block 35): Empty block
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 00f4285..213c458 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
import android.annotation.TargetApi;
-import android.app.ActivityOptions;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ClipData;
@@ -68,6 +67,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.PinRequestHelper;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.views.AbstractSlideInView;
@@ -259,9 +259,7 @@
.setPackage(getPackageName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Launcher.ACTIVITY_TRACKER.registerCallback(listener);
- startActivity(homeIntent,
- ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out)
- .toBundle());
+ startActivity(homeIntent, ApiWrapper.createFadeOutAnimOptions(this).toBundle());
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED);
mFinishOnPause = true;
return false;
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index af43ae8..48b5646 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -31,7 +31,6 @@
import android.widget.RemoteViews;
import com.android.launcher3.DragSource;
-import com.android.launcher3.Launcher;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -72,15 +71,6 @@
}
@Override
- public boolean init(Launcher launcher, boolean alreadyOnHome) {
- super.init(launcher, alreadyOnHome);
- if (!alreadyOnHome) {
- launcher.useFadeOutAnimationForLauncherStart(mCancelSignal);
- }
- return false;
- }
-
- @Override
protected PendingItemDragHelper createDragHelper() {
final PendingAddItemInfo item;
if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index f38cce1..55a539a 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -535,7 +535,7 @@
mFolderName.selectAll();
}
}
- mFolderName.showKeyboard();
+ mFolderName.showKeyboard(true /* shouldFocus */);
mFolderName.displayCompletions(
Stream.of(mInfo.suggestedFolderNames.getLabels())
.filter(Objects::nonNull)
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index d78bfba..53d0efb 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -16,6 +16,7 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
@@ -627,7 +628,7 @@
Utilities.scaleRectAboutCenter(iconBounds, iconScale);
// If we are animating to the accepting state, animate the dot out.
- mDotParams.scale = Math.max(0, mDotScale - mBackground.getScaleProgress());
+ mDotParams.scale = Math.max(0, mDotScale - mBackground.getAcceptScaleProgress());
mDotParams.dotColor = mBackground.getDotColor();
mDotRenderer.draw(canvas, mDotParams);
}
@@ -801,6 +802,14 @@
}
}
+ @Override
+ public void onHoverChanged(boolean hovered) {
+ super.onHoverChanged(hovered);
+ if (ENABLE_CURSOR_HOVER_STATES.get()) {
+ mBackground.setHovered(hovered);
+ }
+ }
+
/**
* Interface that provides callbacks to a parent ViewGroup that hosts this FolderIcon.
*/
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 406955c..b320ceb 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -16,6 +16,8 @@
package com.android.launcher3.folder;
+import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.graphics.IconShape.getShape;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
@@ -39,6 +41,9 @@
import android.graphics.Shader;
import android.util.Property;
import android.view.View;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
@@ -55,7 +60,10 @@
private static final boolean DRAW_SHADOW = false;
private static final boolean DRAW_STROKE = false;
- private static final int CONSUMPTION_ANIMATION_DURATION = 100;
+ @VisibleForTesting protected static final int CONSUMPTION_ANIMATION_DURATION = 100;
+
+ @VisibleForTesting protected static final float HOVER_SCALE = 1.1f;
+ @VisibleForTesting protected static final int HOVER_ANIMATION_DURATION = 300;
private final PorterDuffXfermode mShadowPorterDuffXfermode
= new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
@@ -86,17 +94,21 @@
public boolean isClipping = true;
// Drawing / animation configurations
- private static final float ACCEPT_SCALE_FACTOR = 1.20f;
+ @VisibleForTesting protected static final float ACCEPT_SCALE_FACTOR = 1.20f;
// Expressed on a scale from 0 to 255.
private static final int BG_OPACITY = 255;
private static final int MAX_BG_OPACITY = 255;
private static final int SHADOW_OPACITY = 40;
- private ValueAnimator mScaleAnimator;
+ @VisibleForTesting protected ValueAnimator mScaleAnimator;
private ObjectAnimator mStrokeAlphaAnimator;
private ObjectAnimator mShadowAnimator;
+ @VisibleForTesting protected boolean mIsAccepting;
+ @VisibleForTesting protected boolean mIsHovered;
+ @VisibleForTesting protected boolean mIsHoveredOrAnimating;
+
private static final Property<PreviewBackground, Integer> STROKE_ALPHA =
new Property<PreviewBackground, Integer>(Integer.class, "strokeAlpha") {
@Override
@@ -203,11 +215,11 @@
}
/**
- * Returns the progress of the scale animation, where 0 means the scale is at 1f
- * and 1 means the scale is at ACCEPT_SCALE_FACTOR.
+ * Returns the progress of the scale animation to accept state, where 0 means the scale is at
+ * 1f and 1 means the scale is at ACCEPT_SCALE_FACTOR. Returns 0 when scaled due to hover.
*/
- float getScaleProgress() {
- return (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f);
+ float getAcceptScaleProgress() {
+ return mIsHoveredOrAnimating ? 0 : (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f);
}
void invalidate() {
@@ -385,60 +397,70 @@
return mDrawingDelegate != null;
}
- private void animateScale(float finalScale, final Runnable onStart, final Runnable onEnd) {
- final float scale0 = mScale;
- final float scale1 = finalScale;
-
+ protected void animateScale(boolean isAccepting, boolean isHovered) {
if (mScaleAnimator != null) {
mScaleAnimator.cancel();
}
- mScaleAnimator = ValueAnimator.ofFloat(0f, 1.0f);
-
- mScaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float prog = animation.getAnimatedFraction();
- mScale = prog * scale1 + (1 - prog) * scale0;
- invalidate();
+ final float startScale = mScale;
+ final float endScale = isAccepting ? ACCEPT_SCALE_FACTOR : (isHovered ? HOVER_SCALE : 1f);
+ Interpolator interpolator =
+ isAccepting != mIsAccepting ? ACCELERATE_DECELERATE : EMPHASIZED_DECELERATE;
+ int duration = isAccepting != mIsAccepting ? CONSUMPTION_ANIMATION_DURATION
+ : HOVER_ANIMATION_DURATION;
+ mIsAccepting = isAccepting;
+ mIsHovered = isHovered;
+ if (startScale == endScale) {
+ if (!mIsAccepting) {
+ clearDrawingDelegate();
}
+ mIsHoveredOrAnimating = mIsHovered;
+ return;
+ }
+
+
+ mScaleAnimator = ValueAnimator.ofFloat(0f, 1.0f);
+ mScaleAnimator.addUpdateListener(animation -> {
+ float prog = animation.getAnimatedFraction();
+ mScale = prog * endScale + (1 - prog) * startScale;
+ invalidate();
});
mScaleAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- if (onStart != null) {
- onStart.run();
+ if (mIsHovered) {
+ mIsHoveredOrAnimating = true;
}
}
@Override
public void onAnimationEnd(Animator animation) {
- if (onEnd != null) {
- onEnd.run();
+ if (!mIsAccepting) {
+ clearDrawingDelegate();
}
+ mIsHoveredOrAnimating = mIsHovered;
mScaleAnimator = null;
}
});
-
- mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
+ mScaleAnimator.setInterpolator(interpolator);
+ mScaleAnimator.setDuration(duration);
mScaleAnimator.start();
}
public void animateToAccept(CellLayout cl, int cellX, int cellY) {
- animateScale(ACCEPT_SCALE_FACTOR, () -> delegateDrawing(cl, cellX, cellY), null);
+ delegateDrawing(cl, cellX, cellY);
+ animateScale(/* isAccepting= */ true, mIsHovered);
}
public void animateToRest() {
- // This can be called multiple times -- we need to make sure the drawing delegate
- // is saved and restored at the beginning of the animation, since cancelling the
- // existing animation can clear the delgate.
- CellLayout cl = mDrawingDelegate;
- int cellX = mDelegateCellX;
- int cellY = mDelegateCellY;
- animateScale(1f, () -> delegateDrawing(cl, cellX, cellY), this::clearDrawingDelegate);
+ animateScale(/* isAccepting= */ false, mIsHovered);
}
public float getStrokeWidth() {
return mStrokeWidth;
}
+
+ protected void setHovered(boolean hovered) {
+ animateScale(mIsAccepting, /* isHovered= */ hovered);
+ }
}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 7457f30..b51373c 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -21,10 +21,12 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.view.View;
import androidx.annotation.Nullable;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.BitmapRenderer;
@@ -37,7 +39,6 @@
* A utility class to generate preview bitmap for dragging.
*/
public class DragPreviewProvider {
-
private final Rect mTempRect = new Rect();
protected final View mView;
@@ -99,6 +100,14 @@
height = mView.getHeight();
}
+ if (mView instanceof BubbleTextView) {
+ FastBitmapDrawable icon = ((BubbleTextView) mView).getIcon();
+ Drawable drawable = icon.getConstantState().newDrawable();
+ float xInset = (float) blurSizeOutline / (float) (width + blurSizeOutline);
+ float yInset = (float) blurSizeOutline / (float) (height + blurSizeOutline);
+ return new InsetDrawable(drawable, xInset / 2, yInset / 2, xInset / 2, yInset / 2);
+ }
+
return new FastBitmapDrawable(
BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
height + blurSizeOutline, (c) -> drawDragView(c, scale)));
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 68106c4..ae44f0a 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -45,12 +45,11 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.ContextThemeWrapper;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextClock;
@@ -94,6 +93,7 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
@@ -206,14 +206,7 @@
} else {
mDpOrig = mDp;
}
-
- WindowInsets currentWindowInsets = context.getSystemService(WindowManager.class)
- .getCurrentWindowMetrics().getWindowInsets();
- mInsets = new Rect(
- currentWindowInsets.getSystemWindowInsetLeft(),
- currentWindowInsets.getSystemWindowInsetTop(),
- currentWindowInsets.getSystemWindowInsetRight(),
- mDp.isTaskbarPresent ? 0 : currentWindowInsets.getSystemWindowInsetBottom());
+ mInsets = getInsets(context);
mDp.updateInsets(mInsets);
mHomeElementInflater = LayoutInflater.from(
@@ -265,6 +258,26 @@
mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
}
+ /**
+ * Returns the insets of the screen closest to the display given by the context
+ */
+ private Rect getInsets(Context context) {
+ DisplayController.Info info = DisplayController.INSTANCE.get(context).getInfo();
+ float maxDiff = Float.MAX_VALUE;
+ Display display = context.getDisplay();
+ Rect insets = new Rect();
+ for (WindowBounds supportedBound : info.supportedBounds) {
+ double diff = Math.pow(display.getWidth() - supportedBound.availableSize.x, 2)
+ + Math.pow(display.getHeight() - supportedBound.availableSize.y, 2);
+ if (supportedBound.rotationHint == context.getDisplay().getRotation()
+ && diff < maxDiff) {
+ maxDiff = (float) diff;
+ insets = supportedBound.insets;
+ }
+ }
+ return new Rect(insets);
+ }
+
/** Populate preview and render it. */
public View getRenderedView(BgDataModel dataModel,
Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index e89c0c5..aebcdd4 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -16,6 +16,8 @@
package com.android.launcher3.graphics;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -80,11 +82,12 @@
private static final String KEY_DISPLAY_ID = "display_id";
private static final String KEY_COLORS = "wallpaper_colors";
- private final Context mContext;
- private final InvariantDeviceProfile mIdp;
+ private Context mContext;
private final IBinder mHostToken;
private final int mWidth;
private final int mHeight;
+ private String mGridName;
+
private final Display mDisplay;
private final WallpaperColors mWallpaperColors;
private final RunnableList mOnDestroyCallbacks = new RunnableList();
@@ -97,15 +100,13 @@
public PreviewSurfaceRenderer(Context context, Bundle bundle) throws Exception {
mContext = context;
-
- String gridName = bundle.getString("name");
+ mGridName = bundle.getString("name");
bundle.remove("name");
- if (gridName == null) {
- gridName = InvariantDeviceProfile.getCurrentGridName(context);
+ if (mGridName == null) {
+ mGridName = InvariantDeviceProfile.getCurrentGridName(context);
}
mWallpaperColors = bundle.getParcelable(KEY_COLORS);
mHideQsb = bundle.getBoolean(GridCustomizationsProvider.KEY_HIDE_BOTTOM_ROW);
- mIdp = new InvariantDeviceProfile(context, gridName);
mHostToken = bundle.getBinder(KEY_HOST_TOKEN);
mWidth = bundle.getInt(KEY_VIEW_WIDTH);
@@ -113,9 +114,9 @@
mDisplay = context.getSystemService(DisplayManager.class)
.getDisplay(bundle.getInt(KEY_DISPLAY_ID));
- mSurfaceControlViewHost = MAIN_EXECUTOR
- .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))
- .get(5, TimeUnit.SECONDS);
+ mSurfaceControlViewHost = MAIN_EXECUTOR.submit(() -> new SurfaceControlViewHost(mContext,
+ context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY),
+ mHostToken)).get(5, TimeUnit.SECONDS);
mOnDestroyCallbacks.add(mSurfaceControlViewHost::release);
}
@@ -195,28 +196,33 @@
}
}
+ /***
+ * Generates a new context overriding the theme color and the display size without affecting the
+ * main application context
+ */
+ private Context getPreviewContext() {
+ Context context = mContext.createDisplayContext(mDisplay);
+ if (mWallpaperColors == null) {
+ return new ContextThemeWrapper(context,
+ Themes.getActivityThemeRes(context));
+ }
+ if (Utilities.ATLEAST_R) {
+ context = context.createWindowContext(
+ LayoutParams.TYPE_APPLICATION_OVERLAY, null);
+ }
+ LocalColorExtractor.newInstance(context)
+ .applyColorsOverride(context, mWallpaperColors);
+ return new ContextThemeWrapper(context,
+ Themes.getActivityThemeRes(context, mWallpaperColors.getColorHints()));
+ }
+
@WorkerThread
private void loadModelData() {
- final Context inflationContext;
- if (mWallpaperColors != null) {
- // Create a themed context, without affecting the main application context
- Context context = mContext.createDisplayContext(mDisplay);
- if (Utilities.ATLEAST_R) {
- context = context.createWindowContext(
- LayoutParams.TYPE_APPLICATION_OVERLAY, null);
- }
- LocalColorExtractor.newInstance(mContext)
- .applyColorsOverride(context, mWallpaperColors);
- inflationContext = new ContextThemeWrapper(context,
- Themes.getActivityThemeRes(context, mWallpaperColors.getColorHints()));
- } else {
- inflationContext = new ContextThemeWrapper(mContext,
- Themes.getActivityThemeRes(mContext));
- }
-
- if (GridSizeMigrationUtil.needsToMigrate(inflationContext, mIdp)) {
+ final Context inflationContext = getPreviewContext();
+ final InvariantDeviceProfile idp = new InvariantDeviceProfile(inflationContext, mGridName);
+ if (GridSizeMigrationUtil.needsToMigrate(inflationContext, idp)) {
// Start the migration
- PreviewContext previewContext = new PreviewContext(inflationContext, mIdp);
+ PreviewContext previewContext = new PreviewContext(inflationContext, idp);
// Copy existing data to preview DB
LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext)
.getModel().getModelDbController().getDb(),
@@ -239,7 +245,7 @@
@Override
public void run() {
- DeviceProfile deviceProfile = mIdp.getDeviceProfile(previewContext);
+ DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext);
String query =
LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
+ " or " + LauncherSettings.Favorites.CONTAINER + " = "
@@ -254,7 +260,8 @@
getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
MAIN_EXECUTOR.execute(() -> {
- renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo);
+ renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo,
+ idp);
mOnDestroyCallbacks.add(previewContext::onDestroy);
});
}
@@ -263,7 +270,7 @@
LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> {
if (dataModel != null) {
MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null,
- null));
+ null, idp));
} else {
Log.e(TAG, "Model loading failed");
}
@@ -274,11 +281,11 @@
@UiThread
private void renderView(Context inflationContext, BgDataModel dataModel,
Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
- @Nullable final SparseArray<Size> launcherWidgetSpanInfo) {
+ @Nullable final SparseArray<Size> launcherWidgetSpanInfo, InvariantDeviceProfile idp) {
if (mDestroyed) {
return;
}
- mRenderer = new LauncherPreviewRenderer(inflationContext, mIdp,
+ mRenderer = new LauncherPreviewRenderer(inflationContext, idp,
mWallpaperColors, launcherWidgetSpanInfo);
mRenderer.hideBottomRow(mHideQsb);
View view = mRenderer.getRenderedView(dataModel, widgetProviderInfoMap);
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 780cb5e..265378c 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -621,9 +621,12 @@
@UiEvent(doc = "User has invoked split to left half with a keyboard shortcut.")
LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233),
- @UiEvent(doc = "User has invoked split to right half with desktop mode app icon")
+ @UiEvent(doc = "User has invoked split to right half from desktop mode.")
LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM(1412),
+ @UiEvent(doc = "User has invoked split to left half from desktop mode.")
+ LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP(1464),
+
@UiEvent(doc = "User has collapsed the work FAB button by scrolling down in the all apps"
+ " work A-Z list.")
LAUNCHER_WORK_FAB_BUTTON_COLLAPSE(1276),
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 933468c..0e68db2 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -374,6 +374,8 @@
final HashMap<PackageUserKey, SessionInfo> installingPkgs =
mSessionHelper.getActiveSessions();
installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
+ FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
+ + installingPkgs.values());
final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 570d6ff..4ab2037 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -27,6 +27,14 @@
void setMarkersCount(int numMarkers);
/**
+ * Sets flag to indicate when the screens are in the process of binding so that we don't animate
+ * during that period.
+ */
+ default void setAreScreensBinding(boolean areScreensBinding) {
+ // No-op by default
+ }
+
+ /**
* Sets the flag if the Page Indicator should autohide.
*/
default void setShouldAutoHide(boolean shouldAutoHide) {
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 073e523..ce71275 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -130,6 +130,7 @@
*/
private float mCurrentPosition;
private float mFinalPosition;
+ private boolean mAreScreensBinding;
private ObjectAnimator mAnimator;
private @Nullable ObjectAnimator mAlphaAnimator;
@@ -163,7 +164,7 @@
@Override
public void setScroll(int currentScroll, int totalScroll) {
- if (SHOW_DOT_PAGINATION.get() && mActivePage != 0 && currentScroll == 0) {
+ if (SHOW_DOT_PAGINATION.get() && currentScroll == 0 && totalScroll == 0) {
CURRENT_POSITION.set(this, (float) mActivePage);
return;
}
@@ -172,6 +173,11 @@
return;
}
+ // Skip scroll update during binding. We will update it when binding completes.
+ if (mAreScreensBinding) {
+ return;
+ }
+
if (mShouldAutoHide) {
animatePaginationToAlpha(VISIBLE_ALPHA);
}
@@ -359,6 +365,16 @@
}
@Override
+ public void setAreScreensBinding(boolean areScreensBinding) {
+ // Reapply correct current position which was skipped during setScroll.
+ if (mAreScreensBinding && !areScreensBinding) {
+ CURRENT_POSITION.set(this, (float) mActivePage);
+ }
+
+ mAreScreensBinding = areScreensBinding;
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Add extra spacing of mDotRadius on all sides so than entry animation could be run.
int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index c554def..4725dd1 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -82,11 +82,15 @@
public static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
public static final String APPWIDGET_IDS = "appwidget_ids";
+ private static final String[] DB_COLUMNS_TO_LOG = {"profileId", "title", "itemType", "screen",
+ "container", "cellX", "cellY", "spanX", "spanY", "intent"};
+
/**
* Tries to restore the backup DB if needed
*/
public static void restoreIfNeeded(Context context, ModelDbController dbController) {
if (!isPending(context)) {
+ Log.d(TAG, "No restore task pending, exiting RestoreDbTask");
return;
}
if (!performRestore(context, dbController)) {
@@ -106,6 +110,7 @@
private static boolean performRestore(Context context, ModelDbController controller) {
SQLiteDatabase db = controller.getDb();
+ FileLog.d(TAG, "performRestore: starting restore from db");
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.sanitizeDB(context, controller, db, new BackupManager(context));
@@ -133,10 +138,11 @@
@VisibleForTesting
protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
BackupManager backupManager) throws Exception {
+ FileLog.d(TAG, "Old Launcher Database before sanitizing:");
// Primary user ids
long myProfileId = controller.getSerialNumberForUser(myUserHandle());
long oldProfileId = getDefaultProfileId(db);
- Log.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
+ FileLog.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
+ 1);
@@ -149,8 +155,11 @@
if (user != null) {
long newManagedProfileId = controller.getSerialNumberForUser(user);
profileMapping.put(oldManagedProfileId, newManagedProfileId);
- Log.d(TAG, "sanitizeDB: managed profile id=" + oldManagedProfileId
+ FileLog.d(TAG, "sanitizeDB: managed profile id=" + oldManagedProfileId
+ " should be mapped to new id=" + newManagedProfileId);
+ } else {
+ FileLog.e(TAG, "sanitizeDB: No User found for old profileId, Ancestral Serial "
+ + "Number: " + oldManagedProfileId);
}
}
@@ -161,11 +170,13 @@
for (int i = numProfiles - 1; i >= 1; --i) {
profileIds[i] = Long.toString(profileMapping.keyAt(i));
}
+
final String[] args = new String[profileIds.length];
Arrays.fill(args, "?");
final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
- int itemsDeleted = db.delete(Favorites.TABLE_NAME, where, profileIds);
- FileLog.d(TAG, itemsDeleted + " items from unrestored user(s) were deleted");
+ logUnrestoredItems(db, where, profileIds);
+ int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
+ FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
// Mark all items as restored.
boolean keepAllIcons = Utilities.isPropertyEnabled(LogConfig.KEEP_ALL_ICONS);
@@ -219,8 +230,48 @@
// Override shortcuts
maybeOverrideShortcuts(context, controller, db, myProfileId);
+ return itemsDeletedCount;
+ }
- return itemsDeleted;
+ /**
+ * Queries and logs the items we will delete from unrestored profiles in the launcher db.
+ * This is to understand why items might be missing during the restore process for Launcher.
+ * @param database the Launcher db to query from.
+ * @param where the SELECT statement to query items that will be deleted.
+ * @param profileIds the profile ID's the user will be migrating to.
+ */
+ private void logUnrestoredItems(SQLiteDatabase database, String where, String[] profileIds) {
+ try (Cursor itemsToDelete = database.query(
+ /* table */ Favorites.TABLE_NAME,
+ /* columns */ DB_COLUMNS_TO_LOG,
+ /* selection */ where,
+ /* selection args */ profileIds,
+ /* groupBy */ null,
+ /* having */ null,
+ /* orderBy */ null
+ )) {
+ if (itemsToDelete.moveToFirst()) {
+ String[] columnNames = itemsToDelete.getColumnNames();
+ StringBuilder stringBuilder = new StringBuilder(
+ "items to be deleted from the Favorites Table during restore:\n"
+ );
+ do {
+ for (String columnName : columnNames) {
+ stringBuilder.append(columnName)
+ .append("=")
+ .append(itemsToDelete.getString(
+ itemsToDelete.getColumnIndex(columnName)))
+ .append(" ");
+ }
+ stringBuilder.append("\n");
+ } while (itemsToDelete.moveToNext());
+ FileLog.d(TAG, stringBuilder.toString());
+ } else {
+ FileLog.d(TAG, "logDeletedItems: No items found to delete");
+ }
+ } catch (Exception e) {
+ FileLog.e(TAG, "logDeletedItems: Error reading from database", e);
+ }
}
/**
@@ -321,7 +372,7 @@
* Marks the DB state as pending restoration
*/
public static void setPending(Context context) {
- FileLog.d(TAG, "Restore data received through full backup ");
+ FileLog.d(TAG, "Restore data received through full backup");
LauncherPrefs.get(context)
.putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType()));
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5306932..07a1b82 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -16,7 +16,7 @@
package com.android.launcher3.testing;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -235,12 +235,6 @@
return response;
}
- case TestProtocol.REQUEST_IS_TRACKPAD_GESTURE_ENABLED: {
- response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- ENABLE_TRACKPAD_GESTURE.get());
- return response;
- }
-
case TestProtocol.REQUEST_ALL_APPS_TOP_PADDING: {
return getLauncherUIProperty(Bundle::putInt,
l -> l.getAppsView().getActiveRecyclerView().getClipBounds().top);
@@ -253,6 +247,12 @@
+ l.getAppsView().getActiveRecyclerView().getPaddingBottom());
}
+ case TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW: {
+ response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ ENABLE_GRID_ONLY_OVERVIEW.get());
+ return response;
+ }
+
default:
return null;
}
diff --git a/src/com/android/launcher3/testing/TestLogging.java b/src/com/android/launcher3/testing/TestLogging.java
index f95548d..70691f8 100644
--- a/src/com/android/launcher3/testing/TestLogging.java
+++ b/src/com/android/launcher3/testing/TestLogging.java
@@ -27,26 +27,29 @@
import java.util.function.BiConsumer;
public final class TestLogging {
+ private static final String TAPL_EVENTS_TAG = "TaplEvents";
+ private static final String LAUNCHER_EVENTS_TAG = "LauncherEvents";
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);
+ private static void recordEventSlow(String sequence, String event, boolean reportToTapl) {
+ Log.d(reportToTapl ? TAPL_EVENTS_TAG : LAUNCHER_EVENTS_TAG,
+ sequence + " / " + event);
final BiConsumer<String, String> eventConsumer = sEventConsumer;
- if (eventConsumer != null) {
+ if (reportToTapl && eventConsumer != null) {
eventConsumer.accept(sequence, event);
}
}
public static void recordEvent(String sequence, String event) {
if (Utilities.isRunningInTestHarness()) {
- recordEventSlow(sequence, event);
+ recordEventSlow(sequence, event, true);
}
}
public static void recordEvent(String sequence, String message, Object parameter) {
if (Utilities.isRunningInTestHarness()) {
- recordEventSlow(sequence, message + ": " + parameter);
+ recordEventSlow(sequence, message + ": " + parameter, true);
}
}
@@ -59,14 +62,20 @@
public static void recordKeyEvent(String sequence, String message, KeyEvent event) {
if (Utilities.isRunningInTestHarness()) {
- recordEventSlow(sequence, message + ": " + event);
+ recordEventSlow(sequence, message + ": " + event, true);
registerEventNotFromTest(event);
}
}
public static void recordMotionEvent(String sequence, String message, MotionEvent event) {
- if (Utilities.isRunningInTestHarness() && event.getAction() != MotionEvent.ACTION_MOVE) {
- recordEventSlow(sequence, message + ": " + event);
+ final int action = event.getAction();
+ if (Utilities.isRunningInTestHarness() && action != MotionEvent.ACTION_MOVE) {
+ // "Expecting" in TAPL motion events was thought to be producing considerable noise in
+ // tests due to failed checks for expected events. So we are not sending them to TAPL.
+ // Other events, such as EVENT_PILFER_POINTERS produce less noise and are thought to
+ // be more useful.
+ // That's why we pass false as the value for the 'reportToTapl' parameter.
+ recordEventSlow(sequence, message + ": " + event, false);
registerEventNotFromTest(event);
}
}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 9cba19d..122b1e0 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -67,7 +67,7 @@
if (!(v.getTag() instanceof ItemInfo)) return false;
launcher.setWaitingForResult(null);
- beginDrag(v, launcher, (ItemInfo) v.getTag(), launcher.getDefaultWorkspaceDragOptions());
+ beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());
return true;
}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 6a972eb..dc4621e 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -582,7 +582,8 @@
? splitInfo.dividerHeightPercent
: splitInfo.dividerWidthPercent;
- float scale = (float) outRect.height() / dp.availableHeightPx;
+ int taskbarHeight = dp.isTransientTaskbar ? 0 : dp.taskbarHeight;
+ float scale = (float) outRect.height() / (dp.availableHeightPx - taskbarHeight);
float topTaskHeight = dp.availableHeightPx * topLeftTaskPercent;
float scaledTopTaskHeight = topTaskHeight * scale;
float dividerHeight = dp.availableHeightPx * dividerBarPercent;
@@ -639,7 +640,8 @@
// Reset unused translations
primarySnapshot.setTranslationY(0);
} else {
- float scale = (float) totalThumbnailHeight / dp.availableHeightPx;
+ int taskbarHeight = dp.isTransientTaskbar ? 0 : dp.taskbarHeight;
+ float scale = (float) totalThumbnailHeight / (dp.availableHeightPx - taskbarHeight);
float topTaskHeight = dp.availableHeightPx * taskPercent;
float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
float scaledTopTaskHeight = topTaskHeight * scale;
diff --git a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
new file mode 100644
index 0000000..18f8339
--- /dev/null
+++ b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.launcher3.util
+
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.util.Log
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import androidx.core.view.OneShotPreDrawListener
+import com.android.app.animation.Interpolators.LINEAR
+import com.android.launcher3.anim.AnimatorListeners
+import com.android.launcher3.anim.AnimatorPlaybackController
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.statemanager.StatefulActivity
+import java.util.function.Consumer
+
+private const val TAG = "CannedAnimCoordinator"
+
+/**
+ * Utility class to run a canned animation on Launcher.
+ *
+ * This class takes care to registering animations with stateManager and ensures that only one
+ * animation is playing at a time.
+ */
+class CannedAnimationCoordinator(private val activity: StatefulActivity<*>) {
+
+ private val launcherLayoutListener = OnGlobalLayoutListener { scheduleRecreateAnimOnPreDraw() }
+ private var recreatePending = false
+
+ private var animationProvider: Any? = null
+
+ private var animationDuration: Long = 0L
+ private var animationFactory: Consumer<PendingAnimation>? = null
+ private var animationController: AnimatorPlaybackController? = null
+
+ private var currentAnim: AnimatorPlaybackController? = null
+
+ /**
+ * Sets the current animation cancelling any previously set animation.
+ *
+ * Callers can control the animation using {@link #getPlaybackController}. The state is
+ * automatically cleared when the playback controller ends. The animation is automatically
+ * recreated when any layout change happens. Callers can also ask for recreation by calling
+ * {@link #recreateAnimation}
+ */
+ fun setAnimation(provider: Any, factory: Consumer<PendingAnimation>, duration: Long) {
+ if (provider != animationProvider) {
+ Log.e(TAG, "Trying to play two animations together, $provider and $animationProvider")
+ }
+
+ // Cancel any previously running animation
+ endCurrentAnimation(false)
+ animationController?.dispatchOnCancel()?.dispatchOnEnd()
+
+ animationProvider = provider
+ animationFactory = factory
+ animationDuration = duration
+
+ // Setup a new controller and link it with launcher state animation
+ val anim = AnimatorSet()
+ anim.play(
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ interpolator = LINEAR
+ this.duration = duration
+ addUpdateListener { anim -> currentAnim?.setPlayFraction(anim.animatedFraction) }
+ }
+ )
+ val controller = AnimatorPlaybackController.wrap(anim, duration)
+ anim.addListener(
+ AnimatorListeners.forEndCallback { success ->
+ if (animationController != controller) {
+ return@forEndCallback
+ }
+
+ endCurrentAnimation(success)
+ animationController = null
+ animationFactory = null
+ animationProvider = null
+
+ activity.rootView.viewTreeObserver.apply {
+ if (isAlive) {
+ removeOnGlobalLayoutListener(launcherLayoutListener)
+ }
+ }
+ }
+ )
+
+ // Recreate animation whenever layout happens in case transforms change during layout
+ activity.rootView.viewTreeObserver.apply {
+ if (isAlive) {
+ addOnGlobalLayoutListener(launcherLayoutListener)
+ }
+ }
+ // Link this to the state manager so that it auto-cancels when state changes
+ recreatePending = false
+ animationController =
+ controller.apply { activity.stateManager.setCurrentUserControlledAnimation(this) }
+ recreateAnimation(provider)
+ }
+
+ private fun endCurrentAnimation(success: Boolean) {
+ currentAnim?.apply {
+ // When cancelling an animation, apply final progress so that all transformations
+ // are restored
+ setPlayFraction(1f)
+ if (!success) dispatchOnCancel()
+ dispatchOnEnd()
+ }
+ currentAnim = null
+ }
+
+ /** Returns the current animation controller to control the animation */
+ fun getPlaybackController(provider: Any): AnimatorPlaybackController? {
+ return if (provider == animationProvider) animationController
+ else {
+ Log.d(TAG, "Wrong controller access from $provider, actual provider $animationProvider")
+ null
+ }
+ }
+
+ private fun scheduleRecreateAnimOnPreDraw() {
+ if (!recreatePending) {
+ recreatePending = true
+ OneShotPreDrawListener.add(activity.rootView) {
+ if (recreatePending) {
+ recreatePending = false
+ animationProvider?.apply { recreateAnimation(this) }
+ }
+ }
+ }
+ }
+
+ /** Notify the controller to recreate the animation. The animation progress is preserved */
+ fun recreateAnimation(provider: Any) {
+ if (provider != animationProvider) {
+ Log.e(TAG, "Ignore recreate request from $provider, actual provider $animationProvider")
+ return
+ }
+ endCurrentAnimation(false /* success */)
+
+ if (animationFactory == null || animationController == null) {
+ return
+ }
+ currentAnim =
+ PendingAnimation(animationDuration)
+ .apply { animationFactory?.accept(this) }
+ .createPlaybackController()
+ .apply { setPlayFraction(animationController!!.progressFraction) }
+ }
+}
diff --git a/src/com/android/launcher3/util/MultiScalePropertyFactory.java b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
index a7e6cc8..cf8d6cc 100644
--- a/src/com/android/launcher3/util/MultiScalePropertyFactory.java
+++ b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
@@ -40,8 +40,7 @@
private static final boolean DEBUG = false;
private static final String TAG = "MultiScaleProperty";
private final String mName;
- private final ArrayMap<Integer, MultiScaleProperty> mProperties =
- new ArrayMap<Integer, MultiScaleProperty>();
+ private final ArrayMap<Integer, MultiScaleProperty> mProperties = new ArrayMap<>();
// This is an optimization for cases when set is called repeatedly with the same setterIndex.
private float mMinOfOthers = 0;
@@ -55,7 +54,7 @@
}
/** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
- public MultiScaleProperty get(Integer index) {
+ public FloatProperty<T> get(Integer index) {
return mProperties.computeIfAbsent(index,
(k) -> new MultiScaleProperty(index, mName + "_" + index));
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 348c8d8..f8f4b5f 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -38,8 +38,6 @@
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
- public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen";
- public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
public static final String TASKBAR_EDU_TOOLTIP_STEP = "launcher.taskbar_edu_tooltip_step";
// When adding a new key, add it here as well, to be able to reset it from Developer Options.
@@ -47,7 +45,6 @@
"All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT },
"Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT,
HOTSEAT_LONGPRESS_TIP_SEEN },
- "Search Education", new String[] { SEARCH_KEYBOARD_EDU_SEEN, SEARCH_SNACKBAR_COUNT},
"Taskbar Education", new String[] { TASKBAR_EDU_TOOLTIP_STEP },
"All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
);
@@ -58,7 +55,6 @@
@StringDef(value = {
HOME_BOUNCE_SEEN,
HOTSEAT_LONGPRESS_TIP_SEEN,
- SEARCH_KEYBOARD_EDU_SEEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventBoolKey {}
@@ -69,7 +65,6 @@
@StringDef(value = {
HOME_BOUNCE_COUNT,
HOTSEAT_DISCOVERY_TIP_COUNT,
- SEARCH_SNACKBAR_COUNT,
ALL_APPS_VISITED_COUNT,
TASKBAR_EDU_TOOLTIP_STEP,
})
@@ -82,7 +77,6 @@
Map<String, Integer> maxCounts = new ArrayMap<>(5);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
- maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
maxCounts.put(ALL_APPS_VISITED_COUNT, 20);
maxCounts.put(TASKBAR_EDU_TOOLTIP_STEP, 2);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index a5c663f..60951ba 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -21,8 +21,6 @@
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
@@ -48,16 +46,9 @@
public static final String KEY_THEMED_ICONS = "themed_icons";
+ /** Gets the WallpaperColorHints and then uses those to get the correct activity theme res. */
public static int getActivityThemeRes(Context context) {
- final int colorHints;
- if (Utilities.ATLEAST_P) {
- WallpaperColors colors = context.getSystemService(WallpaperManager.class)
- .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- colorHints = colors == null ? 0 : colors.getColorHints();
- } else {
- colorHints = 0;
- }
- return getActivityThemeRes(context, colorHints);
+ return getActivityThemeRes(context, WallpaperColorHints.get(context).getHints());
}
public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
diff --git a/src/com/android/launcher3/util/WallpaperColorHints.kt b/src/com/android/launcher3/util/WallpaperColorHints.kt
new file mode 100644
index 0000000..1361c1e
--- /dev/null
+++ b/src/com/android/launcher3/util/WallpaperColorHints.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.app.WallpaperColors
+import android.app.WallpaperManager
+import android.app.WallpaperManager.FLAG_SYSTEM
+import android.app.WallpaperManager.OnColorsChangedListener
+import android.content.Context
+import androidx.annotation.MainThread
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+
+/**
+ * This class caches the system's wallpaper color hints for use by other classes as a performance
+ * enhancer. It also centralizes all the WallpaperManager color hint code in one location.
+ */
+class WallpaperColorHints(private val context: Context) : SafeCloseable {
+ var hints: Int = 0
+ private set
+ private val wallpaperManager
+ get() = context.getSystemService(WallpaperManager::class.java)!!
+ private val onColorHintsChangedListeners = mutableListOf<OnColorHintListener>()
+ private val onClose: SafeCloseable
+
+ init {
+ if (Utilities.ATLEAST_S) {
+ hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
+ val onColorsChangedListener = OnColorsChangedListener { colors, which ->
+ onColorsChanged(colors, which)
+ }
+ UI_HELPER_EXECUTOR.execute {
+ wallpaperManager.addOnColorsChangedListener(
+ onColorsChangedListener,
+ MAIN_EXECUTOR.handler
+ )
+ }
+ onClose = SafeCloseable {
+ UI_HELPER_EXECUTOR.execute {
+ wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
+ }
+ }
+ } else {
+ onClose = SafeCloseable {}
+ }
+ }
+
+ @MainThread
+ private fun onColorsChanged(colors: WallpaperColors?, which: Int) {
+ if ((which and FLAG_SYSTEM) != 0 && Utilities.ATLEAST_S) {
+ val newHints = colors?.colorHints ?: 0
+ if (newHints != hints) {
+ hints = newHints
+ onColorHintsChangedListeners.forEach { it.onColorHintsChanged(newHints) }
+ }
+ }
+ }
+
+ override fun close() = onClose.close()
+
+ fun registerOnColorHintsChangedListener(listener: OnColorHintListener) {
+ onColorHintsChangedListeners.add(listener)
+ }
+
+ fun unregisterOnColorsChangedListener(listener: OnColorHintListener) {
+ onColorHintsChangedListeners.remove(listener)
+ }
+
+ companion object {
+ @VisibleForTesting
+ @JvmField
+ val INSTANCE = MainThreadInitializedObject { WallpaperColorHints(it) }
+ @JvmStatic fun get(context: Context): WallpaperColorHints = INSTANCE.get(context)
+ }
+}
+
+interface OnColorHintListener {
+ fun onColorHintsChanged(colorHints: Int)
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index abca1f8..a4b605c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -794,13 +794,15 @@
}
// Checks the orientation of the screen
- if (LARGE_SCREEN_WIDGET_PICKER.get()
- && mOrientation != newConfig.orientation
- && mDeviceProfile.isTablet
- && !mDeviceProfile.isTwoPanels) {
+ if (mOrientation != newConfig.orientation) {
mOrientation = newConfig.orientation;
- handleClose(false);
- show(Launcher.getLauncher(getContext()), false);
+ if (LARGE_SCREEN_WIDGET_PICKER.get()
+ && mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
+ handleClose(false);
+ show(Launcher.getLauncher(getContext()), false);
+ } else {
+ reset();
+ }
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index d6b41c9..599a591 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides;
+import android.app.ActivityOptions;
import android.app.Person;
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
@@ -40,4 +41,11 @@
public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
return Collections.emptyMap();
}
+
+ /**
+ * Creates an ActivityOptions to play fade-out animation on closing targets
+ */
+ public static ActivityOptions createFadeOutAnimOptions(Context context) {
+ return ActivityOptions.makeCustomAnimation(context, 0, android.R.anim.fade_out);
+ }
}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index bb61fbe..ee151bb 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -345,6 +345,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity-alias android:name="WebSearchActivity"
+ android:label="WebSearchActivity"
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.WEB_SEARCH" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity-alias>
<!-- [b/197780098] Disable eager initialization of Jetpack libraries. -->
<provider
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d86a2f8..825b3dc 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -39,7 +39,6 @@
public static final int HINT_STATE_TWO_BUTTON_ORDINAL = 8;
public static final int OVERVIEW_SPLIT_SELECT_ORDINAL = 9;
public static final int EDIT_MODE_STATE_ORDINAL = 10;
- public static final String TAPL_EVENTS_TAG = "TaplEvents";
public static final String SEQUENCE_MAIN = "Main";
public static final String SEQUENCE_TIS = "TIS";
public static final String SEQUENCE_PILFER = "Pilfer";
@@ -121,7 +120,6 @@
"get-activities-created-count";
public static final String REQUEST_GET_ACTIVITIES = "get-activities";
public static final String REQUEST_HAS_TIS = "has-touch-interaction-service";
- public static final String REQUEST_IS_TRACKPAD_GESTURE_ENABLED = "is-trackpad-gesture-enabled";
public static final String REQUEST_TASKBAR_ALL_APPS_TOP_PADDING =
"taskbar-all-apps-top-padding";
public static final String REQUEST_ALL_APPS_TOP_PADDING = "all-apps-top-padding";
@@ -155,18 +153,19 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
- public static final String FLAKY_ACTIVITY_COUNT = "b/260260325";
public static final String FLAKY_QUICK_SWITCH_TO_PREVIOUS_APP = "b/286084688";
public static final String ICON_MISSING = "b/282963545";
public static final String LAUNCH_SPLIT_PAIR = "b/288939273";
public static final String OVERVIEW_OVER_HOME = "b/279059025";
-
+ public static final String INCORRECT_HOME_STATE = "b/293191790";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
+ public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
+
/** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
public static void testLogD(String tag, String message) {
if (!sDebugTracing) {
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
index e33a304..419cb3d 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
@@ -63,8 +63,8 @@
}
public static class Board extends TestSection {
- Point gridSize;
- String board;
+ public Point gridSize;
+ public String board;
public Board(Point gridSize, String board) {
super(State.BOARD);
@@ -127,7 +127,7 @@
}
}
- List<TestSection> parse() {
+ public List<TestSection> parse() {
List<TestSection> sections = new ArrayList<>();
String[] lines = mTest.split("\n");
Iterator<String> it = Arrays.stream(lines).iterator();
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
index b6c55af..86a7bd3 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
@@ -42,7 +42,7 @@
params.getCellX(), params.getCellY(),
launcher.getWorkspace().getIdForScreen(cellLayout), CONTAINER_DESKTOP);
int screenId = pos.screenId;
- if (screenId > boards.size() - 1) {
+ for (int j = boards.size(); j <= screenId; j++) {
boards.add(new CellLayoutBoard(cellLayout.getCountX(), cellLayout.getCountY()));
}
CellLayoutBoard board = boards.get(screenId);
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
new file mode 100644
index 0000000..715a1f8
--- /dev/null
+++ b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.folder;
+
+import static com.android.launcher3.folder.PreviewBackground.ACCEPT_SCALE_FACTOR;
+import static com.android.launcher3.folder.PreviewBackground.CONSUMPTION_ANIMATION_DURATION;
+import static com.android.launcher3.folder.PreviewBackground.HOVER_ANIMATION_DURATION;
+import static com.android.launcher3.folder.PreviewBackground.HOVER_SCALE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.PathInterpolator;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.CellLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class PreviewBackgroundTest {
+
+ private static final float REST_SCALE = 1f;
+ private static final float EPSILON = 0.00001f;
+
+ @Mock
+ CellLayout mCellLayout;
+
+ private final PreviewBackground mPreviewBackground = new PreviewBackground();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mPreviewBackground.mScale = REST_SCALE;
+ mPreviewBackground.mIsAccepting = false;
+ mPreviewBackground.mIsHovered = false;
+ mPreviewBackground.mIsHoveredOrAnimating = false;
+ mPreviewBackground.invalidate();
+ }
+
+ @Test
+ public void testAnimateScale_restToHovered() {
+ mPreviewBackground.setHovered(true);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ HOVER_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator() instanceof PathInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_restToNotHovered() {
+ mPreviewBackground.setHovered(false);
+
+ assertEquals("Scale changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertNull("Animator not null.", mPreviewBackground.mScaleAnimator);
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_hoveredToHovered() {
+ mPreviewBackground.mScale = HOVER_SCALE;
+ mPreviewBackground.mIsHovered = true;
+ mPreviewBackground.mIsHoveredOrAnimating = true;
+ mPreviewBackground.invalidate();
+
+ mPreviewBackground.setHovered(true);
+
+ assertEquals("Scale changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ assertNull("Animator not null.", mPreviewBackground.mScaleAnimator);
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_hoveredToRest() {
+ mPreviewBackground.mScale = HOVER_SCALE;
+ mPreviewBackground.mIsHovered = true;
+ mPreviewBackground.mIsHoveredOrAnimating = true;
+ mPreviewBackground.invalidate();
+
+ mPreviewBackground.setHovered(false);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ HOVER_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator() instanceof PathInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_restToAccept() {
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale changed.", mPreviewBackground.mScale, ACCEPT_SCALE_FACTOR, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ CONSUMPTION_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator()
+ instanceof AccelerateDecelerateInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 1.", mPreviewBackground.getAcceptScaleProgress(), 1,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_restToRest() {
+ mPreviewBackground.animateToRest();
+
+ assertEquals("Scale changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertNull("Animator not null.", mPreviewBackground.mScaleAnimator);
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_acceptToRest() {
+ mPreviewBackground.mScale = ACCEPT_SCALE_FACTOR;
+ mPreviewBackground.mIsAccepting = true;
+ mPreviewBackground.invalidate();
+
+ mPreviewBackground.animateToRest();
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ CONSUMPTION_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator()
+ instanceof AccelerateDecelerateInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_acceptToHover() {
+ mPreviewBackground.mScale = ACCEPT_SCALE_FACTOR;
+ mPreviewBackground.mIsAccepting = true;
+ mPreviewBackground.invalidate();
+
+ mPreviewBackground.mIsAccepting = false;
+ mPreviewBackground.setHovered(true);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ HOVER_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator() instanceof PathInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_hoverToAccept() {
+ mPreviewBackground.mScale = HOVER_SCALE;
+ mPreviewBackground.mIsHovered = true;
+ mPreviewBackground.mIsHoveredOrAnimating = true;
+ mPreviewBackground.invalidate();
+
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, ACCEPT_SCALE_FACTOR, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ CONSUMPTION_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator()
+ instanceof AccelerateDecelerateInterpolator);
+ mPreviewBackground.mIsHovered = false;
+ endAnimation();
+ assertEquals("Scale progress not 1.", mPreviewBackground.getAcceptScaleProgress(), 1,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_midwayToHoverToAccept() {
+ mPreviewBackground.setHovered(true);
+ runAnimationToFraction(0.5f);
+ assertTrue("Scale not changed.",
+ mPreviewBackground.mScale > REST_SCALE && mPreviewBackground.mScale < HOVER_SCALE);
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, ACCEPT_SCALE_FACTOR, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ CONSUMPTION_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator()
+ instanceof AccelerateDecelerateInterpolator);
+ mPreviewBackground.mIsHovered = false;
+ endAnimation();
+ assertEquals("Scale progress not 1.", mPreviewBackground.getAcceptScaleProgress(), 1,
+ EPSILON);
+ assertNull("Animator not null.", mPreviewBackground.mScaleAnimator);
+ }
+
+ @Test
+ public void testAnimateScale_partWayToAcceptToHover() {
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(0.25f);
+ assertTrue("Scale not changed part way.", mPreviewBackground.mScale > REST_SCALE
+ && mPreviewBackground.mScale < ACCEPT_SCALE_FACTOR);
+
+ mPreviewBackground.mIsAccepting = false;
+ mPreviewBackground.setHovered(true);
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ HOVER_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator() instanceof PathInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_midwayToAcceptEqualsHover() {
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(0.5f);
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ mPreviewBackground.mIsAccepting = false;
+
+ mPreviewBackground.setHovered(true);
+
+ assertEquals("Scale changed.", mPreviewBackground.mScale, HOVER_SCALE, EPSILON);
+ assertNull("Animator not null.", mPreviewBackground.mScaleAnimator);
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_midwayToHoverToRest() {
+ mPreviewBackground.setHovered(true);
+ runAnimationToFraction(0.5f);
+ assertTrue("Scale not changed midway.",
+ mPreviewBackground.mScale > REST_SCALE && mPreviewBackground.mScale < HOVER_SCALE);
+
+ mPreviewBackground.mIsHovered = false;
+ mPreviewBackground.animateToRest();
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ HOVER_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator() instanceof PathInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ @Test
+ public void testAnimateScale_midwayToAcceptToRest() {
+ mPreviewBackground.animateToAccept(mCellLayout, 0, 0);
+ runAnimationToFraction(0.5f);
+ assertTrue("Scale not changed.", mPreviewBackground.mScale > REST_SCALE
+ && mPreviewBackground.mScale < ACCEPT_SCALE_FACTOR);
+
+ mPreviewBackground.animateToRest();
+ runAnimationToFraction(1f);
+
+ assertEquals("Scale not changed.", mPreviewBackground.mScale, REST_SCALE, EPSILON);
+ assertEquals("Duration not correct.", mPreviewBackground.mScaleAnimator.getDuration(),
+ CONSUMPTION_ANIMATION_DURATION);
+ assertTrue("Wrong interpolator used.",
+ mPreviewBackground.mScaleAnimator.getInterpolator()
+ instanceof AccelerateDecelerateInterpolator);
+ endAnimation();
+ assertEquals("Scale progress not 0.", mPreviewBackground.getAcceptScaleProgress(), 0,
+ EPSILON);
+ }
+
+ private void runAnimationToFraction(float animationFraction) {
+ mPreviewBackground.mScaleAnimator.setCurrentFraction(animationFraction);
+ }
+
+ private void endAnimation() {
+ mPreviewBackground.mScaleAnimator.end();
+ }
+}
diff --git a/tests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java b/tests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
new file mode 100644
index 0000000..038c98b
--- /dev/null
+++ b/tests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons;
+
+import static com.android.launcher3.icons.FastBitmapDrawable.CLICK_FEEDBACK_DURATION;
+import static com.android.launcher3.icons.FastBitmapDrawable.HOVERED_SCALE;
+import static com.android.launcher3.icons.FastBitmapDrawable.HOVER_FEEDBACK_DURATION;
+import static com.android.launcher3.icons.FastBitmapDrawable.PRESSED_SCALE;
+import static com.android.launcher3.icons.FastBitmapDrawable.SCALE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Bitmap;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.PathInterpolator;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Spy;
+
+/**
+ * Tests for FastBitmapDrawable.
+ */
+@SmallTest
+@UiThreadTest
+@RunWith(AndroidJUnit4.class)
+public class FastBitmapDrawableTest {
+ private static final float EPSILON = 0.00001f;
+
+ @Spy
+ FastBitmapDrawable mFastBitmapDrawable =
+ spy(new FastBitmapDrawable(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)));
+
+ @Before
+ public void setUp() {
+ FastBitmapDrawable.setFlagHoverEnabled(true);
+ when(mFastBitmapDrawable.isVisible()).thenReturn(true);
+ mFastBitmapDrawable.mIsPressed = false;
+ mFastBitmapDrawable.mIsHovered = false;
+ mFastBitmapDrawable.resetScale();
+ }
+
+ @Test
+ public void testOnStateChange_noState() {
+ int[] state = new int[]{};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No scale changes without state change.
+ assertFalse("State change handled.", isHandled);
+ assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
+ }
+
+ @Test
+ public void testOnStateChange_statePressed() {
+ int[] state = new int[]{android.R.attr.state_pressed};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to state pressed.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ CLICK_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator()
+ instanceof AccelerateInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateHovered() {
+ int[] state = new int[]{android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to state hovered.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ HOVER_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredFlagDisabled() {
+ FastBitmapDrawable.setFlagHoverEnabled(false);
+ int[] state = new int[]{android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No state change with flag disabled.
+ assertFalse("Hover state change handled with flag disabled.", isHandled);
+ assertNull("Animation should not run with hover flag disabled.",
+ mFastBitmapDrawable.mScaleAnimation);
+ }
+
+ @Test
+ public void testOnStateChange_statePressedAndHovered() {
+ int[] state = new int[]{android.R.attr.state_pressed, android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to pressed state only.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ CLICK_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator()
+ instanceof AccelerateInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredAndPressed() {
+ int[] state = new int[]{android.R.attr.state_hovered, android.R.attr.state_pressed};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to pressed state only.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ CLICK_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator()
+ instanceof AccelerateInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredAndPressedToPressed() {
+ mFastBitmapDrawable.mIsPressed = true;
+ mFastBitmapDrawable.mIsHovered = true;
+ SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
+ int[] state = new int[]{android.R.attr.state_pressed};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No scale change from pressed state to pressed state.
+ assertTrue("State not changed.", isHandled);
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredAndPressedToHovered() {
+ mFastBitmapDrawable.mIsPressed = true;
+ mFastBitmapDrawable.mIsHovered = true;
+ SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
+ int[] state = new int[]{android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No scale change from pressed state to hovered state.
+ assertTrue("State not changed.", isHandled);
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredToPressed() {
+ mFastBitmapDrawable.mIsHovered = true;
+ SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
+ int[] state = new int[]{android.R.attr.state_pressed};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No scale change from pressed state to hovered state.
+ assertTrue("State not changed.", isHandled);
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ }
+
+ @Test
+ public void testOnStateChange_statePressedToHovered() {
+ mFastBitmapDrawable.mIsPressed = true;
+ SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
+ int[] state = new int[]{android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No scale change from pressed state to hovered state.
+ assertTrue("State not changed.", isHandled);
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
+ }
+
+ @Test
+ public void testOnStateChange_stateDefaultFromPressed() {
+ mFastBitmapDrawable.mIsPressed = true;
+ SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
+ int[] state = new int[]{};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to default state from pressed state.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ CLICK_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator()
+ instanceof DecelerateInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateDefaultFromHovered() {
+ mFastBitmapDrawable.mIsHovered = true;
+ SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
+ int[] state = new int[]{};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to default state from hovered state.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
+ HOVER_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateHoveredWhilePartiallyScaled() {
+ SCALE.setValue(mFastBitmapDrawable, 0.5f);
+ int[] state = new int[]{android.R.attr.state_hovered};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to hovered state from midway to pressed state.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.",
+ mFastBitmapDrawable.mScaleAnimation.getDuration(), HOVER_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_statePressedWhilePartiallyScaled() {
+ SCALE.setValue(mFastBitmapDrawable, 0.5f);
+ int[] state = new int[]{android.R.attr.state_pressed};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // Animate to pressed state from midway to hovered state.
+ assertTrue("State change not handled.", isHandled);
+ assertEquals("Duration not correct.",
+ mFastBitmapDrawable.mScaleAnimation.getDuration(), CLICK_FEEDBACK_DURATION);
+ mFastBitmapDrawable.mScaleAnimation.end();
+ assertEquals("End value not correct.",
+ (float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
+ assertTrue("Wrong interpolator used.",
+ mFastBitmapDrawable.mScaleAnimation.getInterpolator()
+ instanceof AccelerateInterpolator);
+ }
+
+ @Test
+ public void testOnStateChange_stateDefaultFromPressedNotVisible() {
+ when(mFastBitmapDrawable.isVisible()).thenReturn(false);
+ mFastBitmapDrawable.mIsPressed = true;
+ SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
+ clearInvocations(mFastBitmapDrawable);
+ int[] state = new int[]{};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No animations when state was pressed but drawable no longer visible. Set values directly.
+ assertTrue("State change not handled.", isHandled);
+ assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
+ assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
+ verify(mFastBitmapDrawable).invalidateSelf();
+ }
+
+ @Test
+ public void testOnStateChange_stateDefaultFromHoveredNotVisible() {
+ when(mFastBitmapDrawable.isVisible()).thenReturn(false);
+ mFastBitmapDrawable.mIsHovered = true;
+ SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
+ clearInvocations(mFastBitmapDrawable);
+ int[] state = new int[]{};
+
+ boolean isHandled = mFastBitmapDrawable.onStateChange(state);
+
+ // No animations when state was hovered but drawable no longer visible. Set values directly.
+ assertTrue("State change not handled.", isHandled);
+ assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
+ assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
+ verify(mFastBitmapDrawable).invalidateSelf();
+ }
+}
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index 2a27487..d102397 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -158,4 +158,25 @@
assertThat(dp.isQsbInline).isFalse()
assertThat(dp.hotseatQsbWidth).isEqualTo(1095)
}
+
+ @Test
+ fun border_space_should_be_zero_when_numHotseatIcons_is_smallerOrEqual_1() {
+ initializeVarsForTablet(isGestureMode = false)
+ windowBounds = WindowBounds(Rect(0, 0, 1800, 2560), Rect(0, 104, 0, 0))
+
+ val numShownHotseatIcons = listOf(-1, 0, 1)
+ for (numHotseatIcons in numShownHotseatIcons) {
+ inv?.numShownHotseatIcons = numHotseatIcons
+
+ val dp = newDP()
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dp.numShownHotseatIcons).isEqualTo(numHotseatIcons)
+ assertThat(dp.hotseatBorderSpace).isEqualTo(0)
+
+ assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(177)
+ assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(177)
+ assertThat(dp.hotseatQsbWidth).isEqualTo(1445)
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
index 7e9d9da..c7431f2 100644
--- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
+++ b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
@@ -184,7 +184,7 @@
mStartPoint = icon.getVisibleCenter();
mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
assertThat(findObjectByResourceName("popup_container")).isNotNull();
return appName;
}
@@ -206,7 +206,7 @@
mStartPoint = icon.getVisibleCenter();
mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
assertThat(findObjectByResourceName("popup_container")).isNotNull();
return appName;
}
@@ -214,12 +214,12 @@
private void moveAppToCenterOfScreen() {
mEndPoint.set(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2);
mLauncher.movePointer(mDownTime, SystemClock.uptimeMillis(), DRAG_TIME_MS, true,
- mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+ mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
private void dropApp() {
mLauncher.sendPointer(mDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
- mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+ mEndPoint, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
private void removeAppByName(String appName) {
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 753d89d..45b01f4 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -19,6 +19,8 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.google.common.truth.Truth.assertThat;
@@ -61,6 +63,7 @@
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.TISBindRule;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
@@ -155,7 +158,6 @@
}
@Test
- @ScreenRecord
public void testPressHomeOnAllAppsContextMenu() throws Exception {
final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
@@ -229,7 +231,18 @@
@PortraitLandscape
public void testAllAppsSwitchToWorkspace() {
assertNotNull("switchToWorkspace() returned null",
- mLauncher.getWorkspace().switchToAllApps().switchToWorkspace());
+ mLauncher.getWorkspace().switchToAllApps()
+ .switchToWorkspace(/* swipeDown= */ true));
+ assertTrue("Launcher internal state is not Workspace",
+ isInState(() -> LauncherState.NORMAL));
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testAllAppsSwipeUpToWorkspace() {
+ assertNotNull("testAllAppsSwipeUpToWorkspace() returned null",
+ mLauncher.getWorkspace().switchToAllApps()
+ .switchToWorkspace(/* swipeDown= */ false));
assertTrue("Launcher internal state is not Workspace",
isInState(() -> LauncherState.NORMAL));
}
@@ -318,7 +331,8 @@
}
@Test
- @Ignore // b/293191790
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/293191790
+ @ScreenRecord
@PortraitLandscape
public void testWidgets() throws Exception {
// Test opening widgets.
@@ -380,6 +394,28 @@
}
}
+ @Test
+ public void testLaunchHomeScreenMenuItem() {
+ // Drag the test app icon to home screen and open short cut menu from the icon
+ final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
+ final AppIconMenu menu = mLauncher.getWorkspace().getWorkspaceAppIcon(
+ APP_NAME).openDeepShortcutMenu();
+
+ executeOnLauncher(
+ launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
+ isOptionsPopupVisible(launcher)));
+
+ final AppIconMenuItem menuItem = menu.getMenuItem(1);
+ assertEquals("Wrong menu item", "Shortcut 2", menuItem.getText());
+ menuItem.launch(getAppPackageName());
+ } finally {
+ allApps.unfreeze();
+ }
+ }
+
@PlatinumTest(focusArea = "launcher")
@Test
@PortraitLandscape
@@ -519,7 +555,9 @@
@Test
@PortraitLandscape
- @PlatinumTest(focusArea = "launcher")
+ // TODO(b/293944634): Remove Screenrecord after flaky debug, and add
+ // @PlatinumTest(focusArea = "launcher") back
+ @ScreenRecord
public void testUninstallFromWorkspace() throws Exception {
installDummyAppAndWaitForUIUpdate();
try {
@@ -581,10 +619,13 @@
}
}
+ /**
+ * Adds three icons to the workspace and removes one of them by dragging to uninstall.
+ */
@Test
@ScreenRecord // b/241821721
@PlatinumTest(focusArea = "launcher")
- public void getIconsPosition_afterIconRemoved_notContained() throws IOException {
+ public void uninstallWorkspaceIcon() throws IOException {
Point[] gridPositions = getCornersAndCenterPositions();
StringBuilder sb = new StringBuilder();
for (Point p : gridPositions) {
@@ -605,6 +646,10 @@
mLauncher.getWorkspace().verifyWorkspaceAppIconIsGone(
DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
+ // Debug for b/288944469 I want to test if we are not waiting enough after removing
+ // the icon to request the list of icons again, since the items are not removed
+ // immediately. This should reduce the flake rate
+ SystemClock.sleep(500);
Map<String, Point> finalPositions =
mLauncher.getWorkspace().getWorkspaceIconsPositions();
assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 4580082..261436b 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -227,7 +227,8 @@
UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
- SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE, LockedUserState.INSTANCE,
+ SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
+ LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
// System settings cache content provider. Ensure that they are statically initialized
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
index 4cd6c53..21059e6 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -67,6 +67,7 @@
private static final String TAG = "TestUtil";
public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
+ public static final String DUMMY_CLASS_NAME = "com.example.android.aardwolf.Activity1";
public static final long DEFAULT_UI_TIMEOUT = 10000;
public static void installDummyApp() throws IOException {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index f2ae9d3..62d70ad 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -103,7 +103,8 @@
if (viewCaptureDataSupplier != null) {
out.putNextEntry(new ZipEntry("FS/data/misc/wmtrace/failed_test.vc"));
- viewCaptureDataSupplier.get().writeTo(out);
+ final ExportedData exportedData = viewCaptureDataSupplier.get();
+ if (exportedData != null) exportedData.writeTo(out);
out.closeEntry();
}
} catch (Exception ignored) {
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index f33a50a..38de071 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -17,6 +17,8 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeTrue;
+
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
@@ -69,12 +71,9 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- if ((stability.flavors() & getRunFlavor()) != 0) {
- Log.d(TAG, "Running " + description.getDisplayName());
- base.evaluate();
- } else {
- Log.d(TAG, "Skipping " + description.getDisplayName());
- }
+ assumeTrue("Ignoring the test due to @Stability annotation",
+ (stability.flavors() & getRunFlavor()) != 0);
+ base.evaluate();
}
};
} else {
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index f3f9b89..ccbae4f 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -20,11 +20,13 @@
import android.media.permission.SafeCloseable
import android.os.Bundle
import androidx.test.core.app.ApplicationProvider
+import androidx.test.platform.app.InstrumentationRegistry
import com.android.app.viewcapture.SimpleViewCapture
import com.android.app.viewcapture.ViewCapture.MAIN_EXECUTOR
import com.android.app.viewcapture.data.ExportedData
import com.android.launcher3.tapl.TestHelpers
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT
import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer
import java.io.BufferedOutputStream
import java.io.FileOutputStream
@@ -49,6 +51,13 @@
private set
override fun apply(base: Statement, description: Description): Statement {
+ // Skip view capture collection in Launcher3 tests to avoid hidden API check exception.
+ if (
+ "com.android.launcher3.tests" ==
+ InstrumentationRegistry.getInstrumentation().context.packageName
+ )
+ return base
+
return object : Statement() {
override fun evaluate() {
viewCaptureData = null
@@ -116,6 +125,9 @@
// OOP tests don't produce ViewCapture data
if (!TestHelpers.isInLauncherProcess()) return
+ // Due to flakiness of ViewCapture verifier, don't run the check in presubmit
+ if (TestStabilityRule.getRunFlavor() != PLATFORM_POSTSUBMIT) return
+
var frameCount = 0
for (i in 0 until viewCaptureData!!.windowDataCount) {
frameCount += viewCaptureData!!.getWindowData(i).frameDataCount
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
index 38de2fa..4b65439 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -104,12 +104,14 @@
DRAG_LAYER + "Snackbar|TextView:id/label",
DRAG_LAYER + "SplitInstructionsView|AppCompatTextView:id/split_instructions_text",
DRAG_LAYER + "TaskMenuView|LinearLayout:id/menu_option_layout",
+ DRAG_LAYER + "TaskMenuViewWithArrow|LinearLayout:id/menu_option_layout",
DRAG_LAYER + "TaskMenuView|TextView:id/task_name",
DRAG_LAYER + "View",
DRAG_LAYER + "WidgetsFullSheet|SpringRelativeLayout:id/container",
DRAG_LAYER + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container",
CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
RECENTS_DRAG_LAYER + "ArrowTipView",
+ DRAG_LAYER + "ArrowTipView",
DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
DRAG_LAYER
@@ -178,7 +180,8 @@
}
@Override
- String detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN, long timestamp) {
+ String detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN, long timestamp,
+ int windowSizePx) {
// If the view was previously seen, proceed with analysis only if it was present in the
// view hierarchy in the previous frame.
if (oldInfo != null && oldInfo.frameN != frameN) return null;
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AnomalyDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AnomalyDetector.java
index 09e2f65..786791c 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AnomalyDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AnomalyDetector.java
@@ -68,17 +68,18 @@
* null value means that the view. 'oldInfo' and 'newInfo' cannot be both null.
* If an anomaly is detected, an exception will be thrown.
*
- * @param oldInfo the view, as seen in the last frame that contained it in the view
- * hierarchy before 'currentFrame'. 'null' means that the view is first seen
- * in the 'currentFrame'.
- * @param newInfo the view in the view hierarchy of the 'currentFrame'. 'null' means that
- * the view is not present in the 'currentFrame', but was present in the previous
- * frame.
- * @param frameN number of the current frame.
+ * @param oldInfo the view, as seen in the last frame that contained it in the view
+ * hierarchy before 'currentFrame'. 'null' means that the view is first seen
+ * in the 'currentFrame'.
+ * @param newInfo the view in the view hierarchy of the 'currentFrame'. 'null' means that
+ * the view is not present in the 'currentFrame', but was present in the
+ * previous frame.
+ * @param frameN number of the current frame.
+ * @param windowSizePx maximum of the window width and height, in pixels.
* @return Anomaly diagnostic message if an anomaly has been detected; null otherwise.
*/
abstract String detectAnomalies(
@Nullable ViewCaptureAnalyzer.AnalysisNode oldInfo,
@Nullable ViewCaptureAnalyzer.AnalysisNode newInfo, int frameN,
- long frameTimeNs);
+ long frameTimeNs, int windowSizePx);
}
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
index 4210d06..8b88ace 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
@@ -38,9 +38,6 @@
private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree(List.of(
CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
- DRAG_LAYER
- + "SearchContainerView:id/apps_view|AllAppsRecyclerView:id/apps_list_view"
- + "|BubbleTextView:id/icon",
DRAG_LAYER + "LauncherRecentsView:id/overview_panel|TaskView|TextView",
DRAG_LAYER
+ "LauncherAllAppsContainerView:id/apps_view|AllAppsRecyclerView:id"
@@ -57,10 +54,17 @@
+ "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
+ "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel|TaskView|IconView:id/icon",
+ DRAG_LAYER + "SearchContainerView:id/apps_view",
+ DRAG_LAYER + "LauncherDragView",
+ DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail",
DRAG_LAYER
- + "SearchContainerView:id/apps_view|UniversalSearchInputView:id"
- + "/search_container_all_apps|View:id/ripple",
- DRAG_LAYER + "LauncherDragView"
+ + "WidgetsFullSheet|SpringRelativeLayout:id/container|WidgetsRecyclerView:id"
+ + "/primary_widgets_list_view|WidgetsListHeader:id/widgets_list_header",
+ DRAG_LAYER
+ + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container|LinearLayout:id"
+ + "/linear_layout_container|FrameLayout:id/recycler_view_container"
+ + "|FrameLayout:id/widgets_two_pane_sheet_recyclerview|WidgetsRecyclerView:id"
+ + "/primary_widgets_list_view|WidgetsListHeader:id/widgets_list_header"
));
// Per-AnalysisNode data that's specific to this detector.
@@ -106,7 +110,7 @@
@Override
String detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN,
- long frameTimeNs) {
+ long frameTimeNs, int windowSizePx) {
// Should we check when a view was visible for a short period, then its alpha became 0?
// Then 'lastVisible' time should be the last one still visible?
// Check only transitions of alpha between 0 and 1?
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java
new file mode 100644
index 0000000..a1ddcb0
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util.viewcapture_analysis;
+
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnalysisNode;
+
+import java.util.List;
+
+/**
+ * Anomaly detector that triggers an error when a view position jumps.
+ */
+final class PositionJumpDetector extends AnomalyDetector {
+ // Maximum allowed jump in "milliwindows", i.e. a 1/1000's of the maximum of the window
+ // dimensions.
+ private static final float JUMP_MIW = 250;
+
+ private static final String[] BORDER_NAMES = {"left", "top", "right", "bottom"};
+
+ // Commonly used parts of the paths to ignore.
+ private static final String CONTENT = "DecorView|LinearLayout|FrameLayout:id/content|";
+ private static final String DRAG_LAYER =
+ CONTENT + "LauncherRootView:id/launcher|DragLayer:id/drag_layer|";
+ private static final String RECENTS_DRAG_LAYER =
+ CONTENT + "LauncherRootView:id/launcher|RecentsDragLayer:id/drag_layer|";
+
+ private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree(List.of(
+ DRAG_LAYER + "SearchContainerView:id/apps_view",
+ DRAG_LAYER + "AppWidgetResizeFrame",
+ DRAG_LAYER + "LauncherAllAppsContainerView:id/apps_view",
+ CONTENT
+ + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+ + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content",
+ DRAG_LAYER + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container",
+ DRAG_LAYER + "WidgetsFullSheet|SpringRelativeLayout:id/container",
+ DRAG_LAYER + "LauncherDragView",
+ RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel|TaskView",
+ CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
+ DRAG_LAYER + "FloatingTaskView",
+ DRAG_LAYER + "LauncherRecentsView:id/overview_panel"
+ ));
+
+ // Per-AnalysisNode data that's specific to this detector.
+ private static class NodeData {
+ public boolean ignoreJumps;
+
+ // If ignoreNode is null, then this AnalysisNode node will be ignored if its parent is
+ // ignored.
+ // Otherwise, this AnalysisNode will be ignored if ignoreNode is a leaf i.e. has no
+ // children.
+ public IgnoreNode ignoreNode;
+ }
+
+ private NodeData getNodeData(AnalysisNode info) {
+ return (NodeData) info.detectorsData[detectorOrdinal];
+ }
+
+ @Override
+ void initializeNode(AnalysisNode info) {
+ final NodeData nodeData = new NodeData();
+ info.detectorsData[detectorOrdinal] = nodeData;
+
+ // If the parent view ignores jumps, its descendants will too.
+ final boolean parentIgnoresJumps = info.parent != null && getNodeData(
+ info.parent).ignoreJumps;
+ if (parentIgnoresJumps) {
+ nodeData.ignoreJumps = true;
+ return;
+ }
+
+ // Parent view doesn't ignore jumps.
+ // Initialize this AnalysisNode's ignore-node with the corresponding child of the
+ // ignore-node of the parent, if present.
+ final IgnoreNode parentIgnoreNode = info.parent != null
+ ? getNodeData(info.parent).ignoreNode
+ : IGNORED_NODES_ROOT;
+ nodeData.ignoreNode = parentIgnoreNode != null
+ ? parentIgnoreNode.children.get(info.nodeIdentity) : null;
+ // AnalysisNode will be ignored if the corresponding ignore-node is a leaf.
+ nodeData.ignoreJumps =
+ nodeData.ignoreNode != null && nodeData.ignoreNode.children.isEmpty();
+ }
+
+ @Override
+ String detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN,
+ long frameTimeNs, int windowSizePx) {
+ // If the view is not present in the current frame, there can't be a jump detected in the
+ // current frame.
+ if (newInfo == null) return null;
+
+ // We only detect position jumps if the view was visible in the previous frame.
+ if (oldInfo == null || frameN != oldInfo.frameN + 1) return null;
+
+ final NodeData newNodeData = getNodeData(newInfo);
+ if (newNodeData.ignoreJumps) return null;
+
+ final float[] positionDiffs = {
+ newInfo.left - oldInfo.left,
+ newInfo.top - oldInfo.top,
+ newInfo.right - oldInfo.right,
+ newInfo.bottom - oldInfo.bottom
+ };
+
+ for (int i = 0; i < 4; ++i) {
+ final float positionDiffAbs = Math.abs(positionDiffs[i]);
+ if (positionDiffAbs * 1000 > JUMP_MIW * windowSizePx) {
+ newNodeData.ignoreJumps = true;
+ return String.format("Position jump: %s jumped by %s",
+ BORDER_NAMES[i], positionDiffAbs);
+ }
+ }
+ return null;
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
index ccb4a1e..9459cc2 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
@@ -36,7 +36,8 @@
// All detectors. They will be invoked in the order listed here.
private static final AnomalyDetector[] ANOMALY_DETECTORS = {
new AlphaJumpDetector(),
- new FlashDetector()
+ new FlashDetector(),
+ new PositionJumpDetector()
};
static {
@@ -52,6 +53,8 @@
// Window coordinates of the view.
public float left;
public float top;
+ public float right;
+ public float bottom;
// Visible scale and alpha, build recursively from the ancestor list.
public float scaleX;
@@ -81,7 +84,8 @@
@Override
public String toString() {
- return String.format("view window coordinates: (%s, %s)", left, top);
+ return String.format("view window coordinates: (%s, %s, %s, %s)",
+ left, top, right, bottom);
}
}
@@ -112,15 +116,33 @@
// As we go though frames, if a view becomes invisible, it stays in the map.
final Map<Integer, AnalysisNode> lastSeenNodes = new HashMap<>();
+ int windowWidthPx = -1;
+ int windowHeightPx = -1;
+
for (int frameN = 0; frameN < windowData.getFrameDataCount(); ++frameN) {
- analyzeFrame(frameN, windowData.getFrameData(frameN), viewCaptureData, lastSeenNodes,
- scrimClassIndex, anomalies);
+ final FrameData frame = windowData.getFrameData(frameN);
+ final ViewNode rootNode = frame.getNode();
+
+ // If the rotation or window size has changed, reset the analyzer state.
+ final boolean isFirstFrame = windowWidthPx != rootNode.getWidth()
+ || windowHeightPx != rootNode.getHeight();
+ if (isFirstFrame) {
+ windowWidthPx = rootNode.getWidth();
+ windowHeightPx = rootNode.getHeight();
+ lastSeenNodes.clear();
+ }
+
+ final int windowSizePx = Math.max(rootNode.getWidth(), rootNode.getHeight());
+
+ analyzeFrame(frameN, isFirstFrame, frame, viewCaptureData, lastSeenNodes,
+ scrimClassIndex, anomalies, windowSizePx);
}
}
- private static void analyzeFrame(int frameN, FrameData frame, ExportedData viewCaptureData,
+ private static void analyzeFrame(int frameN, boolean isFirstFrame, FrameData frame,
+ ExportedData viewCaptureData,
Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex,
- Map<String, String> anomalies) {
+ Map<String, String> anomalies, int windowSizePx) {
// Analyze the node tree starting from the root.
long frameTimeNs = frame.getTimestamp();
analyzeView(
@@ -128,12 +150,14 @@
frame.getNode(),
/* parent = */ null,
frameN,
+ isFirstFrame,
/* leftShift = */ 0,
/* topShift = */ 0,
viewCaptureData,
lastSeenNodes,
scrimClassIndex,
- anomalies);
+ anomalies,
+ windowSizePx);
// Analyze transitions when a view visible in the previous frame became invisible in the
// current one.
@@ -148,7 +172,8 @@
/* oldInfo = */ info,
/* newInfo = */ null,
anomalies,
- frameTimeNs)
+ frameTimeNs,
+ windowSizePx)
);
}
info.timeBecameInvisibleNs = info.alpha == 1 ? frameTimeNs : -1;
@@ -159,9 +184,9 @@
private static void analyzeView(long frameTimeNs, ViewNode viewCaptureNode, AnalysisNode parent,
int frameN,
- float leftShift, float topShift, ExportedData viewCaptureData,
+ boolean isFirstFrame, float leftShift, float topShift, ExportedData viewCaptureData,
Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex,
- Map<String, String> anomalies) {
+ Map<String, String> anomalies, int windowSizePx) {
// Skip analysis of invisible views
final float parentAlpha = parent != null ? parent.alpha : 1;
final float alpha = getVisibleAlpha(viewCaptureNode, parentAlpha);
@@ -182,6 +207,8 @@
final float top = topShift
+ (viewCaptureNode.getTop() + viewCaptureNode.getTranslationY()) * parentScaleY
+ viewCaptureNode.getHeight() * (parentScaleY - scaleY) / 2;
+ final float width = viewCaptureNode.getWidth() * scaleX;
+ final float height = viewCaptureNode.getHeight() * scaleY;
// Initialize new analysis node
final AnalysisNode newAnalysisNode = new AnalysisNode();
@@ -192,6 +219,8 @@
newAnalysisNode.parent = parent;
newAnalysisNode.left = left;
newAnalysisNode.top = top;
+ newAnalysisNode.right = left + width;
+ newAnalysisNode.bottom = top + height;
newAnalysisNode.scaleX = scaleX;
newAnalysisNode.scaleY = scaleY;
newAnalysisNode.alpha = alpha;
@@ -216,11 +245,11 @@
}
// Detect anomalies for the view.
- if (frameN != 0 && !viewCaptureNode.getWillNotDraw()) {
+ if (!isFirstFrame && !viewCaptureNode.getWillNotDraw()) {
Arrays.stream(ANOMALY_DETECTORS).forEach(
detector ->
detectAnomaly(detector, frameN, oldAnalysisNode, newAnalysisNode,
- anomalies, frameTimeNs)
+ anomalies, frameTimeNs, windowSizePx)
);
}
lastSeenNodes.put(hashcode, newAnalysisNode);
@@ -235,17 +264,19 @@
// transparent.
if (child.getClassnameIndex() == scrimClassIndex) break;
- analyzeView(frameTimeNs, child, newAnalysisNode, frameN, leftShiftForChildren,
+ analyzeView(frameTimeNs, child, newAnalysisNode, frameN, isFirstFrame,
+ leftShiftForChildren,
topShiftForChildren,
- viewCaptureData, lastSeenNodes, scrimClassIndex, anomalies);
+ viewCaptureData, lastSeenNodes, scrimClassIndex, anomalies, windowSizePx);
}
}
private static void detectAnomaly(AnomalyDetector detector, int frameN,
AnalysisNode oldAnalysisNode, AnalysisNode newAnalysisNode,
- Map<String, String> anomalies, long frameTimeNs) {
+ Map<String, String> anomalies, long frameTimeNs, int windowSizePx) {
final String maybeAnomaly =
- detector.detectAnomalies(oldAnalysisNode, newAnalysisNode, frameN, frameTimeNs);
+ detector.detectAnomalies(oldAnalysisNode, newAnalysisNode, frameN, frameTimeNs,
+ windowSizePx);
if (maybeAnomaly != null) {
AnalysisNode latestInfo = newAnalysisNode != null ? newAnalysisNode : oldAnalysisNode;
final String viewDiagPath = diagPathFromRoot(latestInfo);
diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
index 10afe13..425c3c0 100644
--- a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
+++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
@@ -45,8 +45,8 @@
mLauncher.clickObject(
mLauncher.waitForObjectInContainer(
mWidgetCell.getParent().getParent().getParent().getParent(),
- By.text(ADD_AUTOMATICALLY)),
- LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+ By.text(ADD_AUTOMATICALLY))
+ );
mLauncher.waitUntilLauncherObjectGone(getSelector());
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 23d09d4..fb08ea4 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -336,4 +336,11 @@
final Bundle testInfo = mLauncher.getTestInfo(TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS);
return testInfo == null ? 0 : testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+
+ /**
+ * Return the QSB UI object on the AllApps screen.
+ * @return the QSB UI object.
+ */
+ @NonNull
+ public abstract Qsb getQsb();
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java
index c4744a1..0e0291f 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java
@@ -62,4 +62,10 @@
return mLauncher.getTestInfo(TestProtocol.REQUEST_TASKBAR_APPS_LIST_SCROLL_Y)
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+
+ @NonNull
+ @Override
+ public TaskbarAllAppsQsb getQsb() {
+ return new TaskbarAllAppsQsb(mLauncher, verifyActiveContainer());
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java b/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java
index 0931cd4..1692351 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java
@@ -22,16 +22,7 @@
*/
class AllAppsQsb extends Qsb {
- private final UiObject2 mAllAppsContainer;
-
AllAppsQsb(LauncherInstrumentation launcher, UiObject2 allAppsContainer) {
- super(launcher);
- mAllAppsContainer = allAppsContainer;
- waitForQsbObject();
- }
-
- @Override
- protected UiObject2 waitForQsbObject() {
- return mLauncher.waitForObjectInContainer(mAllAppsContainer, "search_container_all_apps");
+ super(launcher, allAppsContainer, "search_container_all_apps");
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 7dd5827..677f204 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -18,8 +18,6 @@
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-import static com.android.launcher3.tapl.LauncherInstrumentation.EVENT_TOUCH_DOWN_TIS;
-import static com.android.launcher3.tapl.LauncherInstrumentation.EVENT_TOUCH_UP_TIS;
import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
@@ -68,10 +66,6 @@
}
- protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
- return mLauncher.isTablet();
- }
-
protected boolean zeroButtonToOverviewGestureStateTransitionWhileHolding() {
return false;
}
@@ -133,16 +127,6 @@
}
}
} else {
- if (mLauncher.isTablet()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_DOWN);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_UP);
- }
- if (mLauncher.isTrackpadGestureEnabled()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
- }
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
mLauncher.runToState(
() -> mLauncher.waitForNavigationUiObject("recent_apps").click(),
@@ -158,12 +142,9 @@
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
final int startY = getSwipeStartY();
final Point start = new Point(centerX, startY);
- final LauncherInstrumentation.GestureScope gestureScope =
- zeroButtonToOverviewGestureStartsInLauncher()
- ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
- : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start,
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER);
if (!mLauncher.isLauncher3()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_PILFER,
@@ -179,10 +160,6 @@
final Point start = new Point(centerX, startY);
final Point end =
new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
- final LauncherInstrumentation.GestureScope gestureScope =
- zeroButtonToOverviewGestureStartsInLauncher()
- ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
- : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
mLauncher.movePointer(
downTime,
@@ -190,7 +167,7 @@
ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION,
start,
end,
- gestureScope);
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER);
}
private void sendUpPointerToEnterOverviewToLauncher(long downTime) {
@@ -201,13 +178,9 @@
final Point end =
new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
- final LauncherInstrumentation.GestureScope gestureScope =
- zeroButtonToOverviewGestureStartsInLauncher()
- ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
- : LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER;
-
mLauncher.sendPointer(downTime, SystemClock.uptimeMillis(),
- MotionEvent.ACTION_UP, end, gestureScope);
+ MotionEvent.ACTION_UP, end,
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
/**
@@ -239,7 +212,6 @@
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to quick switch to the previous app")) {
verifyActiveContainer();
- final boolean launcherWasVisible = mLauncher.isLauncherVisible();
if (mLauncher.getNavigationModel() == NavigationModel.ZERO_BUTTON
|| mLauncher.getTrackpadGestureType() == TrackpadGestureType.FOUR_FINGER) {
final int startX;
@@ -261,42 +233,19 @@
endY = startY;
}
- LauncherInstrumentation.GestureScope gestureScope =
- launcherWasVisible
- ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
- : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
mLauncher.executeAndWaitForEvent(
() -> mLauncher.linearGesture(
- startX, startY, endX, endY, 20, false, gestureScope),
+ startX, startY, endX, endY, 20, false,
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER),
event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
() -> "Quick switch gesture didn't change window state", "swiping");
} else {
// Double press the recents button.
UiObject2 recentsButton = mLauncher.waitForNavigationUiObject("recent_apps");
- if (mLauncher.isTablet()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_DOWN);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_UP);
- }
- if (mLauncher.isTrackpadGestureEnabled()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
- }
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
mLauncher.runToState(() -> recentsButton.click(), OVERVIEW_STATE_ORDINAL,
"clicking Recents button for the first time");
mLauncher.getOverview();
- if (mLauncher.isTablet()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_DOWN);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_TOUCH_UP);
- }
- if (mLauncher.isTrackpadGestureEnabled()) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
- }
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
mLauncher.executeAndWaitForEvent(
() -> recentsButton.click(),
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 2c3c028..aa5c770 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -324,13 +324,16 @@
if (!hasTasks() || isClearAllVisible()) {
return false;
}
- OverviewTask task = mLauncher.isTablet() ? getFocusedTaskForTablet() : getCurrentTask();
+ boolean isTablet = mLauncher.isTablet();
+ if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
+ return false;
+ }
+ OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
if (task == null) {
return false;
}
// In tablets, if focused task is not in center, overview actions aren't visible.
- if (mLauncher.isTablet()
- && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
+ if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
return false;
}
// Overview actions aren't visible for split screen tasks.
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index ee9dd1a..252435b 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -59,11 +59,6 @@
}
@Override
- protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
- return true;
- }
-
- @Override
protected boolean zeroButtonToOverviewGestureStateTransitionWhileHolding() {
return true;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 1239d7a..2951901 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -30,23 +30,28 @@
}
/**
- * Swipes down to Workspace.
+ * Swipes up or down to dismiss to Workspace.
+ * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
*
* @return the Workspace object.
*/
@NonNull
- public Workspace switchToWorkspace() {
+ public Workspace switchToWorkspace(boolean swipeDown) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to switch from all apps to workspace")) {
UiObject2 allAppsContainer = verifyActiveContainer();
final int startX = allAppsContainer.getVisibleCenter().x;
- final int startY = getTopVisibleIconBounds(allAppsContainer).centerY();
- final int endY = mLauncher.getDevice().getDisplayHeight();
+ final int startY = swipeDown ? getTopVisibleIconBounds(allAppsContainer).centerY()
+ : mLauncher.getDevice().getDisplayHeight();
+ final int endY =
+ swipeDown ? mLauncher.getDevice().getDisplayHeight() : getTopVisibleIconBounds(
+ allAppsContainer).centerY();
LauncherInstrumentation.log(
"switchToWorkspace: startY = " + startY + ", endY = " + endY
- + ", slop = " + mLauncher.getTouchSlop());
+ + ", slop = " + mLauncher.getTouchSlop()
+ + ", swipeDown = " + swipeDown);
mLauncher.swipeToState(
startX,
@@ -54,7 +59,9 @@
startX,
endY,
5 /* steps */,
- NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
+ NORMAL_STATE_ORDINAL,
+ swipeDown ? LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER
+ : LauncherInstrumentation.GestureScope.EXPECT_PILFER);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"swiped to workspace")) {
@@ -110,11 +117,8 @@
}
}
- /**
- * Return the QSB UI object on the AllApps screen.
- * @return the QSB UI object.
- */
@NonNull
+ @Override
public Qsb getQsb() {
return new AllAppsQsb(mLauncher, verifyActiveContainer());
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
index 20d09a1..5385c65 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
@@ -22,16 +22,7 @@
*/
class HomeQsb extends Qsb {
- private final UiObject2 mHotSeat;
-
HomeQsb(LauncherInstrumentation launcher, UiObject2 hotseat) {
- super(launcher);
- mHotSeat = hotseat;
- waitForQsbObject();
- }
-
- @Override
- protected UiObject2 waitForQsbObject() {
- return mLauncher.waitForObjectInContainer(mHotSeat, "search_container_hotseat");
+ super(launcher, hotseat, "search_container_hotseat");
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 48e327f..a953fa9 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -152,7 +152,7 @@
downTime,
MotionEvent.ACTION_DOWN,
iconCenter,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
LauncherInstrumentation.log("movePointerForStartDrag: sent down");
expectLongClickEvents.run();
waitForLongPressConfirmation();
@@ -165,7 +165,7 @@
downTime,
downTime,
/* slowDown= */ true,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
private int getStartDragThreshold() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 9b4d273..30417c0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -30,6 +30,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -127,13 +128,13 @@
mLauncher.getRealDisplaySize().x / 2, unstashTargetY);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget,
- LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER);
LauncherInstrumentation.log("showTaskbar: sent down");
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
- LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER);
return new Taskbar(mLauncher);
}
@@ -182,7 +183,7 @@
downTime,
SystemClock.uptimeMillis(),
/* slowDown= */ false,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
try (LauncherInstrumentation.Closable c3 = launcher.addContextLayer(
"moved pointer to drop point")) {
@@ -193,7 +194,7 @@
SystemClock.uptimeMillis(),
MotionEvent.ACTION_UP,
endPoint,
- LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
LauncherInstrumentation.log("SplitscreenDragSource.dragToSplitscreen: "
+ "after drop");
@@ -223,12 +224,14 @@
int leftEdge = 10;
Point taskbarUnstashArea = new Point(leftEdge, mLauncher.getRealDisplaySize().y - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
- new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+ InputDevice.SOURCE_MOUSE);
mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
- new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+ InputDevice.SOURCE_MOUSE);
return new Taskbar(mLauncher);
}
@@ -245,7 +248,8 @@
Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
mLauncher.getRealDisplaySize().y - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
- new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+ new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null,
+ InputDevice.SOURCE_MOUSE);
mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
LauncherInstrumentation.WAIT_TIME_MS);
@@ -256,7 +260,8 @@
Point taskbarUnstashArea = new Point(mLauncher.getRealDisplaySize().x / 2,
mLauncher.getRealDisplaySize().y - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
- new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+ InputDevice.SOURCE_MOUSE);
mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
return new Taskbar(mLauncher);
@@ -308,7 +313,8 @@
Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
mLauncher.getRealDisplaySize().y - stashedTaskbarBottomEdge - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
- new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+ new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null,
+ InputDevice.SOURCE_MOUSE);
mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
LauncherInstrumentation.WAIT_TIME_MS);
@@ -317,19 +323,21 @@
"cursor clicking stashed taskbar to go home")) {
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
- null);
+ null, InputDevice.SOURCE_MOUSE);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
- LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER,
+ InputDevice.SOURCE_MOUSE);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_PRESS,
new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
- null);
+ null, InputDevice.SOURCE_MOUSE);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_RELEASE,
new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
- null);
+ null, InputDevice.SOURCE_MOUSE);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP,
new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
- LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER,
+ InputDevice.SOURCE_MOUSE);
return mLauncher.getWorkspace();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index b929293..c58ae16 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -99,23 +99,9 @@
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
private static final int GESTURE_STEP_MS = 16;
- static final Pattern EVENT_TOUCH_DOWN = getTouchEventPatternWithPointerCount("ACTION_DOWN");
- static final Pattern EVENT_TOUCH_UP = getTouchEventPatternWithPointerCount("ACTION_UP");
- private static final Pattern EVENT_TOUCH_CANCEL = getTouchEventPatternWithPointerCount(
- "ACTION_CANCEL");
static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
static final Pattern EVENT_START = Pattern.compile("start:");
- static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
- static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
- static final Pattern EVENT_TOUCH_CANCEL_TIS = getTouchEventPattern(
- "TouchInteractionService.onInputEvent", "ACTION_CANCEL");
- static final Pattern EVENT_HOVER_ENTER_TIS = getTouchEventPatternTIS("ACTION_HOVER_ENTER");
- static final Pattern EVENT_HOVER_EXIT_TIS = getTouchEventPatternTIS("ACTION_HOVER_EXIT");
- static final Pattern EVENT_BUTTON_PRESS_TIS = getTouchEventPatternTIS("ACTION_BUTTON_PRESS");
- static final Pattern EVENT_BUTTON_RELEASE_TIS =
- getTouchEventPatternTIS("ACTION_BUTTON_RELEASE");
-
private static final Pattern EVENT_KEY_BACK_DOWN =
getKeyEventPattern("ACTION_DOWN", "KEYCODE_BACK");
private static final Pattern EVENT_KEY_BACK_UP =
@@ -135,13 +121,10 @@
public enum NavigationModel {ZERO_BUTTON, THREE_BUTTON}
- // Where the gesture happens: outside of Launcher, inside or from inside to outside and
- // whether the gesture recognition triggers pilfer.
+ // Defines whether the gesture recognition triggers pilfer.
public enum GestureScope {
- OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE,
- INSIDE_TO_OUTSIDE_WITHOUT_PILFER,
- INSIDE_TO_OUTSIDE_WITH_KEYCODE, // For gestures that will trigger a keycode from TIS.
- OUTSIDE_WITH_KEYCODE,
+ DONT_EXPECT_PILFER,
+ EXPECT_PILFER,
}
public enum TrackpadGestureType {
@@ -213,38 +196,6 @@
private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
private int mPointerCount = 0;
- private static Pattern getTouchEventPattern(String prefix, String action) {
- return Pattern.compile(
- prefix + ": MotionEvent.*?action=" + action + ".*?id\\[0\\]=0"
- + ".*?toolType\\[0\\]=TOOL_TYPE_FINGER.*?buttonState=0.*?");
- }
-
- private static Pattern getTouchEventPatternWithPointerCount(String prefix, String action,
- int pointerCount) {
- return Pattern.compile(
- prefix + ": MotionEvent.*?action=" + action + ".*?id\\[0\\]=0"
- + ".*?toolType\\[0\\]=TOOL_TYPE_FINGER.*?buttonState=0.*?pointerCount="
- + pointerCount);
- }
-
- private static Pattern getTouchEventPatternWithPointerCount(String action) {
- return getTouchEventPatternWithPointerCount("Touch event", action, 1);
- }
-
- private static Pattern getTouchEventPatternWithPointerCount(String action, int pointerCount) {
- return getTouchEventPatternWithPointerCount("Touch event", action, pointerCount);
- }
-
- private static Pattern getTouchEventPatternTIS(String action) {
- return getTouchEventPatternWithPointerCount("TouchInteractionService.onInputEvent", action,
- 1);
- }
-
- private static Pattern getTouchEventPatternTIS(String action, int pointerCount) {
- return getTouchEventPatternWithPointerCount("TouchInteractionService.onInputEvent", action,
- pointerCount);
- }
-
private static Pattern getKeyEventPattern(String action, String keyCode) {
return Pattern.compile("Key event: KeyEvent.*action=" + action + ".*keyCode=" + keyCode);
}
@@ -992,8 +943,8 @@
GestureScope gestureScope = gestureStartFromLauncher
// Without the navigation bar layer, the gesture scope on tablets remains inside the
// launcher process.
- ? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
- : GestureScope.OUTSIDE_WITH_PILFER;
+ ? (isTablet() ? GestureScope.DONT_EXPECT_PILFER : GestureScope.EXPECT_PILFER)
+ : GestureScope.EXPECT_PILFER;
linearGesture(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
@@ -1065,21 +1016,12 @@
displaySize.x / 2, startY,
displaySize.x / 2, endY,
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL,
- gestureStartFromLauncher ? GestureScope.INSIDE_TO_OUTSIDE
- : GestureScope.OUTSIDE_WITH_PILFER);
+ GestureScope.EXPECT_PILFER);
}
} else {
log("Hierarchy before clicking home:");
dumpViewHierarchy();
action = "clicking home button";
- if (isTablet()) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_UP);
- }
- if (isTrackpadGestureEnabled()) {
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
- }
runToState(
waitForNavigationUiObject("home")::click,
@@ -1109,25 +1051,14 @@
if (getNavigationModel() == NavigationModel.ZERO_BUTTON
|| isThreeFingerTrackpadGesture) {
final Point displaySize = getRealDisplaySize();
- final GestureScope gestureScope =
- launcherVisible ? GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
- : GestureScope.OUTSIDE_WITH_KEYCODE;
// TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
// issue is solved.
int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
- 10, false, gestureScope);
+ 10, false, GestureScope.DONT_EXPECT_PILFER);
} else {
waitForNavigationUiObject("back").click();
- if (isTablet()) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_UP);
- }
- if (isTrackpadGestureEnabled()) {
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
- }
}
if (launcherVisible) {
if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
@@ -1535,15 +1466,17 @@
* animations because in some scenarios there is a playing animations when the click is
* attempted.
*/
- void clickObject(UiObject2 uiObject, GestureScope gestureScope) {
+ void clickObject(UiObject2 uiObject) {
final long clickTime = SystemClock.uptimeMillis();
final Point center = uiObject.getVisibleCenter();
- sendPointer(clickTime, clickTime, MotionEvent.ACTION_DOWN, center, gestureScope);
- sendPointer(clickTime, clickTime, MotionEvent.ACTION_UP, center, gestureScope);
+ sendPointer(clickTime, clickTime, MotionEvent.ACTION_DOWN, center,
+ GestureScope.DONT_EXPECT_PILFER);
+ sendPointer(clickTime, clickTime, MotionEvent.ACTION_UP, center,
+ GestureScope.DONT_EXPECT_PILFER);
}
void clickLauncherObject(UiObject2 object) {
- clickObject(object, GestureScope.INSIDE);
+ clickObject(object);
}
void scrollToLastVisibleRow(
@@ -1636,7 +1569,8 @@
executeAndWaitForLauncherEvent(
() -> linearGesture(
- startX, startY, endX, endY, steps, slowDown, GestureScope.INSIDE),
+ startX, startY, endX, endY, steps, slowDown,
+ GestureScope.DONT_EXPECT_PILFER),
event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
() -> "Didn't receive a scroll end message: " + startX + ", " + startY
+ ", " + endX + ", " + endY,
@@ -1728,11 +1662,11 @@
}
private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
- float x, float y) {
+ float x, float y, int source) {
return MotionEvent.obtain(downTime, eventTime, action, 1,
- new MotionEvent.PointerProperties[] {getPointerProperties(0)},
- new MotionEvent.PointerCoords[] {getPointerCoords(x, y)},
- 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ new MotionEvent.PointerProperties[]{getPointerProperties(0)},
+ new MotionEvent.PointerCoords[]{getPointerCoords(x, y)},
+ 0, 0, 1.0f, 1.0f, 0, 0, source, 0);
}
private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
@@ -1756,113 +1690,50 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- boolean isTrackpadGestureEnabled() {
- return getTestInfo(TestProtocol.REQUEST_IS_TRACKPAD_GESTURE_ENABLED).getBoolean(
+ boolean isGridOnlyOverviewEnabled() {
+ return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW).getBoolean(
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope) {
+ sendPointer(downTime, currentTime, action, point, gestureScope,
+ InputDevice.SOURCE_TOUCHSCREEN);
+ }
+
+ public void sendPointer(long downTime, long currentTime, int action, Point point,
+ GestureScope gestureScope, int source) {
final boolean hasTIS = hasTIS();
int pointerCount = mPointerCount;
boolean isTrackpadGesture = mTrackpadGestureType != TrackpadGestureType.NONE;
- boolean isTwoFingerTrackpadGesture = mTrackpadGestureType == TrackpadGestureType.TWO_FINGER;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
- if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
- && (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
- }
- if (hasTIS && (isTrackpadGestureEnabled()
- || getNavigationModel() != NavigationModel.THREE_BUTTON)) {
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
- }
if (isTrackpadGesture) {
mPointerCount = 1;
pointerCount = mPointerCount;
}
break;
case MotionEvent.ACTION_UP:
- if (hasTIS && gestureScope != GestureScope.INSIDE
- && gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
- && (gestureScope == GestureScope.OUTSIDE_WITH_PILFER
- || gestureScope == GestureScope.INSIDE_TO_OUTSIDE)) {
+ if (hasTIS && gestureScope == GestureScope.EXPECT_PILFER) {
expectEvent(TestProtocol.SEQUENCE_PILFER, EVENT_PILFER_POINTERS);
}
- if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
- && (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
- expectEvent(TestProtocol.SEQUENCE_MAIN,
- gestureScope == GestureScope.INSIDE
- || gestureScope == GestureScope.OUTSIDE_WITHOUT_PILFER
- ? EVENT_TOUCH_UP : EVENT_TOUCH_CANCEL);
- }
- if (hasTIS && (isTrackpadGestureEnabled()
- || getNavigationModel() != NavigationModel.THREE_BUTTON)) {
- expectEvent(TestProtocol.SEQUENCE_TIS,
- gestureScope == GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
- || gestureScope == GestureScope.OUTSIDE_WITH_KEYCODE
- ? EVENT_TOUCH_CANCEL_TIS : EVENT_TOUCH_UP_TIS);
- }
- break;
- case MotionEvent.ACTION_HOVER_ENTER:
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_HOVER_ENTER_TIS);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_HOVER_EXIT_TIS);
break;
case MotionEvent.ACTION_POINTER_DOWN:
mPointerCount++;
- if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
- && (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, getTouchEventPatternWithPointerCount(
- "ACTION_POINTER_DOWN", mPointerCount));
- }
- if (hasTIS && (isTrackpadGestureEnabled()
- || getNavigationModel() != NavigationModel.THREE_BUTTON)) {
- expectEvent(TestProtocol.SEQUENCE_TIS, getTouchEventPatternTIS(
- "ACTION_POINTER_DOWN", mPointerCount));
- }
pointerCount = mPointerCount;
break;
case MotionEvent.ACTION_POINTER_UP:
- if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
- && (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, getTouchEventPatternWithPointerCount(
- "ACTION_POINTER_UP", mPointerCount));
- }
// When the gesture is handled outside, it's cancelled within launcher.
- if (hasTIS && (isTrackpadGestureEnabled()
- || getNavigationModel() != NavigationModel.THREE_BUTTON)) {
- if (gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE) {
- expectEvent(TestProtocol.SEQUENCE_TIS, getTouchEventPatternTIS(
- "ACTION_POINTER_UP", mPointerCount));
- }
- }
mPointerCount--;
break;
- case MotionEvent.ACTION_BUTTON_PRESS:
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_BUTTON_PRESS_TIS);
- break;
- case MotionEvent.ACTION_BUTTON_RELEASE:
- expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_BUTTON_RELEASE_TIS);
- break;
}
final MotionEvent event = isTrackpadGesture
? getTrackpadMotionEvent(
downTime, currentTime, action, point.x, point.y, pointerCount,
mTrackpadGestureType)
- : getMotionEvent(downTime, currentTime, action, point.x, point.y);
+ : getMotionEvent(downTime, currentTime, action, point.x, point.y, source);
if (action == MotionEvent.ACTION_BUTTON_PRESS
|| action == MotionEvent.ACTION_BUTTON_RELEASE) {
event.setActionButton(MotionEvent.BUTTON_PRIMARY);
@@ -1934,11 +1805,12 @@
@NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
final Point targetCenter = target.getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
- sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter, GestureScope.INSIDE);
+ sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
+ GestureScope.DONT_EXPECT_PILFER);
expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
final UiObject2 result = waitForLauncherObject(resName);
sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
- GestureScope.INSIDE);
+ GestureScope.DONT_EXPECT_PILFER);
return result;
}
@@ -2219,9 +2091,9 @@
final long downTime = SystemClock.uptimeMillis();
final Point tapTarget = new Point(x, y);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index 2f7596e..bd2c9c1 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -19,8 +19,6 @@
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
-import com.android.launcher3.testing.shared.TestProtocol;
-
/**
* View containing overview actions
*/
@@ -51,13 +49,6 @@
"clicked screenshot button")) {
UiObject2 closeScreenshot = mLauncher.waitForSystemUiObject(
"screenshot_dismiss_image");
- if (mLauncher.isTrackpadGestureEnabled() || mLauncher.getNavigationModel()
- != LauncherInstrumentation.NavigationModel.THREE_BUTTON) {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS,
- LauncherInstrumentation.EVENT_TOUCH_DOWN_TIS);
- mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS,
- LauncherInstrumentation.EVENT_TOUCH_UP_TIS);
- }
closeScreenshot.click();
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"dismissed screenshot")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 39b93b4..e4cfc52 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -124,7 +124,7 @@
final int centerY = taskBounds.centerY();
mLauncher.executeAndWaitForLauncherEvent(
() -> mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
- LauncherInstrumentation.GestureScope.INSIDE),
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER),
event -> TestProtocol.DISMISS_ANIMATION_ENDS_MESSAGE.equals(event.getClassName()),
() -> "Didn't receive a dismiss animation ends message: " + centerX + ", "
+ centerY, "swiping to dismiss");
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
index 6bc4f21..7f3f61d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Qsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -30,13 +30,21 @@
private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
protected final LauncherInstrumentation mLauncher;
+ private final UiObject2 mContainer;
+ private final String mQsbResName;
- protected Qsb(LauncherInstrumentation launcher) {
+ protected Qsb(LauncherInstrumentation launcher, UiObject2 container, String qsbResName) {
mLauncher = launcher;
+ mContainer = container;
+ mQsbResName = qsbResName;
+ waitForQsbObject();
}
// Waits for the quick search box.
- protected abstract UiObject2 waitForQsbObject();
+ private UiObject2 waitForQsbObject() {
+ return mLauncher.waitForObjectInContainer(mContainer, mQsbResName);
+ }
+
/**
* Launch assistant app by tapping mic icon on qsb.
*/
@@ -79,8 +87,12 @@
mLauncher.waitForIdle();
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"clicked qsb to open search result page")) {
- return new SearchResultFromQsb(mLauncher);
+ return createSearchResult();
}
}
}
+
+ protected SearchResultFromQsb createSearchResult() {
+ return new SearchResultFromQsb(mLauncher);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 80176e9..d02e747 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -32,7 +32,7 @@
// This particular ID change should happen with caution
private static final String SEARCH_CONTAINER_RES_ID = "search_results_list_view";
- private final LauncherInstrumentation mLauncher;
+ protected final LauncherInstrumentation mLauncher;
SearchResultFromQsb(LauncherInstrumentation launcher) {
mLauncher = launcher;
@@ -49,27 +49,33 @@
}
/** Find the app from search results with app name. */
- public Launchable findAppIcon(String appName) {
+ public AppIcon findAppIcon(String appName) {
UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
+ return createAppIcon(icon);
+ }
+
+ protected AppIcon createAppIcon(UiObject2 icon) {
return new AllAppsAppIcon(mLauncher, icon);
}
/** Find the web suggestion from search suggestion's title text */
- public void verifyWebSuggestIsPresent(String text) {
- ArrayList<UiObject2> goldenGateResults =
+ public SearchWebSuggestion findWebSuggestion(String text) {
+ ArrayList<UiObject2> webSuggestions =
new ArrayList<>(mLauncher.waitForObjectsInContainer(
mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
By.clazz(TextView.class)));
- boolean found = false;
- for(UiObject2 uiObject: goldenGateResults) {
+ for (UiObject2 uiObject: webSuggestions) {
String currentString = uiObject.getText();
if (currentString.equals(text)) {
- found = true;
+ return createWebSuggestion(uiObject);
}
}
- if (!found) {
- throw new IllegalStateException("Web suggestion title: " + text + " not found");
- }
+ mLauncher.fail("Web suggestion title: " + text + " not found");
+ return null;
+ }
+
+ protected SearchWebSuggestion createWebSuggestion(UiObject2 webSuggestion) {
+ return new SearchWebSuggestion(mLauncher, webSuggestion);
}
/** Find the total amount of views being displayed and return the size */
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
new file mode 100644
index 0000000..6c6ab05
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on search result page opened from Taskbar qsb.
+ */
+public class SearchResultFromTaskbarQsb extends SearchResultFromQsb {
+
+ SearchResultFromTaskbarQsb(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ public TaskbarAppIcon findAppIcon(String appName) {
+ return (TaskbarAppIcon) super.findAppIcon(appName);
+ }
+
+ @Override
+ protected TaskbarAppIcon createAppIcon(UiObject2 icon) {
+ return new TaskbarAppIcon(mLauncher, icon);
+ }
+
+ @Override
+ public TaskbarSearchWebSuggestion findWebSuggestion(String text) {
+ return (TaskbarSearchWebSuggestion) super.findWebSuggestion(text);
+ }
+
+ @Override
+ protected TaskbarSearchWebSuggestion createWebSuggestion(UiObject2 webSuggestion) {
+ return new TaskbarSearchWebSuggestion(mLauncher, webSuggestion);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchWebSuggestion.java b/tests/tapl/com/android/launcher3/tapl/SearchWebSuggestion.java
new file mode 100644
index 0000000..e4dec98
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SearchWebSuggestion.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.testing.shared.TestProtocol;
+
+import java.util.regex.Pattern;
+
+/**
+ * Operations on a search web suggestion from a qsb.
+ */
+public class SearchWebSuggestion extends Launchable {
+
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
+
+ SearchWebSuggestion(LauncherInstrumentation launcher, UiObject2 object) {
+ super(launcher, object);
+ }
+
+ @Override
+ protected void expectActivityStartEvents() {
+ }
+
+ @Override
+ protected String launchableType() {
+ return "search web suggestion";
+ }
+
+ @Override
+ protected void waitForLongPressConfirmation() {
+ mLauncher.waitForLauncherObject("popup_container");
+ }
+
+ @Override
+ protected void addExpectedEventsForLongClick() {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, getLongClickEvent());
+ }
+
+ protected Pattern getLongClickEvent() {
+ return LONG_CLICK_EVENT;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index 051630e..8671738 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -76,13 +76,13 @@
mLauncher.getRealDisplaySize().x - 1, mLauncher.getRealDisplaySize().y - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, stashTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
LauncherInstrumentation.log("hideTaskbar: sent down");
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
} finally {
mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
@@ -147,9 +147,9 @@
mLauncher.getRealDisplaySize().y - 1);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAllAppsQsb.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAllAppsQsb.java
new file mode 100644
index 0000000..7cecd3e
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAllAppsQsb.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on Taskbar AllApp screen qsb.
+ */
+public class TaskbarAllAppsQsb extends Qsb {
+
+ TaskbarAllAppsQsb(LauncherInstrumentation launcher, UiObject2 allAppsContainer) {
+ super(launcher, allAppsContainer, "search_container_all_apps");
+ }
+
+ @Override
+ public SearchResultFromTaskbarQsb showSearchResult() {
+ return (SearchResultFromTaskbarQsb) super.showSearchResult();
+ }
+
+ @Override
+ protected SearchResultFromTaskbarQsb createSearchResult() {
+ return new SearchResultFromTaskbarQsb(mLauncher);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarSearchWebSuggestion.java b/tests/tapl/com/android/launcher3/tapl/TaskbarSearchWebSuggestion.java
new file mode 100644
index 0000000..cd8ce42
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarSearchWebSuggestion.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+import java.util.regex.Pattern;
+
+/**
+ * Operations on a search web suggestion from the Taskbar qsb.
+ */
+public class TaskbarSearchWebSuggestion extends SearchWebSuggestion implements
+ SplitscreenDragSource {
+
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onTaskbarItemLongClick");
+
+ TaskbarSearchWebSuggestion(LauncherInstrumentation launcher,
+ UiObject2 object) {
+ super(launcher, object);
+ }
+
+ @Override
+ protected Pattern getLongClickEvent() {
+ return LONG_CLICK_EVENT;
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 8604988..6f6f292 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -104,7 +104,8 @@
windowCornerRadius,
startY - swipeHeight - mLauncher.getTouchSlop(),
12,
- ALL_APPS_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
+ ALL_APPS_STATE_ORDINAL,
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"swiped to all apps")) {
@@ -386,7 +387,7 @@
Until.hasObject(installerAlert), LauncherInstrumentation.WAIT_TIME_MS));
final UiObject2 ok = device.findObject(By.text("OK"));
assertNotNull("OK button is not shown", ok);
- launcher.clickObject(ok, LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+ launcher.clickObject(ok);
assertTrue("Uninstall alert is not dismissed after clicking OK", device.wait(
Until.gone(installerAlert), LauncherInstrumentation.WAIT_TIME_MS));
@@ -453,7 +454,7 @@
launcher.runToState(
() -> launcher.sendPointer(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
- LauncherInstrumentation.GestureScope.INSIDE),
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER),
NORMAL_STATE_ORDINAL,
"sending UP event");
if (expectedEvents != null) {
@@ -542,7 +543,7 @@
executeAndWaitForPageScroll(launcher,
() -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
true, downTime, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE));
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER));
targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1);
dragStart = screenEdge;
}
@@ -551,7 +552,7 @@
// we just have to put move the icon to the destination and drop it
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
downTime, SystemClock.uptimeMillis(), false,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
}
@@ -584,7 +585,7 @@
// we just have to put move the icon to the destination and drop it
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
downTime, SystemClock.uptimeMillis(), false,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
}
@@ -621,7 +622,7 @@
executeAndWaitForPageScroll(launcher,
() -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
true, downTime, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE));
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER));
currentPage = Workspace.geCurrentPage(launcher);
currentPosition = screenEdge;
}
@@ -650,7 +651,7 @@
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, true,
downTime, SystemClock.uptimeMillis(), false,
- LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}