Merge "Fix pageindicator for RTL mode" 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 ecb8365..f99155f 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -188,12 +188,27 @@
return response;
}
+ case TestProtocol.REQUEST_REINITIALIZE_DATA: {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ MODEL_EXECUTOR.execute(() -> {
+ LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
+ model.getModelDbController().createEmptyDB();
+ MAIN_EXECUTOR.execute(model::forceReload);
+ });
+ return response;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
case TestProtocol.REQUEST_CLEAR_DATA: {
final long identity = Binder.clearCallingIdentity();
try {
MODEL_EXECUTOR.execute(() -> {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
model.getModelDbController().createEmptyDB();
+ model.getModelDbController().clearEmptyDbFlag();
MAIN_EXECUTOR.execute(model::forceReload);
});
return response;
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 225b4cd..672440f 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -13,155 +13,163 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:theme="@style/GestureTutorialActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
- android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
- android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
- android:background="?androidprv:attr/materialColorSurfaceContainer">
+ android:background="?androidprv:attr/materialColorSurfaceContainer"
+ android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_home_button"
- android:layout_width="0dp"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
- android:layout_marginBottom="24dp"
- android:background="@drawable/gesture_tutorial_menu_home_button_background"
- android:clipToOutline="true"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
+ android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
+ android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
+ android:clipToPadding="false">
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/guideline"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_back_button">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_home_step_shape"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
- android:id="@+id/gesture_tutorial_menu_home_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/home_gesture_tutorial_title"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_home_button"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+ android:layout_marginBottom="24dp"
+ android:background="@drawable/gesture_tutorial_menu_home_button_background"
+ android:clipToOutline="true"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_back_button">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_home_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
+ android:id="@+id/gesture_tutorial_menu_home_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/home_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_back_button"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+ android:layout_marginBottom="24dp"
+ android:background="@drawable/gesture_tutorial_menu_back_button_background"
+ android:clipToOutline="true"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
+ app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_home_button"
+ app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_overview_button">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_back_step_shape"
+ android:layout_marginBottom="@dimen/gesture_tutorial_menu_back_shape_bottom_margin"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
+ android:id="@+id/gesture_tutorial_menu_back_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/back_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_overview_button"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginBottom="24dp"
+ android:background="@drawable/gesture_tutorial_menu_overview_button_background"
+ android:clipToOutline="true"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
+ app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_back_button"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_overview_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
+ android:id="@+id/gesture_tutorial_menu_overview_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/overview_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+
+ app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
+
+ <Button
+ style="@style/TextAppearance.GestureTutorial.ButtonLabel"
+ android:id="@+id/gesture_tutorial_menu_done_button"
+ android:layout_width="wrap_content"
+ android:layout_height="40dp"
+ android:layout_marginVertical="16dp"
+ android:text="@string/gesture_tutorial_action_button_label"
+ android:background="@drawable/gesture_tutorial_action_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:stateListAnimator="@null"
+
+ app:layout_constraintTop_toBottomOf="@id/guideline"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_back_button"
- android:layout_width="0dp"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
- android:layout_marginBottom="24dp"
- android:background="@drawable/gesture_tutorial_menu_back_button_background"
- android:clipToOutline="true"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/guideline"
- app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_home_button"
- app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_overview_button">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_back_step_shape"
- android:layout_marginBottom="@dimen/gesture_tutorial_menu_back_shape_bottom_margin"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
- android:id="@+id/gesture_tutorial_menu_back_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/back_gesture_tutorial_title"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_overview_button"
- android:layout_width="0dp"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:layout_marginBottom="24dp"
- android:background="@drawable/gesture_tutorial_menu_overview_button_background"
- android:clipToOutline="true"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/guideline"
- app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_back_button"
- app:layout_constraintEnd_toEndOf="parent">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_overview_step_shape"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
- android:id="@+id/gesture_tutorial_menu_overview_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/overview_gesture_tutorial_title"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/guideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
-
- app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
-
- <Button
- style="@style/TextAppearance.GestureTutorial.ButtonLabel"
- android:id="@+id/gesture_tutorial_menu_done_button"
- android:layout_width="wrap_content"
- android:layout_height="40dp"
- android:layout_marginVertical="16dp"
- android:text="@string/gesture_tutorial_action_button_label"
- android:background="@drawable/gesture_tutorial_action_button_background"
- android:backgroundTint="?androidprv:attr/materialColorPrimary"
- android:stateListAnimator="@null"
-
- app:layout_constraintTop_toBottomOf="@id/guideline"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 2c312a7..685a151 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -41,6 +41,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
+ android:fitsSystemWindows="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -95,7 +96,6 @@
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="24dp"
android:text="@string/allset_hint"
android:textSize="@dimen/allset_page_swipe_up_text_size"
android:gravity="center_horizontal"
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index cf78b1b..c8ee6e9 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -13,154 +13,161 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:theme="@style/GestureTutorialActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
- android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
- android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
android:background="?androidprv:attr/materialColorSurfaceContainer"
- android:clipToPadding="false">
+ android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_home_button"
android:layout_width="match_parent"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:background="@drawable/gesture_tutorial_menu_home_button_background"
- android:clipToOutline="true"
- app:layout_constraintVertical_chainStyle="packed"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/gesture_tutorial_menu_padding_top"
+ android:paddingBottom="@dimen/gesture_tutorial_menu_padding_bottom"
+ android:paddingHorizontal="@dimen/gesture_tutorial_menu_padding_horizontal"
+ android:clipToPadding="false">
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_back_button"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_home_step_shape"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
- android:id="@+id/gesture_tutorial_menu_home_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/home_gesture_tutorial_title"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_home_button"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:background="@drawable/gesture_tutorial_menu_home_button_background"
+ android:clipToOutline="true"
+ app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_back_button"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_home_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Home"
+ android:id="@+id/gesture_tutorial_menu_home_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/home_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_back_button"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
+ android:background="@drawable/gesture_tutorial_menu_back_button_background"
+ android:clipToOutline="true"
+
+ app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_home_button"
+ app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_overview_button"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_back_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
+ android:id="@+id/gesture_tutorial_menu_back_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/back_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/gesture_tutorial_menu_overview_button"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
+ android:background="@drawable/gesture_tutorial_menu_overview_button_background"
+ android:clipToOutline="true"
+
+ app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_back_button"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_overview_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
+
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
+ android:id="@+id/gesture_tutorial_menu_overview_button_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/overview_gesture_tutorial_title"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+
+ app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
+
+ <Button
+ style="@style/TextAppearance.GestureTutorial.ButtonLabel"
+ android:id="@+id/gesture_tutorial_menu_done_button"
+ android:layout_width="wrap_content"
+ android:layout_height="40dp"
+ android:layout_marginVertical="16dp"
+ android:text="@string/gesture_tutorial_action_button_label"
+ android:background="@drawable/gesture_tutorial_action_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:stateListAnimator="@null"
+
+ app:layout_constraintTop_toBottomOf="@id/guideline"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_back_button"
- android:layout_width="match_parent"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
- android:background="@drawable/gesture_tutorial_menu_back_button_background"
- android:clipToOutline="true"
-
- app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_home_button"
- app:layout_constraintBottom_toTopOf="@id/gesture_tutorial_menu_overview_button"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_back_step_shape"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Back"
- android:id="@+id/gesture_tutorial_menu_back_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/back_gesture_tutorial_title"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/gesture_tutorial_menu_overview_button"
- android:layout_width="match_parent"
- android:layout_height="@dimen/gesture_tutorial_menu_button_height"
- android:layout_marginTop="@dimen/gesture_tutorial_menu_button_spacing"
- android:background="@drawable/gesture_tutorial_menu_overview_button_background"
- android:clipToOutline="true"
-
- app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_menu_back_button"
- app:layout_constraintBottom_toTopOf="@id/guideline"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_overview_step_shape"
- android:scaleType="fitXY"
- android:adjustViewBounds="true"
-
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- <TextView
- style="@style/TextAppearance.GestureTutorial.MenuButton.Overview"
- android:id="@+id/gesture_tutorial_menu_overview_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/overview_gesture_tutorial_title"
-
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/guideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
-
- app:layout_constraintGuide_end="@dimen/gesture_tutorial_menu_done_button_spacing"/>
-
- <Button
- style="@style/TextAppearance.GestureTutorial.ButtonLabel"
- android:id="@+id/gesture_tutorial_menu_done_button"
- android:layout_width="wrap_content"
- android:layout_height="40dp"
- android:layout_marginVertical="16dp"
- android:text="@string/gesture_tutorial_action_button_label"
- android:background="@drawable/gesture_tutorial_action_button_background"
- android:backgroundTint="?androidprv:attr/materialColorPrimary"
- android:stateListAnimator="@null"
-
- app:layout_constraintTop_toBottomOf="@id/guideline"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index bf4b811..7a6d16a 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -44,7 +44,6 @@
android:layout_height="@dimen/bubblebar_size"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/transient_taskbar_bottom_margin"
- android:layout_marginBottom="@dimen/transient_taskbar_bottom_margin"
android:paddingEnd="@dimen/taskbar_icon_spacing"
android:paddingStart="@dimen/taskbar_icon_spacing"
android:visibility="gone"
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 506d5a7..c8f19f1 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -86,7 +86,7 @@
<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>
+ <string name="allset_hint" msgid="459504134589971527">"Плъзнете пръст нагоре, за да отворите началния екран"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Докоснете бутона „Начало“, за да преминете към началния екран"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Можете да започнете да използвате <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"устройството"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 193476e..0497fe4 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -88,7 +88,7 @@
<string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
<string name="allset_hint" msgid="459504134589971527">"Prevucite prema gore da odete na početni ekran"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Sve je spremno da počnete koristiti <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete koristiti <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigiranja sistemom"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 4766523..bfce9a1 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -84,7 +84,7 @@
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Indstillinger"</string>
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"Prøv igen"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sådan!"</string>
- <string name="gesture_tutorial_step" msgid="1279786122817620968">"Selvstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vejledning <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Alt er parat!"</string>
<string name="allset_hint" msgid="459504134589971527">"Stryg opad for at gå til startsiden"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tryk på knappen Hjem for at gå til din startskærm"</string>
@@ -97,7 +97,7 @@
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
- <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe selvstudiet for navigation over?"</string>
+ <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe vejledningen for navigation over?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finde dette senere i appen <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuller"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Spring over"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 98d662b..35ab3db 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -23,7 +23,7 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"Cerrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recientes"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Se cerró la tarea"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 9293207..b876cf4 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -58,7 +58,7 @@
<string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Egin atzera"</string>
<string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Pasatu hatza pantailaren eskuineko edo ezkerreko ertzetik erdialdera"</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula"</string>
- <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ziurtatu hatza jaso aurretik ez zarela gelditzen"</string>
+ <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ziurtatu ez duzula mugimendua gelditzen askatu arte"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Ziurtatu hatza zuzen pasatzen duzula gora"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Ikasi duzu hasierako pantailara joateko keinua. Jarraian, ikasi atzera egiten."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Ikasi duzu hasierako pantailara joateko keinua"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 2b58605..6affb00 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -88,7 +88,7 @@
<string name="allset_title" msgid="5021126669778966707">"हो गया!"</string>
<string name="allset_hint" msgid="459504134589971527">"होम पेज पर जाने के लिए, ऊपर की ओर स्वाइप करें"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"होम स्क्रीन पर जाने के लिए, होम बटन पर टैप करें"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"अब <xliff:g id="DEVICE">%1$s</xliff:g> इस्तेमाल के लिए तैयार हैं"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"अब <xliff:g id="DEVICE">%1$s</xliff:g> इस्तेमाल के लिए तैयार है"</string>
<string name="default_device_name" msgid="6660656727127422487">"डिवाइस"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टम नेविगेशन सेटिंग"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index c155b38..0da707a 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -87,7 +87,7 @@
<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>
- <string name="allset_button_hint" msgid="2395219947744706291">"ನಿಮ್ಮ ಮುಖಪುಟದ ಪರದೆಗೆ ಹೋಗಲು ಮುಖಪುಟ ಬಟನ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="allset_button_hint" msgid="2395219947744706291">"ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಲು ಹೋಮ್ ಬಟನ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ಧರಾಗಿರುವಿರಿ"</string>
<string name="default_device_name" msgid="6660656727127422487">"ಸಾಧನ"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಶನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</annotation></string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index a62a24c..9ae478b 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -86,7 +86,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bagus!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Siap!"</string>
- <string name="allset_hint" msgid="459504134589971527">"Leret ke atas untuk mencapai laman utama"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Leret ke atas untuk ke laman utama"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Ketik butang skrin utama untuk pergi ke skrin utama anda"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Anda sudah sedia untuk mula menggunakan <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
<string name="default_device_name" msgid="6660656727127422487">"peranti"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 203b149..52777c2 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -86,7 +86,7 @@
<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>
+ <string name="allset_hint" msgid="459504134589971527">"ହୋମକୁ ଯିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ହୋମ ବଟନରେ ଟାପ କରନ୍ତୁ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ଆପଣ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g> ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string>
<string name="default_device_name" msgid="6660656727127422487">"ଡିଭାଇସ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 40aba40..5f609b2 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -55,7 +55,7 @@
<string name="back_gesture_intro_title" msgid="19551256430224428">"Przesuń palcem, aby przejść wstecz"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Aby wrócić do poprzedniego ekranu, przesuń palcem od lewej lub prawej krawędzi do środka ekranu."</string>
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Aby wrócić do poprzedniego ekranu, przesuń 2 palcami od lewej lub prawej krawędzi do środka ekranu."</string>
- <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Przejdź wstecz"</string>
+ <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Przejście wstecz"</string>
<string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Przesuń palcem od lewej lub prawej krawędzi do środka ekranu"</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Pamiętaj, aby przed podniesieniem palca nie było przerwy"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index f80153c..ddebce9 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -86,7 +86,7 @@
<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>
+ <string name="allset_hint" msgid="459504134589971527">"వర్చువల్ హోమ్కు వెళ్లడానికి పైకి స్వైప్ చేయండి"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"మీ మొదటి స్క్రీన్కు వెళ్లడానికి హోమ్ బటన్ను ట్యాప్ చేయండి"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"మీరు ఇప్పుడు మీ <xliff:g id="DEVICE">%1$s</xliff:g>ను ఉపయోగించడం ప్రారంభించవచ్చు"</string>
<string name="default_device_name" msgid="6660656727127422487">"పరికరం"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b5798ba..d51f46a 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -86,7 +86,7 @@
<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>
+ <string name="allset_hint" msgid="459504134589971527">"向上滑动可前往主屏幕"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"点按主屏幕按钮即可前往主屏幕"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"您可以开始使用<xliff:g id="DEVICE">%1$s</xliff:g>了"</string>
<string name="default_device_name" msgid="6660656727127422487">"设备"</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2b578c3..153c1ac 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -1210,14 +1211,15 @@
return false;
}
- private boolean hasMultipleTargetsWithMode(RemoteAnimationTarget[] targets, int mode) {
+ private boolean shouldPlayFallbackClosingAnimation(RemoteAnimationTarget[] targets) {
int numTargets = 0;
for (RemoteAnimationTarget target : targets) {
- if (target.mode == mode) {
+ if (target.mode == MODE_CLOSING) {
numTargets++;
- }
- if (numTargets > 1) {
- return true;
+ if (numTargets > 1 || target.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_MULTI_WINDOW) {
+ return true;
+ }
}
}
return false;
@@ -1604,7 +1606,7 @@
boolean playFallBackAnimation = (launcherView == null
&& launcherIsForceInvisibleOrOpening)
|| mLauncher.getWorkspace().isOverlayShown()
- || hasMultipleTargetsWithMode(appTargets, MODE_CLOSING);
+ || shouldPlayFallbackClosingAnimation(appTargets);
boolean playWorkspaceReveal = true;
boolean skipAllAppsScale = false;
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 34316db..4f889c0 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,6 +16,8 @@
package com.android.launcher3.appprediction;
+import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
+
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
@@ -36,13 +38,11 @@
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusIndicatorHelper;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -65,7 +65,6 @@
private FloatingHeaderView mParent;
private boolean mPredictionsEnabled = false;
- private OnLongClickListener mOnIconLongClickListener = ItemLongClickListener.INSTANCE_ALL_APPS;
public PredictionRowView(@NonNull Context context) {
this(context, null);
@@ -106,22 +105,12 @@
mActivityContext.getAppsView().getAppsStore().unregisterIconContainer(this);
}
}
-
- // Set the predicted row in All Apps' text line to 1.
- if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()
- || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) {
- for (int i = 0; i < getChildCount(); i++) {
- BubbleTextView icon = (BubbleTextView) getChildAt(i);
- icon.setMaxLines(1);
- }
- }
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
MeasureSpec.EXACTLY));
- updateVisibility();
}
@Override
@@ -185,15 +174,6 @@
applyPredictionApps();
}
- /**
- * Sets the long click listener for predictions for any future predictions.
- *
- * Existing predictions in the container are not updated with this new callback.
- */
- public void setOnIconLongClickListener(OnLongClickListener onIconLongClickListener) {
- mOnIconLongClickListener = onIconLongClickListener;
- }
-
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mNumPredictedAppsPerRow = dp.numShownAllAppsColumns;
@@ -211,7 +191,7 @@
BubbleTextView icon = (BubbleTextView) inflater.inflate(
R.layout.all_apps_icon, this, false);
icon.setOnClickListener(mActivityContext.getItemOnClickListener());
- icon.setOnLongClickListener(mOnIconLongClickListener);
+ icon.setOnLongClickListener(mActivityContext.getAllAppsItemLongClickListener());
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mFocusHelper);
@@ -231,6 +211,7 @@
icon.reset();
if (predictionCount > i) {
icon.setVisibility(View.VISIBLE);
+ icon.setDisplay(DISPLAY_PREDICTION_ROW);
icon.applyFromWorkspaceItem(mPredictedApps.get(i));
} else {
icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
diff --git a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
index 4d7cc85..6d90b035 100644
--- a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
+++ b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
@@ -24,6 +24,8 @@
import android.os.Bundle;
import android.util.Log;
+import com.android.launcher3.util.StartActivityParams;
+
public class ProxyActivityStarter extends Activity {
private static final String TAG = "ProxyActivityStarter";
diff --git a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
index 8720bd8..b982688 100644
--- a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
+++ b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
@@ -18,9 +18,7 @@
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import android.content.Context;
-import android.view.View;
-import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.appprediction.AppsDividerView;
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.model.BgDataModel;
@@ -56,12 +54,4 @@
.findFixedRowByType(PredictionRowView.class)
.setPredictedApps(item.items);
}
-
- @Override
- public void setLongClickListener(ActivityAllAppsContainerView<?> appsView,
- View.OnLongClickListener onIconLongClickListener) {
- appsView.getFloatingHeaderView()
- .findFixedRowByType(PredictionRowView.class)
- .setOnIconLongClickListener(onIconLongClickListener);
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 35b9957..4e834ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -50,6 +50,7 @@
import com.android.quickstep.views.RecentsView;
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* A data source which integrates with a Launcher instance
@@ -105,6 +106,10 @@
// Restore the in-app display progress from before Taskbar was recreated.
float[] prevProgresses = mControllers.getSharedState().inAppDisplayProgressMultiPropValues;
+ // Make a copy of the previous progress to set since updating the multiprop will update
+ // the property which also calls onInAppDisplayProgressChanged() which writes the current
+ // values into the shared state
+ prevProgresses = Arrays.copyOf(prevProgresses, prevProgresses.length);
for (int i = 0; i < prevProgresses.length; i++) {
mTaskbarInAppDisplayProgressMultiProp.get(i).setValue(prevProgresses[i]);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 10ae97b..1705f11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -88,6 +88,7 @@
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
import com.android.launcher3.util.DimensionUtils;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.TouchController;
@@ -197,6 +198,7 @@
this::onComputeInsetsForSeparateWindow;
private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
private ImageView mRecentsButton;
+ private DisplayController mDisplayController;
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
mContext = context;
@@ -226,6 +228,8 @@
TaskbarManager.isPhoneMode(deviceProfile));
mNavButtonsView.getLayoutParams().height = p.y;
+ mDisplayController = DisplayController.INSTANCE.get(mContext);
+
mIsImeRenderingNavButtons =
InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar();
if (!mIsImeRenderingNavButtons) {
@@ -727,14 +731,10 @@
boolean isInKidsMode = mContext.isNavBarKidsModeActive();
if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
- if (!isThreeButtonNav) {
- return;
- }
-
NavButtonLayoutter navButtonLayoutter =
NavButtonLayoutFactory.Companion.getUiLayoutter(
dp, mNavButtonsView, res, isInKidsMode, isInSetup, isThreeButtonNav,
- TaskbarManager.isPhoneMode(dp));
+ TaskbarManager.isPhoneMode(dp), mDisplayController.getInfo().rotation);
navButtonLayoutter.layoutButtons(dp, isContextualButtonShowing());
return;
}
@@ -927,6 +927,15 @@
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
}
+ /**
+ * Called whenever a new ui controller is set, and should update anything that depends on the
+ * ui controller.
+ */
+ public void onUiControllerChanged() {
+ updateNavButtonInAppDisplayProgressForSysui();
+ updateNavButtonTranslationY();
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "NavbarButtonsViewController:");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 43aceec..42cb290 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -55,6 +55,7 @@
import android.view.Display;
import android.view.Gravity;
import android.view.RoundedCorner;
+import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -295,8 +296,7 @@
public void init(@NonNull TaskbarSharedState sharedState) {
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
- mWindowLayoutParams =
- createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL, WINDOW_TITLE);
+ mWindowLayoutParams = createAllWindowParams();
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
@@ -360,11 +360,6 @@
* @param title The window title to pass to the created WindowManager.LayoutParams.
*/
public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type, String title) {
- DeviceProfile deviceProfile = getDeviceProfile();
- // Taskbar is on the logical bottom of the screen
- boolean isVerticalBarLayout = TaskbarManager.isPhoneButtonNavMode(this) &&
- deviceProfile.isLandscape;
-
int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
@@ -373,17 +368,14 @@
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
- isVerticalBarLayout ? mLastRequestedNonFullscreenHeight : MATCH_PARENT,
- isVerticalBarLayout ? MATCH_PARENT : mLastRequestedNonFullscreenHeight,
+ MATCH_PARENT,
+ mLastRequestedNonFullscreenHeight,
type,
windowFlags,
PixelFormat.TRANSLUCENT);
windowLayoutParams.setTitle(title);
windowLayoutParams.packageName = getPackageName();
- windowLayoutParams.gravity = !isVerticalBarLayout ?
- Gravity.BOTTOM :
- Gravity.END; // TODO(b/230394142): seascape
-
+ windowLayoutParams.gravity = Gravity.BOTTOM;
windowLayoutParams.setFitInsetsTypes(0);
windowLayoutParams.receiveInsetsIgnoringZOrder = true;
windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
@@ -394,6 +386,64 @@
TaskbarManager.isPhoneMode(mDeviceProfile)
? R.string.taskbar_phone_a11y_title
: R.string.taskbar_a11y_title);
+
+ return windowLayoutParams;
+ }
+
+ /**
+ * Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
+ * for taskbar showing as navigation bar
+ */
+ private WindowManager.LayoutParams createAllWindowParams() {
+ WindowManager.LayoutParams windowLayoutParams =
+ createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL,
+ TaskbarActivityContext.WINDOW_TITLE);
+ boolean isPhoneNavMode = TaskbarManager.isPhoneButtonNavMode(this);
+ if (!isPhoneNavMode) {
+ return windowLayoutParams;
+ }
+
+ // Provide WM layout params for all rotations to cache, see NavigationBar#getBarLayoutParams
+ int width = WindowManager.LayoutParams.MATCH_PARENT;
+ int height = WindowManager.LayoutParams.MATCH_PARENT;
+ int gravity = Gravity.BOTTOM;
+ windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
+ for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ WindowManager.LayoutParams lp =
+ createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL,
+ TaskbarActivityContext.WINDOW_TITLE);
+ switch (rot) {
+ case Surface.ROTATION_0, Surface.ROTATION_180 -> {
+ // Defaults are fine
+ width = WindowManager.LayoutParams.MATCH_PARENT;
+ height = mLastRequestedNonFullscreenHeight;
+ gravity = Gravity.BOTTOM;
+ }
+ case Surface.ROTATION_90 -> {
+ width = mLastRequestedNonFullscreenHeight;
+ height = WindowManager.LayoutParams.MATCH_PARENT;
+ gravity = Gravity.END;
+ }
+ case Surface.ROTATION_270 -> {
+ width = mLastRequestedNonFullscreenHeight;
+ height = WindowManager.LayoutParams.MATCH_PARENT;
+ gravity = Gravity.START;
+ }
+
+ }
+ lp.width = width;
+ lp.height = height;
+ lp.gravity = gravity;
+ windowLayoutParams.paramsForRotation[rot] = lp;
+ }
+
+ // Override current layout params
+ WindowManager.LayoutParams currentParams =
+ windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
+ windowLayoutParams.width = currentParams.width;
+ windowLayoutParams.height = currentParams.height;
+ windowLayoutParams.gravity = currentParams.gravity;
+
return windowLayoutParams;
}
@@ -593,9 +643,7 @@
* Sets a new data-source for this taskbar instance
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
- mControllers.uiController.onDestroy();
- mControllers.uiController = uiController;
- mControllers.uiController.init(mControllers);
+ mControllers.setUiController(uiController);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 3cd151d..d82f501 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -196,6 +196,19 @@
mPostInitCallbacks.clear();
}
+ /**
+ * Sets the ui controller.
+ */
+ public void setUiController(@NonNull TaskbarUIController newUiController) {
+ uiController.onDestroy();
+ uiController = newUiController;
+ uiController.init(this);
+ uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags);
+
+ // Notify that the ui controller has changed
+ navbarButtonsViewController.onUiControllerChanged();
+ }
+
@Nullable
public TaskbarSharedState getSharedState() {
// This should only be null if called before init() and after destroy().
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 07cd8ff..68ea475 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -19,6 +19,7 @@
import android.graphics.Region
import android.os.Binder
import android.os.IBinder
+import android.view.Gravity
import android.view.InsetsFrameProvider
import android.view.InsetsFrameProvider.SOURCE_DISPLAY
import android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER
@@ -109,23 +110,21 @@
.setSource(SOURCE_DISPLAY)
)
} else {
- windowLayoutParams.providedInsets =
- arrayOf(
- InsetsFrameProvider(insetsOwner, 0, navigationBars())
- .setFlags(
- insetsRoundedCornerFlag,
- (FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER)
- ),
- InsetsFrameProvider(insetsOwner, 0, tappableElement()),
- InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures())
- )
+ windowLayoutParams.providedInsets = getButtonNavInsets(insetsRoundedCornerFlag)
+ if (windowLayoutParams.paramsForRotation != null) {
+ for (layoutParams in windowLayoutParams.paramsForRotation) {
+ layoutParams.providedInsets = getButtonNavInsets(insetsRoundedCornerFlag)
+ }
+ }
}
val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
val bubblesTouchableHeight =
- if (controllers.bubbleControllers.isPresent)
+ if (controllers.bubbleControllers.isPresent) {
controllers.bubbleControllers.get().bubbleStashController.touchableHeight
- else 0
+ } else {
+ 0
+ }
val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight)
if (
@@ -148,75 +147,99 @@
windowLayoutParams.height
)
}
- val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
- val res = context.resources
+
+ val gravity = windowLayoutParams.gravity
for (provider in windowLayoutParams.providedInsets) {
- if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
- provider.insetsSize = getInsetsByNavMode(contentHeight)
- } else if (provider.type == tappableElement()) {
- provider.insetsSize = getInsetsByNavMode(tappableHeight)
- } else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
- provider.insetsSize =
- Insets.of(
- gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res),
- 0,
- 0,
- 0
- )
- } else if (provider.type == systemGestures() && provider.index == INDEX_RIGHT) {
- provider.insetsSize =
- Insets.of(
- 0,
- 0,
- gestureNavSettingsObserver.getRightSensitivityForCallingUser(res),
- 0
- )
- }
+ setProviderInsets(provider, gravity)
}
- val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
- val insetsSizeOverride =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
- )
- // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
- val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0)
- val insetsSizeOverrideForGestureNavTappableElement =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
- InsetsFrameProvider.InsetsSizeOverride(
- TYPE_VOICE_INTERACTION,
- visInsetsSizeForGestureNavTappableElement
- ),
- )
- for (provider in windowLayoutParams.providedInsets) {
- if (context.isGestureNav && provider.type == tappableElement()) {
- provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
- } else if (provider.type != systemGestures()) {
- // We only override insets at the bottom of the screen
- provider.insetsSizeOverrides = insetsSizeOverride
+ if (windowLayoutParams.paramsForRotation != null) {
+ // Add insets for navbar rotated params
+ for (layoutParams in windowLayoutParams.paramsForRotation) {
+ for (provider in layoutParams.providedInsets) {
+ setProviderInsets(provider, layoutParams.gravity)
+ }
}
}
context.notifyUpdateLayoutParams()
}
+ private fun getButtonNavInsets(insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
+ return arrayOf(
+ InsetsFrameProvider(insetsOwner, 0, navigationBars())
+ .setFlags(
+ insetsRoundedCornerFlag,
+ (FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER)
+ ),
+ InsetsFrameProvider(insetsOwner, 0, tappableElement()),
+ InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()))
+ }
+
+ private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int) {
+ val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
+ val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ val res = context.resources
+ if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
+ provider.insetsSize = getInsetsByNavMode(contentHeight, gravity)
+ } else if (provider.type == tappableElement()) {
+ provider.insetsSize = getInsetsByNavMode(tappableHeight, gravity)
+ } else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
+ provider.insetsSize =
+ Insets.of(
+ gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res),
+ 0,
+ 0,
+ 0
+ )
+ } else if (provider.type == systemGestures() && provider.index == INDEX_RIGHT) {
+ provider.insetsSize =
+ Insets.of(
+ 0,
+ 0,
+ gestureNavSettingsObserver.getRightSensitivityForCallingUser(res),
+ 0
+ )
+ }
+
+ val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme, gravity)
+ val insetsSizeOverride =
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ )
+ // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
+ val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0, gravity)
+ val insetsSizeOverrideForGestureNavTappableElement =
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ InsetsFrameProvider.InsetsSizeOverride(
+ TYPE_VOICE_INTERACTION,
+ visInsetsSizeForGestureNavTappableElement
+ ),
+ )
+ if (context.isGestureNav && provider.type == tappableElement()) {
+ provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
+ } else if (provider.type != systemGestures()) {
+ // We only override insets at the bottom of the screen
+ provider.insetsSizeOverrides = insetsSizeOverride
+ }
+ }
+
/**
- * @return [Insets] where the [bottomInset] is either used as a bottom inset or
- *
- * ```
- * right/left inset if using 3 button nav
- * ```
+ * @return [Insets] where the [inset] is either used as a bottom inset or
+ * right/left inset if using 3 button nav
*/
- private fun getInsetsByNavMode(bottomInset: Int): Insets {
- val devicePortrait = !context.deviceProfile.isLandscape
- if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
+ private fun getInsetsByNavMode(inset: Int, gravity: Int): Insets {
+ if ((gravity and Gravity.BOTTOM) != 0) {
// Taskbar or portrait phone mode
- return Insets.of(0, 0, 0, bottomInset)
+ return Insets.of(0, 0, 0, inset)
}
// TODO(b/230394142): seascape
- return Insets.of(0, 0, bottomInset, 0)
+ val isSeascape = (gravity and Gravity.START) != 0
+ val leftInset = if (isSeascape) inset else 0
+ val rightInset = if (isSeascape) 0 else inset
+ return Insets.of(leftInset , 0, rightInset, 0)
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 0b822fb..4ad3d5a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -202,6 +202,11 @@
public void onStateTransitionComplete(LauncherState finalState) {
mLauncherState = finalState;
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
+ // TODO(b/279514548) Cleans up bad state that can occur when user interacts with
+ // taskbar on top of transparent activity.
+ if (finalState == LauncherState.NORMAL && mLauncher.isResumed()) {
+ updateStateForFlag(FLAG_RESUMED, true);
+ }
applyState();
boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 8f3898f..1809d40 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -206,7 +206,14 @@
destroyExistingTaskbar();
} else {
if (dp != null && isTaskbarPresent(dp)) {
- mTaskbarActivityContext.updateDeviceProfile(dp);
+ if (FLAG_HIDE_NAVBAR_WINDOW) {
+ // Re-initialize for screen size change? Should this be done
+ // by looking at screen-size change flag in configDiff in the
+ // block above?
+ recreateTaskbar();
+ } else {
+ mTaskbarActivityContext.updateDeviceProfile(dp);
+ }
}
mTaskbarActivityContext.onConfigurationChanged(configDiff);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 5eec726..512b77a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -177,7 +177,6 @@
systemShortcuts);
}
- icon.clearAccessibilityFocus();
container.addOnAttachStateChangeListener(
new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 29f4f38..1b45404 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.anim.AnimatedFloat.VALUE;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
+import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
@@ -171,6 +172,13 @@
.getTaskbarNavButtonTranslationYForInAppDisplay();
mActivity.addOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
+
+ if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
+ // This gets modified in NavbarButtonsViewController, but the initial value it reads
+ // may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
+ mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
+ .animateToValue(isPhoneButtonNavMode(mActivity) ? 0 : 1).start();
+ }
}
/**
@@ -444,8 +452,13 @@
* Creates an animation for aligning the Taskbar icons with the provided Launcher device profile
*/
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
- mOnControllerPreCreateCallback.run();
PendingAnimation setter = new PendingAnimation(100);
+ if (TaskbarManager.isPhoneButtonNavMode(mActivity)) {
+ // No animation for icons in small-screen
+ return setter.createPlaybackController();
+ }
+
+ mOnControllerPreCreateCallback.run();
DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.taskbarIconSize;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 02d9d95..cf0b36a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -112,9 +112,6 @@
/** Updates the current search suggestions. */
public void setZeroStateSearchSuggestions(List<ItemInfo> zeroStateSearchSuggestions) {
mZeroStateSearchSuggestions = zeroStateSearchSuggestions;
- if (mSearchSessionController != null) {
- mSearchSessionController.setZeroStateSearchSuggestions(zeroStateSearchSuggestions);
- }
}
/** Updates the current notification dots. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 01342af..a851734 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -20,7 +20,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.appprediction.AppsDividerView;
-import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.taskbar.NavbarButtonsViewController;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarStashController;
@@ -54,7 +53,6 @@
mOverlayController = taskbarControllers.taskbarOverlayController;
mSlideInView.init(new TaskbarAllAppsCallbacks());
- setUpIconLongClick();
setUpAppDivider();
setUpTaskbarStashing();
}
@@ -69,15 +67,6 @@
mSlideInView.close(animate);
}
- private void setUpIconLongClick() {
- mAppsView.setOnIconLongClickListener(
- mContext.getDragController()::startDragOnLongClick);
- mAppsView.getFloatingHeaderView()
- .findFixedRowByType(PredictionRowView.class)
- .setOnIconLongClickListener(
- mContext.getDragController()::startDragOnLongClick);
- }
-
private void setUpAppDivider() {
mAppsView.getFloatingHeaderView()
.findFixedRowByType(AppsDividerView.class)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 6b5c962..b2d5940 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -184,6 +184,8 @@
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(!BUBBLE_BAR_ENABLED);
mBubbleStashedHandleViewController.setHiddenForBubbles(!BUBBLE_BAR_ENABLED);
+ mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
+ key -> setSelectedBubble(mBubbles.get(key)));
});
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 58c67e3..563ba02 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -32,6 +32,7 @@
import com.android.launcher3.views.ActivityContext;
import java.util.List;
+import java.util.function.Consumer;
/**
* The view that holds all the bubble views. Modifying this view should happen through
@@ -71,7 +72,11 @@
private final BubbleBarBackground mBubbleBarBackground;
- // The current bounds of all the bubble bar.
+ /**
+ * The current bounds of all the bubble bar. Note that these bounds may not account for
+ * translation. The bounds should be retrieved using {@link #getBubbleBarBounds()} which
+ * updates the bounds and accounts for translation.
+ */
private final Rect mBubbleBarBounds = new Rect();
// The amount the bubbles overlap when they are stacked in the bubble bar
private final float mIconOverlapAmount;
@@ -101,6 +106,9 @@
@Nullable
private Runnable mReorderRunnable;
+ @Nullable
+ private Consumer<String> mUpdateSelectedBubbleAfterCollapse;
+
public BubbleBarView(Context context) {
this(context, null);
}
@@ -144,6 +152,13 @@
mReorderRunnable.run();
mReorderRunnable = null;
}
+ // If the bar was just collapsed and the overflow was the last bubble that was
+ // selected, set the first bubble as selected.
+ if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
+ && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
+ BubbleView firstBubble = (BubbleView) getChildAt(0);
+ mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
+ }
updateWidth();
}
@@ -175,9 +190,11 @@
}
/**
- * Returns the bounds of the bubble bar.
+ * Updates the bounds with translation that may have been applied and returns the result.
*/
public Rect getBubbleBarBounds() {
+ mBubbleBarBounds.top = getTop() + (int) getTranslationY();
+ mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
return mBubbleBarBounds;
}
@@ -293,6 +310,11 @@
}
}
+ public void setUpdateSelectedBubbleAfterCollapse(
+ Consumer<String> updateSelectedBubbleAfterCollapse) {
+ mUpdateSelectedBubbleAfterCollapse = updateSelectedBubbleAfterCollapse;
+ }
+
/**
* Sets which bubble view should be shown as selected.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 52c144e..725f948 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -36,6 +36,7 @@
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Controller for {@link BubbleBarView}. Manages the visibility of the bubble bar as well as
@@ -112,8 +113,8 @@
mBubbleStashController.stashBubbleBar();
} else {
mBubbleBarController.setSelectedBubble(bubble);
- mSystemUiProxy.showBubble(bubble.getKey(),
- mBubbleStashController.isBubblesShowingOnHome());
+ int[] bubbleBarCoords = mBarView.getLocationOnScreen();
+ mSystemUiProxy.showBubble(bubble.getKey(), bubbleBarCoords[0], bubbleBarCoords[1]);
}
}
@@ -184,6 +185,12 @@
}
}
+ /** Sets a callback that updates the selected bubble after the bubble bar collapses. */
+ public void setUpdateSelectedBubbleAfterCollapse(
+ Consumer<String> updateSelectedBubbleAfterCollapse) {
+ mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
+ }
+
/**
* Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
*/
@@ -286,8 +293,8 @@
} else {
final String selectedKey = mBubbleBarController.getSelectedBubbleKey();
if (selectedKey != null) {
- mSystemUiProxy.showBubble(selectedKey,
- mBubbleStashController.isBubblesShowingOnHome());
+ int[] bubbleBarCoords = mBarView.getLocationOnScreen();
+ mSystemUiProxy.showBubble(selectedKey, bubbleBarCoords[0], bubbleBarCoords[1]);
} else {
Log.w(TAG, "trying to expand bubbles when there isn't one selected");
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index b3c7d41..5177d93 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar.bubbles;
+import static java.lang.Math.abs;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -125,6 +127,16 @@
mBubblesShowingOnHome = onHome;
if (mBubblesShowingOnHome) {
showBubbleBar(/* expanded= */ false);
+ // When transitioning from app to home the stash animator may already have been
+ // created, so we need to animate the bubble bar here to align with hotseat.
+ if (!mIsStashed) {
+ mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForHotseat())
+ .start();
+ }
+ // If the bubble bar is already unstashed, the taskbar touchable region won't be
+ // updated correctly, so force an update here.
+ mControllers.runAfterInit(() ->
+ mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
} else if (!mBarViewController.isExpanded()) {
stashBubbleBar();
}
@@ -143,6 +155,11 @@
mBubblesShowingOnOverview = onOverview;
if (!mBubblesShowingOnOverview && !mBarViewController.isExpanded()) {
stashBubbleBar();
+ } else {
+ // When transitioning to overview the stash animator may already have been
+ // created, so we need to animate the bubble bar here to align with taskbar.
+ mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForTaskbar())
+ .start();
}
}
}
@@ -234,8 +251,11 @@
secondHalfDurationScale = 0.75f;
// If we're on home, adjust the translation so the bubble bar aligns with hotseat.
- final float hotseatTransY = mActivity.getDeviceProfile().getTaskbarOffsetY();
- final float translationY = mBubblesShowingOnHome ? hotseatTransY : 0;
+ // Otherwise we're either showing in an app or in overview. In either case adjust it so
+ // the bubble bar aligns with the taskbar.
+ final float translationY = mBubblesShowingOnHome ? getBubbleBarTranslationYForHotseat()
+ : getBubbleBarTranslationYForTaskbar();
+
fullLengthAnimatorSet.playTogether(
mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(translationY));
@@ -265,6 +285,7 @@
if (isStashed) {
mBarViewController.setExpanded(false);
}
+ mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
});
}
});
@@ -277,4 +298,15 @@
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
});
}
+
+ private float getBubbleBarTranslationYForTaskbar() {
+ return -mActivity.getDeviceProfile().taskbarBottomMargin;
+ }
+
+ private float getBubbleBarTranslationYForHotseat() {
+ final float hotseatBottomSpace = mActivity.getDeviceProfile().hotseatBarBottomSpacePx;
+ final float hotseatCellHeight = mActivity.getDeviceProfile().hotseatCellHeightPx;
+ return -hotseatBottomSpace - hotseatCellHeight + mUnstashedHeight - abs(
+ hotseatCellHeight - mUnstashedHeight) / 2;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index 27a4988..b682081 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -17,10 +17,12 @@
package com.android.launcher3.taskbar.navbutton
import android.content.res.Resources
+import android.graphics.drawable.RotateDrawable
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.R
+import com.android.launcher3.Utilities
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
/**
@@ -40,7 +42,18 @@
protected val endContextualContainer: ViewGroup,
protected val startContextualContainer: ViewGroup
) : NavButtonLayoutter {
- protected val homeButton: ImageView = navButtonContainer.findViewById(R.id.home)
- protected val recentsButton: ImageView = navButtonContainer.findViewById(R.id.recent_apps)
- protected val backButton: ImageView = navButtonContainer.findViewById(R.id.back)
+ protected val homeButton: ImageView? = navButtonContainer.findViewById(R.id.home)
+ protected val recentsButton: ImageView? = navButtonContainer.findViewById(R.id.recent_apps)
+ protected val backButton: ImageView? = navButtonContainer.findViewById(R.id.back)
+
+ init {
+ // setup back button drawable
+ if (backButton != null) {
+ val rotateDrawable = RotateDrawable()
+ rotateDrawable.drawable = backButton.context?.getDrawable(R.drawable.ic_sysbar_back)
+ rotateDrawable.fromDegrees = 0f
+ rotateDrawable.toDegrees = if (Utilities.isRtl(backButton.resources)) 90f else -90f
+ backButton.setImageDrawable(rotateDrawable)
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index 468a1a7..4a53c0c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -51,10 +51,10 @@
val paddingTop = (buttonHeight - iconSize) / 2
// Update icons
- backButton.setImageDrawable(backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
+ backButton!!.setImageDrawable(backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
backButton.scaleType = ImageView.ScaleType.FIT_CENTER
backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
- homeButton.setImageDrawable(homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
+ homeButton!!.setImageDrawable(homeButton.context.getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
homeButton.scaleType = ImageView.ScaleType.FIT_CENTER
homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 0668da9..7db2320 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -17,6 +17,8 @@
package com.android.launcher3.taskbar.navbutton
import android.content.res.Resources
+import android.view.Surface.ROTATION_90
+import android.view.Surface.Rotation
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
@@ -56,7 +58,8 @@
isKidsMode: Boolean,
isInSetup: Boolean,
isThreeButtonNav: Boolean,
- phoneMode: Boolean
+ phoneMode: Boolean,
+ @Rotation surfaceRotation: Int
): NavButtonLayoutter {
val navButtonContainer = navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
val endContextualContainer =
@@ -73,13 +76,20 @@
endContextualContainer,
startContextualContainer
)
- } else {
+ } else if (surfaceRotation == ROTATION_90) {
PhoneLandscapeNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
+ } else {
+ PhoneSeascapeNavLayoutter(
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer
+ )
}
}
deviceProfile.isTaskbarPresent -> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index 201895f..92715a7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -27,7 +27,7 @@
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
-class PhoneLandscapeNavLayoutter(
+open class PhoneLandscapeNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
@@ -44,8 +44,8 @@
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
- val taskbarDimensions =
- DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
+ val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
+ TaskbarManager.isPhoneMode(dp))
navButtonContainer.removeAllViews()
navButtonContainer.orientation = LinearLayout.VERTICAL
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index f7ac974..7f7fda7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -43,7 +43,8 @@
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
val taskbarDimensions =
- DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
+ DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
+ TaskbarManager.isPhoneMode(dp))
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
navContainerParams.width = taskbarDimensions.x
navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
new file mode 100644
index 0000000..f0fe581
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
@@ -0,0 +1,46 @@
+/*
+* 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.taskbar.navbutton
+
+import android.content.res.Resources
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import com.android.launcher3.DeviceProfile
+
+class PhoneSeascapeNavLayoutter(
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup
+) :
+ PhoneLandscapeNavLayoutter(
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer
+ ) {
+
+ override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
+ // TODO(b/230395757): Polish pending, this is just to make it usable
+ super.layoutButtons(dp, isContextualButtonShowing)
+ navButtonContainer.removeAllViews()
+ // Flip ordering of back and recents buttons
+ navButtonContainer.addView(backButton)
+ navButtonContainer.addView(homeButton)
+ navButtonContainer.addView(recentsButton)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index cfcc1a0..64cc47c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -126,6 +126,11 @@
}
@Override
+ public View.OnLongClickListener getAllAppsItemLongClickListener() {
+ return mDragController::startDragOnLongClick;
+ }
+
+ @Override
public PopupDataProvider getPopupDataProvider() {
return mTaskbarContext.getPopupDataProvider();
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index d241260..9fcadea 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -24,33 +24,26 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
-import static com.android.quickstep.views.FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA;
-import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.FloatProperty;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.views.FloatingTaskView;
import com.android.quickstep.views.RecentsView;
/**
@@ -115,49 +108,18 @@
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
boolean exitingOverview = !FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
- || !toState.overviewUi;
+ && !toState.overviewUi;
if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
- // TODO (b/238651489): Refactor state management to avoid need for double check
- FloatingTaskView floatingTask = mRecentsView.getFirstFloatingTaskView();
- if (floatingTask != null) {
- // We are in split selection state currently, transitioning to another state
- DragLayer dragLayer = mLauncher.getDragLayer();
- RectF onScreenRectF = new RectF();
- Utilities.getBoundsForViewInDragLayer(mLauncher.getDragLayer(), floatingTask,
- new Rect(0, 0, floatingTask.getWidth(), floatingTask.getHeight()),
- false, null, onScreenRectF);
- // Get the part of the floatingTask that intersects with the DragLayer (i.e. the
- // on-screen portion)
- onScreenRectF.intersect(
- dragLayer.getLeft(),
- dragLayer.getTop(),
- dragLayer.getRight(),
- dragLayer.getBottom()
- );
-
- setter.setFloat(
- mRecentsView.getFirstFloatingTaskView(),
- PRIMARY_TRANSLATE_OFFSCREEN,
- mRecentsView.getPagedOrientationHandler()
- .getFloatingTaskOffscreenTranslationTarget(
- floatingTask,
- onScreenRectF,
- floatingTask.getStagePosition(),
- mLauncher.getDeviceProfile()
- ),
- config.getInterpolator(
- ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN,
- LINEAR
- ));
- setter.setViewAlpha(
- mRecentsView.getSplitInstructionsView(),
- 0,
- config.getInterpolator(
- ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
- LINEAR
- )
- );
- }
+ setter.add(mRecentsView.getSplitSelectController().getSplitAnimationController()
+ .animateAwayPlaceholder(mLauncher));
+ setter.setViewAlpha(
+ mRecentsView.getSplitInstructionsView(),
+ 0,
+ config.getInterpolator(
+ ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
+ LINEAR
+ )
+ );
}
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 582b795..3b53e8a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -120,7 +120,6 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.proxy.ProxyActivityStarter;
-import com.android.launcher3.proxy.StartActivityParams;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
@@ -152,6 +151,7 @@
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
+import com.android.launcher3.util.StartActivityParams;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.widget.LauncherWidgetHolder;
import com.android.quickstep.OverviewCommandHelper;
@@ -193,6 +193,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -406,7 +407,8 @@
private List<SystemShortcut.Factory<QuickstepLauncher>> getSplitShortcuts() {
- if (!ENABLE_SPLIT_FROM_WORKSPACE.get() || !mDeviceProfile.isTablet) {
+ if (!ENABLE_SPLIT_FROM_WORKSPACE.get() || !mDeviceProfile.isTablet ||
+ mSplitSelectStateController.isSplitSelectActive()) {
return Collections.emptyList();
}
RecentsView recentsView = getOverviewPanel();
@@ -545,11 +547,22 @@
ArrayList<TouchController> list = new ArrayList<>();
list.add(getDragController());
+ Consumer<AnimatorSet> splitAnimator = animatorSet -> {
+ AnimatorSet anim = mSplitSelectStateController.getSplitAnimationController()
+ .animateAwayPlaceholder(QuickstepLauncher.this);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSplitSelectStateController.resetState();
+ }
+ });
+ animatorSet.play(anim);
+ };
switch (mode) {
case NO_BUTTON:
list.add(new NoButtonQuickSwitchTouchController(this));
- list.add(new NavBarToHomeTouchController(this));
- list.add(new NoButtonNavbarToOverviewTouchController(this));
+ list.add(new NavBarToHomeTouchController(this, splitAnimator));
+ list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator));
break;
case TWO_BUTTONS:
list.add(new TwoButtonNavbarTouchController(this));
@@ -560,8 +573,8 @@
break;
case THREE_BUTTONS:
list.add(new NoButtonQuickSwitchTouchController(this));
- list.add(new NavBarToHomeTouchController(this));
- list.add(new NoButtonNavbarToOverviewTouchController(this));
+ list.add(new NavBarToHomeTouchController(this, splitAnimator));
+ list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator));
list.add(new PortraitStatesTouchController(this));
break;
default:
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index be53220..b266bcd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -43,6 +44,7 @@
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.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.TouchController;
@@ -51,6 +53,8 @@
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
+import java.util.function.Consumer;
+
/**
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
*/
@@ -62,6 +66,7 @@
private static final float OVERVIEW_TO_HOME_SCRIM_MULTIPLIER = 0.5f;
private final Launcher mLauncher;
+ private final Consumer<AnimatorSet> mCancelSplitRunnable;
private final SingleAxisSwipeDetector mSwipeDetector;
private final float mPullbackDistance;
@@ -70,8 +75,14 @@
private LauncherState mEndState = NORMAL;
private AnimatorPlaybackController mCurrentAnimation;
- public NavBarToHomeTouchController(Launcher launcher) {
+ /**
+ * @param cancelSplitRunnable Called when split placeholder view needs to be cancelled.
+ * Animation should be added to the provided AnimatorSet
+ */
+ public NavBarToHomeTouchController(Launcher launcher,
+ Consumer<AnimatorSet> cancelSplitRunnable) {
mLauncher = launcher;
+ mCancelSplitRunnable = cancelSplitRunnable;
mSwipeDetector = new SingleAxisSwipeDetector(mLauncher, this,
SingleAxisSwipeDetector.VERTICAL);
mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance);
@@ -183,7 +194,10 @@
recentsView.switchToScreenshot(null,
() -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
if (mStartState.overviewUi) {
- new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState))
+ new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState),
+ FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ ? mCancelSplitRunnable
+ : null)
.animateWithVelocity(velocity);
} else {
mLauncher.getStateManager().goToState(mEndState, true,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 2f5467e..4075388 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -31,6 +31,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.PointF;
@@ -53,6 +54,8 @@
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
+import java.util.function.Consumer;
+
/**
* Touch controller which handles swipe and hold from the nav bar to go to Overview. Swiping above
* the nav bar falls back to go to All Apps. Swiping from the nav bar without holding goes to the
@@ -67,6 +70,7 @@
private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
private final VibratorWrapper mVibratorWrapper;
+ private final Consumer<AnimatorSet> mCancelSplitRunnable;
private final RecentsView mRecentsView;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
@@ -82,12 +86,18 @@
// Normal to Hint animation has flag SKIP_OVERVIEW, so we update this scrim with this animator.
private ObjectAnimator mNormalToHintOverviewScrimAnimator;
- public NoButtonNavbarToOverviewTouchController(Launcher l) {
+ /**
+ * @param cancelSplitRunnable Called when split placeholder view needs to be cancelled.
+ * Animation should be added to the provided AnimatorSet
+ */
+ public NoButtonNavbarToOverviewTouchController(Launcher l,
+ Consumer<AnimatorSet> cancelSplitRunnable) {
super(l);
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
mVibratorWrapper = VibratorWrapper.INSTANCE.get(l.getApplicationContext());
+ mCancelSplitRunnable = cancelSplitRunnable;
}
@Override
@@ -197,6 +207,9 @@
// state, but since the hint state tracks the entire screen without a clear endpoint, we
// need to manually set the duration to a reasonable value.
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
+ AnimatorSet animatorSet = new AnimatorSet();
+ mCancelSplitRunnable.accept(animatorSet);
+ animatorSet.start();
}
if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() &&
((mFromState == NORMAL && mToState == ALL_APPS)
@@ -268,7 +281,7 @@
private void goToOverviewOrHomeOnDragEnd(float velocity) {
boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
if (goToHomeInsteadOfOverview) {
- new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL))
+ new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL), null)
.animateWithVelocity(velocity);
}
if (mReachedOverview) {
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
index 529213c..33a2366 100644
--- a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -16,12 +16,12 @@
package com.android.quickstep;
-import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.os.RemoteException;
+import android.os.Process;
+import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.model.data.AppInfo;
@@ -55,9 +55,13 @@
@Override
public boolean isInstantApp(String packageName, int userId) {
+ if (!Process.myUserHandle().equals(UserHandle.of(userId))) {
+ // Instant app can only exist on current user
+ return false;
+ }
try {
- return ActivityThread.getPackageManager().isInstantApp(packageName, userId);
- } catch (RemoteException e) {
+ return mPM.isInstantApp(packageName);
+ } catch (Exception e) {
Log.e(TAG, "Failed to determine whether package is instant app " + packageName, e);
return false;
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 13da40a..5784c37 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,6 +18,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
@@ -267,7 +268,9 @@
@Override
public boolean allowAllAppsFromOverview() {
- return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get();
+ return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
+ // If floating search bar would not show in overview, don't allow all apps gesture.
+ && OVERVIEW.areElementsVisible(getCreatedActivity(), FLOATING_SEARCH_BAR);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 7cb6eb6..c58d6cc 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -58,6 +58,7 @@
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;
@@ -117,6 +118,7 @@
// animation callback
private final Handler mHandler = new Handler();
private final Runnable mAnimationStartTimeoutRunnable = this::onAnimationStartTimeout;
+ private SplitSelectStateController mSplitSelectStateController;
/**
* Init drag layer and overview panel views.
@@ -129,13 +131,12 @@
mFallbackRecentsView = findViewById(R.id.overview_panel);
mActionsView = findViewById(R.id.overview_actions_view);
getRootView().getSysUiScrim().getSysUIProgress().updateValue(0);
-
- SplitSelectStateController controller =
+ mSplitSelectStateController =
new SplitSelectStateController(this, mHandler, getStateManager(),
- null /* depthController */, getStatsLogManager(),
+ null /* depthController */, getStatsLogManager(),
SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this));
mDragLayer.recreateControllers();
- mFallbackRecentsView.init(mActionsView, controller);
+ mFallbackRecentsView.init(mActionsView, mSplitSelectStateController);
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 523a98e..2256cbf 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -37,6 +38,7 @@
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
@@ -101,9 +103,22 @@
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
+ long appCount = Arrays.stream(appTargets)
+ .filter(app -> app.mode == MODE_CLOSING)
+ .count();
+ if (appCount == 0) {
+ // Edge case, if there are no closing app targets, then Launcher has nothing to handle
+ ActiveGestureLog.INSTANCE.addLog(
+ /* event= */ "RecentsAnimationCallbacks.onAnimationStart (canceled)",
+ /* extras= */ 0,
+ /* gestureEvent= */ START_RECENTS_ANIMATION);
+ notifyAnimationCanceled();
+ animationController.finish(false /* toHome */, false /* sendUserLeaveHint */);
+ return;
+ }
+
mController = new RecentsAnimationController(animationController,
mAllowMinimizeSplitScreen, this::onAnimationFinished);
-
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
mController::finishAnimationToApp);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 7693e69..1448a52 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -239,7 +239,7 @@
public void onDisplayInfoChanged(Context context, Info info, int flags) {
if ((flags & (CHANGE_ROTATION | CHANGE_NAVIGATION_MODE)) != 0) {
mMode = info.navigationMode;
- mNavBarPosition = new NavBarPosition(mContext, mMode, info);
+ mNavBarPosition = new NavBarPosition(mMode, info);
if (mMode == NO_BUTTON) {
mExclusionListener.register();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index dd6499b..d2e7fb5 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -645,13 +646,13 @@
/**
* Tells SysUI to show the bubble with the provided key.
* @param key the key of the bubble to show.
- * @param onLauncherHome whether the bubble is showing on launcher home or not (modifies where
- * the expanded bubble view is placed).
+ * @param bubbleBarXCoordinate the X coordinate of the bubble bar on the screen.
+ * @param bubbleBarYCoordinate the Y coordinate of the bubble bar on the screen.
*/
- public void showBubble(String key, boolean onLauncherHome) {
+ public void showBubble(String key, int bubbleBarXCoordinate, int bubbleBarYCoordinate) {
if (mBubbles != null) {
try {
- mBubbles.showBubble(key, onLauncherHome);
+ mBubbles.showBubble(key, bubbleBarXCoordinate, bubbleBarYCoordinate);
} catch (RemoteException e) {
Log.w(TAG, "Failed call showBubble");
}
@@ -706,7 +707,7 @@
mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
splitRatio, remoteTransition, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startTasks");
+ Log.w(TAG, splitFailureMessage("startTasks", "RemoteException"), e);
}
}
}
@@ -719,7 +720,7 @@
mSplitScreen.startIntentAndTask(pendingIntent, userId1, options1, taskId, options2,
splitPosition, splitRatio, remoteTransition, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startIntentAndTask");
+ Log.w(TAG, splitFailureMessage("startIntentAndTask", "RemoteException"), e);
}
}
}
@@ -735,7 +736,7 @@
pendingIntent2, userId2, shortcutInfo2, options2, splitPosition, splitRatio,
remoteTransition, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startIntents");
+ Log.w(TAG, splitFailureMessage("startIntents", "RemoteException"), e);
}
}
}
@@ -748,7 +749,7 @@
mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
splitPosition, splitRatio, remoteTransition, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startShortcutAndTask");
+ Log.w(TAG, splitFailureMessage("startShortcutAndTask", "RemoteException"), e);
}
}
}
@@ -764,7 +765,8 @@
mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
splitPosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+ Log.w(TAG, splitFailureMessage(
+ "startTasksWithLegacyTransition", "RemoteException"), e);
}
}
}
@@ -778,7 +780,8 @@
mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
options1, taskId, options2, splitPosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startIntentAndTaskWithLegacyTransition");
+ Log.w(TAG, splitFailureMessage(
+ "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
}
}
}
@@ -791,7 +794,8 @@
mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
taskId, options2, splitPosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startShortcutAndTaskWithLegacyTransition");
+ Log.w(TAG, splitFailureMessage(
+ "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
}
}
}
@@ -811,7 +815,8 @@
shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
sidePosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startIntentsWithLegacyTransition");
+ Log.w(TAG, splitFailureMessage(
+ "startIntentsWithLegacyTransition", "RemoteException"), e);
}
}
}
@@ -823,7 +828,7 @@
mSplitScreen.startShortcut(packageName, shortcutId, position, options,
user, instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startShortcut");
+ Log.w(TAG, splitFailureMessage("startShortcut", "RemoteException"), e);
}
}
}
@@ -835,7 +840,7 @@
mSplitScreen.startIntent(intent, userId, fillInIntent, position, options,
instanceId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call startIntent");
+ Log.w(TAG, splitFailureMessage("startIntent", "RemoteException"), e);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 66f5c00..8a87f63 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -42,7 +42,7 @@
mActivity = activity;
NavigationMode sysUINavigationMode = DisplayController.getNavigationMode(mActivity);
if (sysUINavigationMode == NavigationMode.NO_BUTTON) {
- NavBarPosition navBarPosition = new NavBarPosition(mActivity, sysUINavigationMode,
+ NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
DisplayController.INSTANCE.get(mActivity).getInfo());
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
true /* disableHorizontalSwipe */, navBarPosition,
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index 5202529..c9c64b6 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -103,7 +103,8 @@
mStateCallback = new MultiStateCallback(STATE_NAMES);
mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
this::endRemoteAnimation);
- mStateCallback.runOnceAtState(STATE_FLING_FINISHED, this::onFlingFinished);
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
+ this::onFlingFinished);
mSwipeDetector = new SingleAxisSwipeDetector(mContext, this, VERTICAL);
mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 42b0edf..9f6119c 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -252,6 +252,10 @@
binder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
binder.setOverviewTargetChangeListener(binder::preloadOverviewForSUWAllSet);
binder.preloadOverviewForSUWAllSet();
+ TaskbarManager taskbarManager = binder.getTaskbarManager();
+ if (taskbarManager != null) {
+ mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
+ }
}
@Override
@@ -327,13 +331,9 @@
mRootView.setAlpha(alpha);
mRootView.setTranslationY((alpha - 1) * mSwipeUpShift);
- TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
- if (mLauncherStartAnim == null && taskbarManager != null) {
- mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
- }
if (mLauncherStartAnim != null) {
- mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange(
- mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN));
+ mLauncherStartAnim.setPlayFraction(
+ FAST_OUT_SLOW_IN.getInterpolation(mSwipeProgress.value));
}
maybeResumeOrPauseBackgroundAnimation();
}
diff --git a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
index 46f79b1..c19d44a 100644
--- a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
@@ -19,7 +19,6 @@
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU;
-import android.graphics.Rect;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -28,33 +27,17 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
/** Displays the gesture nav tutorial menu. */
public final class MenuFragment extends GestureSandboxFragment {
- @NonNull private Rect mInsets = new Rect();
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mInsets = InvariantDeviceProfile.INSTANCE.get(getContext())
- .getDeviceProfile(getContext()).getInsets();
- }
-
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
- View root = inflater.inflate(
+ final View root = inflater.inflate(
R.layout.gesture_tutorial_step_menu, container, false);
- root.setPadding(
- root.getPaddingLeft() + mInsets.left,
- root.getPaddingTop() + mInsets.top,
- root.getPaddingRight() + mInsets.right,
- root.getPaddingBottom() + mInsets.bottom);
-
root.findViewById(R.id.gesture_tutorial_menu_home_button).setOnClickListener(
v -> launchTutorialStep(TutorialController.TutorialType.HOME_NAVIGATION));
root.findViewById(R.id.gesture_tutorial_menu_back_button).setOnClickListener(
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 63e41d5..c4a2216 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -60,12 +60,11 @@
NavBarGestureHandler(Context context) {
mContext = context;
DisplayController.Info displayInfo = DisplayController.INSTANCE.get(mContext).getInfo();
- final int displayRotation = displayInfo.rotation;
Point currentSize = displayInfo.currentSize;
mDisplaySize.set(currentSize.x, currentSize.y);
mSwipeUpTouchTracker =
new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
- new NavBarPosition(mContext, NavigationMode.NO_BUTTON, displayRotation),
+ new NavBarPosition(NavigationMode.NO_BUTTON, displayInfo),
null /*onInterceptTouch*/, this);
mMotionPauseDetector = new MotionPauseDetector(context);
diff --git a/quickstep/src/com/android/quickstep/util/LogUtils.kt b/quickstep/src/com/android/quickstep/util/LogUtils.kt
index 23a41f6..e34c4ec 100644
--- a/quickstep/src/com/android/quickstep/util/LogUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/LogUtils.kt
@@ -20,6 +20,11 @@
import com.android.launcher3.logging.InstanceId
object LogUtils {
+ @JvmStatic
+ fun splitFailureMessage(caller: String, reason: String): String {
+ return "($caller) Splitscreen aborted: $reason"
+ }
+
/**
* @return a [Pair] of two InstanceIds but with different types, one that can be used by
* framework (if needing to pass through an intent or such) and one used in Launcher
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
index a89e7e3..9418512 100644
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
@@ -16,9 +16,7 @@
package com.android.quickstep.util;
import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
-import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
-import android.content.Context;
import android.view.Surface;
import com.android.launcher3.util.DisplayController.Info;
@@ -29,26 +27,22 @@
*/
public class NavBarPosition {
- private final boolean mIsLargeScreen;
+ private final boolean mIsTablet;
private final NavigationMode mMode;
private final int mDisplayRotation;
- public NavBarPosition(Context context, NavigationMode mode, Info info) {
- this(context, mode, info.rotation);
- }
-
- public NavBarPosition(Context context, NavigationMode mode, int displayRotation) {
- mIsLargeScreen = isLargeScreen(context);
+ public NavBarPosition(NavigationMode mode, Info info) {
+ mIsTablet = info.isTablet(info.realBounds);
mMode = mode;
- mDisplayRotation = displayRotation;
+ mDisplayRotation = info.rotation;
}
public boolean isRightEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsLargeScreen;
+ return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsTablet;
}
public boolean isLeftEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsLargeScreen;
+ return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsTablet;
}
public float getRotation() {
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 3cec1a4..6d9ecd9 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -22,12 +22,16 @@
import android.animation.AnimatorSet;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
+import java.util.function.Consumer;
+
/**
* Runs an animation from overview to home. Currently, this animation is just a wrapper around the
* normal state transition and may play a {@link WorkspaceRevealAnim} if we're starting from an
@@ -39,14 +43,18 @@
private final Launcher mLauncher;
private final Runnable mOnReachedHome;
+ @Nullable
+ private final Consumer<AnimatorSet> mSplitCancelConsumer;
// Only run mOnReachedHome when both of these are true.
private boolean mIsHomeStaggeredAnimFinished;
private boolean mIsOverviewHidden;
- public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome) {
+ public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome,
+ @Nullable Consumer<AnimatorSet> splitCancelConsumer) {
mLauncher = launcher;
mOnReachedHome = onReachedHome;
+ mSplitCancelConsumer = splitCancelConsumer;
}
/**
@@ -92,6 +100,11 @@
maybeOverviewToHomeAnimComplete();
}
});
+
+ if (mSplitCancelConsumer != null) {
+ // Clear split state when swiping to home
+ mSplitCancelConsumer.accept(anim);
+ }
anim.play(stateAnim);
stateManager.setCurrentAnimation(anim, NORMAL);
anim.start();
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index b76fe5c..2e8af4c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -17,14 +17,22 @@
package com.android.quickstep.util
+import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.graphics.Bitmap
+import android.graphics.Rect
+import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.view.View
import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Launcher
+import com.android.launcher3.Utilities
import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.dragndrop.DragLayer
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
+import com.android.quickstep.views.FloatingTaskView
import com.android.quickstep.views.IconView
+import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
@@ -176,4 +184,38 @@
TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f))
}
}
+
+
+ fun animateAwayPlaceholder(mLauncher: Launcher) : AnimatorSet {
+ val animatorSet = AnimatorSet()
+ val recentsView : RecentsView<*, *> = mLauncher.getOverviewPanel()
+ val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
+ ?: return animatorSet
+
+ // We are in split selection state currently, transitioning to another state
+ val dragLayer: DragLayer = mLauncher.dragLayer
+ val onScreenRectF = RectF()
+ Utilities.getBoundsForViewInDragLayer(mLauncher.dragLayer, floatingTask,
+ Rect(0, 0, floatingTask.width, floatingTask.height),
+ false, null, onScreenRectF)
+ // Get the part of the floatingTask that intersects with the DragLayer (i.e. the
+ // on-screen portion)
+ onScreenRectF.intersect(
+ dragLayer.left.toFloat(),
+ dragLayer.top.toFloat(),
+ dragLayer.right.toFloat(),
+ dragLayer.bottom
+ .toFloat()
+ )
+ animatorSet.play(ObjectAnimator.ofFloat(floatingTask,
+ FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN,
+ recentsView.pagedOrientationHandler
+ .getFloatingTaskOffscreenTranslationTarget(
+ floatingTask,
+ onScreenRectF,
+ floatingTask.stagePosition,
+ mLauncher.deviceProfile
+ )))
+ return animatorSet
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index e063b44..970cf64 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -561,7 +561,7 @@
new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
ActivityThread.currentActivityThread().getApplicationThread(),
- "LaunchSplitPair");
+ "LaunchAppFullscreen");
InstanceId instanceId = LogUtils.getShellShareableInstanceId().first;
if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
switch (launchData.getSplitLaunchType()) {
@@ -895,6 +895,7 @@
mFirstFloatingTaskView = floatingTaskView;
}
+ @Nullable
public FloatingTaskView getFirstFloatingTaskView() {
return mFirstFloatingTaskView;
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index c91b183..01f6ae8 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -223,11 +223,12 @@
// Callbacks run from remote animation when recents animation not currently running
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Enter form GroupedTaskView");
- launchTask(success -> {
+ launchTaskInternal(success -> {
endCallback.executeAllAndDestroy();
InteractionJankMonitorWrapper.end(
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
- }, false /* freezeTaskList */);
+ }, false /* freezeTaskList */, true /*launchingExistingTaskview*/);
+
// Callbacks get run from recentsView for case when recents animation already running
recentsView.addSideTaskLaunchCallback(endCallback);
@@ -236,7 +237,19 @@
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- getRecentsView().getSplitSelectController().launchExistingSplitPair(this, mTask.key.id,
+ launchTaskInternal(callback, isQuickswitch, false /*launchingExistingTaskview*/);
+ }
+
+ /**
+ * @param launchingExistingTaskView {@link SplitSelectStateController#launchExistingSplitPair}
+ * uses existence of GroupedTaskView as control flow of how to animate in the incoming task. If
+ * we're launching from overview (from overview thumbnails) then pass in {@code true},
+ * otherwise pass in {@code false} for case like quickswitching from home to task
+ */
+ private void launchTaskInternal(@NonNull Consumer<Boolean> callback, boolean isQuickswitch,
+ boolean launchingExistingTaskView) {
+ getRecentsView().getSplitSelectController().launchExistingSplitPair(
+ launchingExistingTaskView ? this : null, mTask.key.id,
mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
callback, isQuickswitch, getSplitRatio());
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 421a48c..b8ec5f0 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -43,7 +43,6 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.config.FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCH_FROM_STAGED_APP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
@@ -54,6 +53,7 @@
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
@@ -3242,9 +3242,7 @@
mSplitSelectStateController.setFirstFloatingTaskView(firstFloatingTaskView);
// Allow user to click staged app to launch into fullscreen
- if (ENABLE_LAUNCH_FROM_STAGED_APP.get()) {
- firstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
- }
+ firstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
// SplitInstructionsView: animate in
safeRemoveDragLayerView(mSplitInstructionsView);
@@ -4725,6 +4723,8 @@
return false;
}
if (mSplitSelectStateController.isBothSplitAppsConfirmed()) {
+ Log.w(TAG, splitFailureMessage(
+ "confirmSplitSelect", "both apps have already been set"));
return true;
}
// Second task is selected either as an already-running Task or an Intent
@@ -4732,6 +4732,9 @@
if (!task.isDockable) {
// Task does not support split screen
mSplitUnsupportedToast.show();
+ Log.w(TAG, splitFailureMessage("confirmSplitSelect",
+ "selected Task (" + task.key.getPackageName()
+ + ") is not dockable / does not support splitscreen"));
return true;
}
mSplitSelectStateController.setSecondTask(task);
@@ -6020,11 +6023,6 @@
}
@Nullable
- public FloatingTaskView getFirstFloatingTaskView() {
- return mSplitSelectStateController.getFirstFloatingTaskView();
- }
-
- @Nullable
public SplitInstructionsView getSplitInstructionsView() {
return mSplitInstructionsView;
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 236b5db..3920b08 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -1,6 +1,9 @@
package com.android.launcher3.taskbar.navbutton
import android.content.res.Resources
+import android.view.Surface
+import android.view.Surface.ROTATION_270
+import android.view.Surface.Rotation
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
@@ -32,6 +35,8 @@
@Mock lateinit var mockRecentsButton: ImageView
@Mock lateinit var mockHomeButton: ImageView
+ private var surfaceRotation = Surface.ROTATION_0
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -60,7 +65,8 @@
isKidsMode = true,
isInSetup = false,
isThreeButtonNav = false,
- phoneMode = false
+ phoneMode = false,
+ surfaceRotation = surfaceRotation
)
assert(layoutter is KidsNavLayoutter)
}
@@ -74,7 +80,8 @@
isKidsMode = false,
isInSetup = true,
isThreeButtonNav = false,
- phoneMode = false
+ phoneMode = false,
+ surfaceRotation = surfaceRotation
)
assert(layoutter is SetupNavLayoutter)
}
@@ -88,7 +95,8 @@
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
- phoneMode = false
+ phoneMode = false,
+ surfaceRotation = surfaceRotation
)
assert(layoutter is TaskbarNavLayoutter)
}
@@ -101,7 +109,8 @@
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
- phoneMode = false
+ phoneMode = false,
+ surfaceRotation = surfaceRotation
)
}
@@ -114,7 +123,8 @@
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = true,
- phoneMode = true
+ phoneMode = true,
+ surfaceRotation = surfaceRotation
)
assert(layoutter is PhonePortraitNavLayoutter)
}
@@ -129,11 +139,28 @@
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = true,
- phoneMode = true
+ phoneMode = true,
+ surfaceRotation = surfaceRotation
)
assert(layoutter is PhoneLandscapeNavLayoutter)
}
+ @Test
+ fun getTaskbarSeascapeLayoutter() {
+ assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ mockDeviceProfile.isTaskbarPresent = false
+ setDeviceProfileLandscape()
+ val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = true,
+ phoneMode = true,
+ surfaceRotation = ROTATION_270
+ )
+ assert(layoutter is PhoneSeascapeNavLayoutter)
+ }
+
@Test(expected = IllegalStateException::class)
fun noValidLayoutForPhoneGestureNav() {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
@@ -142,7 +169,8 @@
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
- phoneMode = true
+ phoneMode = true,
+ surfaceRotation = surfaceRotation
)
}
@@ -157,7 +185,8 @@
isKidsMode: Boolean,
isInSetup: Boolean,
isThreeButtonNav: Boolean,
- phoneMode: Boolean
+ phoneMode: Boolean,
+ @Rotation surfaceRotation: Int
): NavButtonLayoutFactory.NavButtonLayoutter {
return NavButtonLayoutFactory.getUiLayoutter(
deviceProfile = mockDeviceProfile,
@@ -166,7 +195,8 @@
isKidsMode = isKidsMode,
isInSetup = isInSetup,
isThreeButtonNav = isThreeButtonNav,
- phoneMode = phoneMode
+ phoneMode = phoneMode,
+ surfaceRotation = surfaceRotation
)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 7492ab8..a67d787 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -62,7 +62,6 @@
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.util.rule.ViewCaptureAnalysisRule;
import com.android.launcher3.util.rule.ViewCaptureRule;
import com.android.quickstep.views.RecentsView;
@@ -123,8 +122,7 @@
.outerRule(new SamplerRule())
.around(new NavigationModeSwitchRule(mLauncher))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule)
- .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
+ .around(viewCaptureRule);
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
new file mode 100644
index 0000000..e92dc8f
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import static org.junit.Assume.assumeTrue;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplTestsTrackpad extends AbstractQuickStepTest {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ TaplTestsLauncher3.initialize(this);
+ mLauncher.setSwipeFromTrackpad(true);
+ }
+
+ @After
+ public void tearDown() {
+ mLauncher.setSwipeFromTrackpad(false);
+ }
+
+ @Test
+ @PortraitLandscape
+ @NavigationModeSwitch
+ public void goHome() throws Exception {
+ assumeTrue(mLauncher.isTablet());
+
+ startTestActivity(2);
+ mLauncher.goHome();
+ }
+}
diff --git a/res/color-v31/surface.xml b/res/color-v31/surface.xml
deleted file mode 100644
index da4571a..0000000
--- a/res/color-v31/surface.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-<selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/materialColorSurfaceContainerHighest"/>
-</selector>
-
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
index c3a8269..e279fa0 100644
--- a/res/drawable/add_item_dialog_background.xml
+++ b/res/drawable/add_item_dialog_background.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
- <solid android:color="@color/surface" />
+ <solid android:color="@color/material_color_surface_container_highest" />
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/res/drawable/button_top_rounded_bordered_ripple.xml b/res/drawable/button_top_rounded_bordered_ripple.xml
index f15a4a0..f5b6886 100644
--- a/res/drawable/button_top_rounded_bordered_ripple.xml
+++ b/res/drawable/button_top_rounded_bordered_ripple.xml
@@ -25,7 +25,7 @@
android:topRightRadius="12dp"
android:bottomLeftRadius="4dp"
android:bottomRightRadius="4dp" />
- <solid android:color="@color/surface"/>
+ <solid android:color="@color/material_color_surface_container_highest"/>
<stroke
android:width="2dp"
android:color="@color/button_bg"/>
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 95ebd94..82b0b8d 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,5 +21,4 @@
android:layout_height="match_parent"
android:theme="@style/HomeScreenElementTheme"
android:importantForAccessibility="no"
- android:preferKeepClear="true"
launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index c39e1d6..1ec09f5 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -168,7 +168,7 @@
<string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"အလုပ်သုံးအက်ပ်များကို တံဆိပ်တပ်ထားပြီး သင်၏ IT စီမံခန့်ခွဲသူက မြင်နိုင်ပါသည်"</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"နားလည်ပြီ"</string>
<string name="work_apps_pause_btn_text" msgid="4669288269140620646">"အလုပ်သုံးအက်ပ်များကို ခဏရပ်ရန်"</string>
- <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ပြန်စရန်"</string>
+ <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ပြန်ဖွင့်ရန်"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"စစ်ထုတ်ရန်"</string>
<string name="search_pref_screen_title" msgid="3258959643336315962">"သင့်ဖုန်းတွင် ရှာခြင်း"</string>
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"သင့်တက်ဘလက်ကို ရှာခြင်း"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 76a1239..73e392d 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -85,6 +85,7 @@
<enum name="taskbar" value="5" />
<enum name="search_result_tall" value="6" />
<enum name="search_result_small" value="7" />
+ <enum name="prediction_row" value="8" />
</attr>
<attr name="centerVertically" format="boolean" />
</declare-styleable>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 05d434e..2356bcc 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -94,11 +94,12 @@
IconLabelDotView, DraggableView, Reorderable {
private static final int DISPLAY_WORKSPACE = 0;
- private static final int DISPLAY_ALL_APPS = 1;
+ public static final int DISPLAY_ALL_APPS = 1;
private static final int DISPLAY_FOLDER = 2;
protected static final int DISPLAY_TASKBAR = 5;
private static final int DISPLAY_SEARCH_RESULT = 6;
private static final int DISPLAY_SEARCH_RESULT_SMALL = 7;
+ public static final int DISPLAY_PREDICTION_ROW = 8;
private static final float MIN_LETTER_SPACING = -0.05f;
private static final int MAX_SEARCH_LOOP_COUNT = 20;
@@ -211,7 +212,7 @@
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
setCenterVertically(grid.iconCenterVertically);
- } else if (mDisplay == DISPLAY_ALL_APPS) {
+ } else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
@@ -402,7 +403,7 @@
* Only if actual text can be displayed in two line, the {@code true} value will be effective.
*/
protected boolean shouldUseTwoLine() {
- return (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() && mDisplay == DISPLAY_ALL_APPS)
+ return (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() && mDisplay == DISPLAY_ALL_APPS)
|| (FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()
&& mDisplay == DISPLAY_SEARCH_RESULT);
}
@@ -424,10 +425,10 @@
}
}
- /** This is used for testing to forcefully set the display to ALL_APPS */
+ /** This is used for testing to forcefully set the display. */
@VisibleForTesting
- public void setDisplayAllApps() {
- mDisplay = DISPLAY_ALL_APPS;
+ public void setDisplay(int display) {
+ mDisplay = display;
}
/**
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bd47fca..814a0f9 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -164,7 +164,7 @@
public int iconSizePx;
public int iconTextSizePx;
public int iconDrawablePaddingPx;
- public int iconDrawablePaddingOriginalPx;
+ private final int mIconDrawablePaddingOriginalPx;
public boolean iconCenterVertically;
public float cellScaleToFit;
@@ -456,7 +456,7 @@
cellStyle = context.obtainStyledAttributes(R.style.CellStyleDefault,
R.styleable.CellStyle);
}
- iconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
+ mIconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
R.styleable.CellStyle_iconDrawablePadding, 0);
cellStyle.recycle();
@@ -883,7 +883,6 @@
iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid;
updateIconSize(1f, res);
-
updateWorkspacePadding();
// Check to see if the icons fit within the available height.
@@ -925,6 +924,25 @@
+ cellLayoutPaddingPx.left + cellLayoutPaddingPx.right;
}
+ private int getNormalizedIconDrawablePadding() {
+ // TODO(b/235886078): workaround needed because of this bug
+ // Icons are 10% larger on XML than their visual size,
+ // so remove that extra space to get labels closer to the correct padding
+ int iconVisibleSizePx = (int) Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
+ return Math.max(0, mIconDrawablePaddingOriginalPx - ((iconSizePx - iconVisibleSizePx) / 2));
+ }
+
+ private int getNormalizedFolderChildDrawablePaddingPx(int textHeight) {
+ // TODO(b/235886078): workaround needed because of this bug
+ // Icons are 10% larger on XML than their visual size,
+ // so remove that extra space to get labels closer to the correct padding
+ int drawablePadding = (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3;
+
+ int iconVisibleSizePx = Math.round(ICON_VISIBLE_AREA_FACTOR * folderChildIconSizePx);
+ int iconSizeDiff = folderChildIconSizePx - iconVisibleSizePx;
+ return Math.max(0, drawablePadding - iconSizeDiff / 2);
+ }
+
/**
* Updating the iconSize affects many aspects of the launcher layout, such as: iconSizePx,
* iconTextSizePx, iconDrawablePaddingPx, cellWidth/Height, allApps* variants,
@@ -937,43 +955,36 @@
// Workspace
final boolean isVerticalLayout = isVerticalBarLayout();
- iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale);
cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale);
- int cellTextAndPaddingHeight =
- iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
if (mIsResponsiveGrid) {
- int cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
-
cellWidthPx = mResponsiveWidthSpec.getCellSizePx();
cellHeightPx = mResponsiveHeightSpec.getCellSizePx();
if (cellWidthPx < iconSizePx) {
// get a smaller icon size
iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
- // calculate new cellContentHeight
- cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
}
+ iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+ int iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
+ int cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
+
while (iconSizePx > mIconSizeSteps.minimumIconSize()
&& cellContentHeight > cellHeightPx) {
- int extraHeightRequired = cellContentHeight - cellHeightPx;
- int newPadding = iconDrawablePaddingPx - extraHeightRequired;
- if (newPadding >= 0) {
- // Responsive uses the padding without scaling
- iconDrawablePaddingPx = iconDrawablePaddingOriginalPx = newPadding;
- cellTextAndPaddingHeight =
- iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
- } else {
+ iconDrawablePaddingPx -= cellContentHeight - cellHeightPx;
+ if (iconDrawablePaddingPx < 0) {
// get a smaller icon size
iconSizePx = mIconSizeSteps.getNextLowerIconSize(iconSizePx);
+ iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
}
// calculate new cellContentHeight
- cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
+ cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
}
cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
} else if (mIsScalableGrid) {
+ iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale);
cellHeightPx = pxFromDp(inv.minCellSize[mTypeIndex].y, mMetrics, scale);
@@ -995,6 +1006,8 @@
}
}
+ int cellTextAndPaddingHeight =
+ iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
int cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
if (cellHeightPx < cellContentHeight) {
// If cellHeight no longer fit iconSize, reduce borderSpace to make cellHeight
@@ -1030,6 +1043,7 @@
desiredWorkspaceHorizontalMarginPx =
(int) (desiredWorkspaceHorizontalMarginOriginalPx * scale);
} else {
+ iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
cellWidthPx = iconSizePx + iconDrawablePaddingPx;
cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR)
+ iconDrawablePaddingPx
@@ -1103,7 +1117,7 @@
if (mIsScalableGrid) {
allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
- allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
+ allAppsIconDrawablePaddingPx = getNormalizedIconDrawablePadding();
allAppsCellWidthPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].x, mMetrics, scale);
if (allAppsCellWidthPx < allAppsIconSizePx) {
@@ -1145,7 +1159,7 @@
private void updateAllAppsWithResponsiveMeasures() {
allAppsIconSizePx = iconSizePx;
allAppsIconTextSizePx = iconTextSizePx;
- allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
+ allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
allAppsBorderSpacePx = new Point(
mAllAppsResponsiveWidthSpec.getGutterPx(),
@@ -1244,6 +1258,32 @@
mResponsiveHeightSpec.getGutterPx());
folderContentPaddingLeftRight = mResponsiveFolderWidthSpec.getStartPaddingPx();
+
+ // Reduce icon width if it's wider than the expected folder cell width
+ if (folderCellWidthPx < folderChildIconSizePx) {
+ folderChildIconSizePx = mIconSizeSteps.getIconSmallerThan(folderCellWidthPx);
+ }
+
+ // Recalculating padding and cell height
+ folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
+ int folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
+ + textHeight;
+
+ // Reduce the icon in height when it's taller than the expected cell height
+ while (folderChildIconSizePx > mIconSizeSteps.minimumIconSize()
+ && folderCellContentHeight > folderCellHeightPx) {
+ folderChildDrawablePaddingPx -= folderCellContentHeight - folderCellHeightPx;
+ if (folderChildDrawablePaddingPx < 0) {
+ // get a smaller icon size
+ folderChildIconSizePx = mIconSizeSteps.getNextLowerIconSize(
+ folderChildIconSizePx);
+ folderChildDrawablePaddingPx =
+ getNormalizedFolderChildDrawablePaddingPx(textHeight);
+ }
+ // calculate new cellContentHeight
+ folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
+ + textHeight;
+ }
} else if (mIsScalableGrid) {
if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
@@ -1261,6 +1301,8 @@
folderFooterHeightPx = roundPxValueFromFloat(folderFooterHeightPx * scale);
folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x;
+
+ folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
} else {
int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
* scale);
@@ -1277,10 +1319,8 @@
res.getDimensionPixelSize(R.dimen.folder_footer_height_default)
* scale);
+ folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
}
-
- folderChildDrawablePaddingPx = Math.max(0,
- (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3);
}
public void updateInsets(Rect insets) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7e43002..849db28 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -194,6 +194,7 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.AllAppsSwipeController;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ActivityTracker;
@@ -1407,8 +1408,7 @@
*/
protected void completeAddShortcut(Intent data, int container, int screenId, int cellX,
int cellY, PendingRequestArgs args) {
- if (args.getRequestCode() != REQUEST_CREATE_SHORTCUT
- || args.getPendingIntent().getComponent() == null) {
+ if (args.getRequestCode() != REQUEST_CREATE_SHORTCUT) {
return;
}
@@ -1916,16 +1916,10 @@
info.spanX = spanX;
info.spanY = spanY;
- switch (info.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- addAppWidgetFromDrop((PendingAddWidgetInfo) info);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- processShortcutFromDrop((PendingAddShortcutInfo) info);
- break;
- default:
- throw new IllegalStateException("Unknown item type: " + info.itemType);
+ if (info instanceof PendingAddWidgetInfo) {
+ addAppWidgetFromDrop((PendingAddWidgetInfo) info);
+ } else { // info can only be PendingAddShortcutInfo
+ processShortcutFromDrop((PendingAddShortcutInfo) info);
}
}
@@ -3379,4 +3373,9 @@
public boolean areFreeformTasksVisible() {
return false; // Base launcher does not track freeform tasks
}
+
+ @Override
+ public View.OnLongClickListener getAllAppsItemLongClickListener() {
+ return ItemLongClickListener.INSTANCE_ALL_APPS;
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ddafd53..5f3d27c 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,9 +20,7 @@
import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
import static com.android.launcher3.testing.shared.TestProtocol.sDebugTracing;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -69,7 +67,6 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@@ -310,11 +307,6 @@
* @see UserCache#addUserEventListener
*/
public void onUserEvent(UserHandle user, String action) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WORK_TAB_MISSING, "onBroadcastIntent intentAction: "
- + action + " user: " + user);
- }
-
if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
enqueueModelUpdateTask(new PackageUpdatedTask(
@@ -562,7 +554,6 @@
synchronized (mLock) {
// Everything loaded bind the data.
mModelLoaded = true;
- testLogD(WORK_TAB_MISSING, "launcher model loaded");
}
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 177f883..427eaa3 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -277,7 +277,7 @@
@JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "", true)
@JvmField
val ALL_APPS_OVERVIEW_THRESHOLD =
- nonRestorableItem(LauncherAppState.KEY_ALL_APPS_OVERVIEW_THRESHOLD, 200, true)
+ nonRestorableItem(LauncherAppState.KEY_ALL_APPS_OVERVIEW_THRESHOLD, 180, true)
@JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, true)
@JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
@JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0)
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 4590125..da1bcd7 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,10 +18,10 @@
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
import android.animation.Animator;
@@ -78,8 +78,6 @@
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -141,7 +139,7 @@
private final SearchTransitionController mSearchTransitionController;
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Rect mInsets = new Rect();
- private final AllAppsStore mAllAppsStore = new AllAppsStore();
+ private final AllAppsStore mAllAppsStore;
private final RecyclerView.OnScrollListener mScrollListener =
new RecyclerView.OnScrollListener() {
@Override
@@ -194,6 +192,7 @@
public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mActivityContext = ActivityContext.lookupContext(context);
+ mAllAppsStore = new AllAppsStore(mActivityContext);
mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
mHeaderThreshold = getResources().getDimensionPixelSize(
@@ -208,10 +207,6 @@
mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
AllAppsStore.OnUpdateListener onAppsUpdated = this::onAppsUpdated;
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "ActivityAllAppsContainer#init registeringListener: " +
- onAppsUpdated);
- }
mAllAppsStore.addUpdateListener(onAppsUpdated);
// This is a focus listener that proxies focus from a view into the list view. This is to
@@ -559,6 +554,13 @@
mAH.get(AdapterHolder.MAIN).setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH.get(AdapterHolder.WORK).setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
mAH.get(AdapterHolder.WORK).mRecyclerView.setId(R.id.apps_list_view_work);
+ if (ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
+ // Let main and work rv share same view pool.
+ ((RecyclerView) mViewPager.getChildAt(0))
+ .setRecycledViewPool(mAllAppsStore.getRecyclerViewPool());
+ ((RecyclerView) mViewPager.getChildAt(1))
+ .setRecycledViewPool(mAllAppsStore.getRecyclerViewPool());
+ }
if (FeatureFlags.ENABLE_EXPANDING_PAUSE_WORK_BUTTON.get()) {
mAH.get(AdapterHolder.WORK).mRecyclerView.addOnScrollListener(
mWorkManager.newScrollListener());
@@ -890,15 +892,6 @@
container.put(R.id.work_tab_state_id, state);
}
- /**
- * Sets the long click listener for icons
- */
- public void setOnIconLongClickListener(OnLongClickListener listener) {
- for (AdapterHolder holder : mAH) {
- holder.mAdapter.setOnIconLongClickListener(listener);
- }
- }
-
public AllAppsStore getAppsStore() {
return mAllAppsStore;
}
@@ -942,10 +935,6 @@
private void onAppsUpdated() {
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "ActivityAllAppsContainerView#onAppsUpdated hasWorkApps: " +
- mHasWorkApps + " allApps: " + mAllAppsStore.getApps().length);
- }
if (!isSearching()) {
rebindAdapters();
if (mHasWorkApps) {
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 7c5c003..602d1a3 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -96,8 +96,8 @@
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
- pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows
- * (mNumAppsPerRow + 1));
+ pool.setMaxRecycledViews(
+ AllAppsGridAdapter.VIEW_TYPE_ICON, (approxRows + 1) * grid.numShownAllAppsColumns);
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 06af970..c3d0e6b 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -15,24 +15,27 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
+import android.content.Context;
import android.os.UserHandle;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView.RecycledViewPool;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.recyclerview.AllAppsRecyclerViewPool;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.Arrays;
@@ -45,8 +48,10 @@
/**
* A utility class to maintain the collection of all apps.
+ *
+ * @param <T> The type of the context.
*/
-public class AllAppsStore {
+public class AllAppsStore<T extends Context & ActivityContext> {
// Defer updates flag used to defer all apps updates to the next draw.
public static final int DEFER_UPDATES_NEXT_DRAW = 1 << 0;
@@ -64,20 +69,36 @@
private int mModelFlags;
private int mDeferUpdatesFlags = 0;
private boolean mUpdatePending = false;
+ private final AllAppsRecyclerViewPool mAllAppsRecyclerViewPool = new AllAppsRecyclerViewPool();
+
+ private final T mContext;
public AppInfo[] getApps() {
return mApps;
}
+ public AllAppsStore(@NonNull T context) {
+ mContext = context;
+ }
+
/**
* 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) {
+ public void setApps(AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
mApps = apps;
mModelFlags = flags;
notifyUpdate();
mPackageUserKeytoUidMap = map;
+ // Preinflate all apps RV when apps has changed, which can happen after unlocking screen,
+ // rotating screen, or downloading/upgrading apps.
+ if (ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
+ mAllAppsRecyclerViewPool.preInflateAllAppsViewHolders(mContext);
+ }
+ }
+
+ RecycledViewPool getRecyclerViewPool() {
+ return mAllAppsRecyclerViewPool;
}
/**
@@ -134,9 +155,6 @@
return;
}
for (OnUpdateListener listener : mUpdateListeners) {
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "AllAppsStore#notifyUpdate listener: " + listener);
- }
listener.onAppsUpdated();
}
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 8fa4276..be0a898 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -15,10 +15,7 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;
-
import android.content.Context;
-import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -27,13 +24,12 @@
import android.view.ViewGroup;
import android.widget.TextView;
-import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.views.ActivityContext;
@@ -139,31 +135,24 @@
protected final LayoutInflater mLayoutInflater;
protected final OnClickListener mOnIconClickListener;
- protected OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
+ protected final OnLongClickListener mOnIconLongClickListener;
protected OnFocusChangeListener mIconFocusListener;
private final int mExtraTextHeight;
public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
- Resources res = activityContext.getResources();
mActivityContext = activityContext;
mApps = apps;
mLayoutInflater = inflater;
mOnIconClickListener = mActivityContext.getItemOnClickListener();
+ mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
mAdapterProvider = adapterProvider;
mExtraTextHeight = Utilities.calculateTextHeight(
mActivityContext.getDeviceProfile().allAppsIconTextSizePx);
}
- /**
- * Sets the long click listener for icons
- */
- public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
- mOnIconLongClickListener = listener;
- }
-
/** Checks if the passed viewType represents all apps divider. */
public static boolean isDividerViewType(int viewType) {
return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index d78e453..5e48177 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -102,6 +102,12 @@
StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
+ // Special case to not expand the search bar when exiting All Apps on phones.
+ if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
+ && mActivityContext.getDeviceProfile().isPhone) {
+ return LauncherState.ALL_APPS.getFloatingSearchBarRestingMarginStart(mActivityContext);
+ }
+
if (stateManager.isInTransition() && stateManager.getTargetState() != null) {
return stateManager.getTargetState()
.getFloatingSearchBarRestingMarginStart(mActivityContext);
@@ -118,6 +124,12 @@
StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
+ // Special case to not expand the search bar when exiting All Apps on phones.
+ if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
+ && mActivityContext.getDeviceProfile().isPhone) {
+ return LauncherState.ALL_APPS.getFloatingSearchBarRestingMarginEnd(mActivityContext);
+ }
+
if (stateManager.isInTransition() && stateManager.getTargetState() != null) {
return stateManager.getTargetState()
.getFloatingSearchBarRestingMarginEnd(mActivityContext);
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 44c233f..1ac8d87 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -25,7 +25,6 @@
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.os.Build;
@@ -47,7 +46,6 @@
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
import java.lang.annotation.Retention;
@@ -144,10 +142,6 @@
}
private void updateCurrentState(@WorkProfileState int currentState) {
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "WorkProfileManager#updateCurrentState: " +
- currentState, new Throwable());
- }
mCurrentState = currentState;
if (getAH() != null) {
getAH().mAppsList.updateAdapterItems();
@@ -166,10 +160,6 @@
* Creates and attaches for profile toggle button to {@link ActivityAllAppsContainerView}
*/
public boolean attachWorkModeSwitch() {
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "ActivityAllAppsContainerView#attachWorkModeSwitch "
- + "mWorkModeSwitch: " + mWorkModeSwitch);
- }
if (!mAllApps.getAppsStore().hasModelFlag(
FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)) {
Log.e(TAG, "unable to attach work mode switch; Missing required permissions");
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index df24620..a070284 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -250,11 +250,6 @@
+ "taskbar flavors");
// TODO(Block 18): Clean up flags
- public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(270395567,
- "ENABLE_LAUNCH_FROM_STAGED_APP", ENABLED,
- "Enable the ability to tap a staged app during split select to launch it in full "
- + "screen");
-
public static final BooleanFlag ENABLE_APP_PAIRS = getDebugFlag(274189428,
"ENABLE_APP_PAIRS", DISABLED,
"Enables the ability to create and save app pairs on the Home screen for easy"
@@ -401,6 +396,12 @@
"ENABLE_RESPONSIVE_WORKSPACE", DISABLED,
"Enables new workspace grid calculations method.");
+ // TODO(Block 33): Clean up flags
+
+ public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
+ "ENABLE_ALL_APPS_RV_PREINFLATION", DISABLED,
+ "Enables preinflating all apps icons to avoid scrolling jank.");
+
public static class BooleanFlag {
private final boolean mCurrentValue;
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index 7bdec1c..0f3cad6 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -16,6 +16,8 @@
package com.android.launcher3.dragndrop;
+import static android.content.pm.LauncherApps.EXTRA_PIN_ITEM_REQUEST;
+
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
@@ -25,6 +27,7 @@
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.PackageManager;
@@ -41,6 +44,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.util.StartActivityParams;
import java.util.function.Supplier;
@@ -105,7 +109,11 @@
@Override
public boolean startConfigActivity(Activity activity, int requestCode) {
- return false;
+ new StartActivityParams(activity, requestCode).deliverResult(
+ activity,
+ Activity.RESULT_OK,
+ new Intent().putExtra(EXTRA_PIN_ITEM_REQUEST, mRequestSupplier.get()));
+ return true;
}
@Override
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index 866e222..97f540e 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.model;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
-
import android.util.Log;
import androidx.annotation.NonNull;
@@ -33,7 +30,6 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -77,7 +73,6 @@
@Override
public final void run() {
boolean isModelLoaded = Objects.requireNonNull(mModel).isModelLoaded();
- testLogD(WORK_TAB_MISSING, "modelLoaded: " + isModelLoaded + " forTask: " + this);
if (!isModelLoaded) {
if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
@@ -115,10 +110,6 @@
List<WorkspaceItemInfo> workspaceUpdates = allUpdates.stream()
.filter(info -> info.id != ItemInfo.NO_ID)
.collect(Collectors.toList());
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "allUpdates: " + allUpdates.size() + ", workspaceUpdates "
- + workspaceUpdates.size());
- }
if (!workspaceUpdates.isEmpty()) {
scheduleCallbackTask(c -> c.bindWorkspaceItemsChanged(workspaceUpdates));
}
@@ -157,12 +148,7 @@
}
public void bindApplicationsIfNeeded() {
- boolean changeFlag = mAllAppsList.getAndResetChangeFlag();
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "bindApplicationsIfNeeded changeFlag? " +
- changeFlag);
- }
- if (changeFlag) {
+ if (mAllAppsList.getAndResetChangeFlag()) {
AppInfo[] apps = mAllAppsList.copyData();
int flags = mAllAppsList.getFlags();
Map<PackageUserKey, Integer> packageUserKeytoUidMap = Arrays.stream(apps).collect(
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 3daf4af..787ac38 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -24,8 +24,6 @@
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
@@ -932,7 +930,6 @@
}
private List<LauncherActivityInfo> loadAllApps() {
- testLogD(WORK_TAB_MISSING, "loadingAllApps");
final List<UserHandle> profiles = mUserCache.getUserProfiles();
List<LauncherActivityInfo> allActivityList = new ArrayList<>();
// Clear the list of apps
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 8c938f4..2591550 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -93,11 +93,6 @@
mOp = op;
mUser = user;
mPackages = packages;
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WORK_TAB_MISSING, "PackageUpdatedTask mOp: " + mOp +
- " packageCount: " + mPackages.length + " user: " + user);
- DEBUG = true;
- }
}
@Override
@@ -142,9 +137,6 @@
// The update may have changed which shortcuts/widgets are available.
// Refresh the widgets for the package if we have an activity running.
Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WORK_TAB_MISSING, "launcher: " + launcher);
- }
if (launcher != null) {
launcher.refreshAndBindWidgetsForPackageUser(
new PackageUserKey(packages[i], mUser));
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index cb78138..63ca35b 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -16,12 +16,10 @@
package com.android.launcher3.model;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
-import android.util.Log;
import androidx.annotation.NonNull;
@@ -31,7 +29,6 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -63,10 +60,6 @@
if (mIsUserUnlocked) {
QueryResult shortcuts = new ShortcutRequest(context, mUser)
.query(ShortcutRequest.PINNED);
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "shortcutQuery success? "
- + shortcuts.wasSuccess());
- }
if (shortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : shortcuts) {
pinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut);
@@ -89,9 +82,6 @@
if (mIsUserUnlocked) {
ShortcutKey key = ShortcutKey.fromItemInfo(si);
ShortcutInfo shortcut = pinnedShortcuts.get(key);
- if (TestProtocol.sDebugTracing) {
- Log.d(WORK_TAB_MISSING, "shortcutInfo: " + shortcut);
- }
// We couldn't verify the shortcut during loader. If its no longer available
// (probably due to clear data), delete the workspace item as well
if (shortcut == null) {
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index c313886..92822ab 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -17,8 +17,6 @@
package com.android.launcher3.pm;
import static com.android.launcher3.Utilities.ATLEAST_U;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.Context;
@@ -94,8 +92,6 @@
@AnyThread
private void onUsersChanged(Intent intent) {
- testLogD(WORK_TAB_MISSING, "onUsersChanged intent: " + intent);
-
MODEL_EXECUTOR.execute(this::updateCache);
UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
if (user == null) {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 08be026..e0f245f 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -673,10 +673,6 @@
}
mIsOpen = false;
- mOpenCloseAnimator = getOpenCloseAnimator(false, mCloseDuration, mCloseFadeStartDelay,
- mCloseFadeDuration, mCloseChildFadeStartDelay, mCloseChildFadeDuration,
- ACCELERATED_EASE);
-
mOpenCloseAnimator = ENABLE_MATERIAL_U_POPUP.get()
? getMaterialUOpenCloseAnimator(
false,
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 8274789..1f26bab 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -125,6 +125,14 @@
this(context, null, 0);
}
+ @Override
+ protected View getAccessibilityInitialFocusView() {
+ if (mSystemShortcutContainer != null) {
+ return mSystemShortcutContainer.getChildAt(0);
+ }
+ return super.getAccessibilityInitialFocusView();
+ }
+
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
return mAccessibilityDelegate;
}
@@ -242,7 +250,6 @@
popupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
}
- launcher.tryClearAccessibilityFocus(icon);
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
container.requestFocus();
return container;
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
new file mode 100644
index 0000000..26dde29
--- /dev/null
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.recyclerview
+
+import android.content.Context
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import com.android.launcher3.BubbleTextView
+import com.android.launcher3.allapps.BaseAllAppsAdapter
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
+import com.android.launcher3.views.ActivityContext
+import java.util.concurrent.Future
+
+private const val PREINFLATE_ICONS_ROW_COUNT = 4
+private const val EXTRA_ICONS_COUNT = 2
+
+/**
+ * An [RecycledViewPool] that preinflates app icons ([ViewHolder] of [BubbleTextView]) of all apps
+ * [RecyclerView]. The view inflation will happen on background thread and inflated [ViewHolder]s
+ * will be added to [RecycledViewPool] on main thread.
+ */
+class AllAppsRecyclerViewPool<T> : RecycledViewPool() {
+
+ private var future: Future<Void>? = null
+
+ /**
+ * Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
+ */
+ fun <T> preInflateAllAppsViewHolders(context: T) where T : Context, T : ActivityContext {
+ val appsView = context.appsView ?: return
+ val activeRv: RecyclerView = appsView.activeRecyclerView ?: return
+ val preInflateCount = getPreinflateCount(context)
+ if (preInflateCount <= 0) {
+ return
+ }
+
+ // Because we perform onCreateViewHolder() on worker thread, we need a separate
+ // adapter/inflator object as they are not thread-safe. Note that the adapter
+ // just need to perform onCreateViewHolder(parent, VIEW_TYPE_ICON) so it doesn't need
+ // data source information.
+ val adapter: RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> =
+ object : BaseAllAppsAdapter<T>(context, context.appsView.layoutInflater, null, null) {
+ override fun setAppsPerRow(appsPerRow: Int) = Unit
+ override fun getLayoutManager(): RecyclerView.LayoutManager? = null
+ }
+
+ // Inflate view holders on background thread, and added to view pool on main thread.
+ future?.cancel(true)
+ future =
+ VIEW_PREINFLATION_EXECUTOR.submit<Void> {
+ val viewHolders =
+ Array(preInflateCount) {
+ adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
+ }
+ MAIN_EXECUTOR.execute {
+ for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
+ putRecycledView(viewHolders[i])
+ }
+ }
+ null
+ }
+ }
+
+ /**
+ * After testing on phone, foldable and tablet, we found [PREINFLATE_ICONS_ROW_COUNT] rows of
+ * app icons plus [EXTRA_ICONS_COUNT] is the magic minimal count of app icons to preinflate to
+ * suffice fast scrolling.
+ */
+ fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
+ val targetPreinflateCount =
+ PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
+ EXTRA_ICONS_COUNT
+ val existingPreinflateCount = getRecycledViewCount(BaseAllAppsAdapter.VIEW_TYPE_ICON)
+ return targetPreinflateCount - existingPreinflateCount
+ }
+}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 458f137..e751730 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -72,7 +72,7 @@
implements BgDataModel.Callbacks, DragController.DragListener {
private LauncherModel mModel;
- private BaseDragLayer mDragLayer;
+ private SecondaryDragLayer mDragLayer;
private SecondaryDragController mDragController;
private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView;
private View mAppsButton;
@@ -314,10 +314,6 @@
}
}
- public SecondaryDisplayPredictions getSecondaryDisplayPredictions() {
- return mSecondaryDisplayPredictions;
- }
-
@Override
public StringCache getStringCache() {
return mStringCache;
@@ -337,6 +333,11 @@
return this::onIconClicked;
}
+ @Override
+ public View.OnLongClickListener getAllAppsItemLongClickListener() {
+ return mDragLayer::onIconLongClicked;
+ }
+
private void onIconClicked(View v) {
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
index 21c50d3..a58916a 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
@@ -16,10 +16,8 @@
package com.android.launcher3.secondarydisplay;
import android.content.Context;
-import android.view.View;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -47,12 +45,4 @@
*/
public void setPredictedApps(BgDataModel.FixedContainerItems item) {
}
-
- /**
- * Set long click listener for predicted apps in top of app drawer.
- */
- public void setLongClickListener(
- ActivityAllAppsContainerView<?> appsView,
- View.OnLongClickListener onIconLongClickListener) {
- }
}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 87afcab..717164e 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -79,9 +79,6 @@
mAllAppsButton = findViewById(R.id.all_apps_button);
mAppsView = findViewById(R.id.apps_view);
- mAppsView.setOnIconLongClickListener(this::onIconLongClicked);
- mActivity.getSecondaryDisplayPredictions()
- .setLongClickListener(mAppsView, this::onIconLongClicked);
// Setup workspace
mWorkspace = findViewById(R.id.workspace_grid);
mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
@@ -179,7 +176,7 @@
return mPinnedAppsAdapter;
}
- private boolean onIconLongClicked(View v) {
+ boolean onIconLongClicked(View v) {
if (!(v instanceof BubbleTextView)) {
return false;
}
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 9188c2e..0eb0e08 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -29,9 +29,9 @@
*/
@JvmStatic
fun getTaskbarPhoneDimensions(
- deviceProfile: DeviceProfile,
- res: Resources,
- isPhoneMode: Boolean
+ deviceProfile: DeviceProfile,
+ res: Resources,
+ isPhoneMode: Boolean
): Point {
val p = Point()
// Taskbar for large screen
diff --git a/src/com/android/launcher3/util/Executors.java b/src/com/android/launcher3/util/Executors.java
index 6978e0c..dec4b5c 100644
--- a/src/com/android/launcher3/util/Executors.java
+++ b/src/com/android/launcher3/util/Executors.java
@@ -21,6 +21,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
@@ -58,6 +59,11 @@
new LooperExecutor(
createAndStartNewLooper("UiThreadHelper", Process.THREAD_PRIORITY_FOREGROUND));
+
+ /** A background executor to preinflate views. */
+ public static final ExecutorService VIEW_PREINFLATION_EXECUTOR =
+ java.util.concurrent.Executors.newSingleThreadExecutor();
+
/**
* Utility method to get a started handler thread statically
*/
diff --git a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java b/src/com/android/launcher3/util/StartActivityParams.java
similarity index 94%
rename from quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
rename to src/com/android/launcher3/util/StartActivityParams.java
index 4d0bee6..b48562f 100644
--- a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
+++ b/src/com/android/launcher3/util/StartActivityParams.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3.proxy;
+package com.android.launcher3.util;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
@@ -34,6 +34,9 @@
import android.os.Parcelable;
import android.util.Log;
+/**
+ * Wrapper class for parameters to start an activity.
+ */
public class StartActivityParams implements Parcelable {
private static final String TAG = "StartActivityParams";
@@ -93,6 +96,7 @@
parcel.writeBundle(options);
}
+ /** Perform the operation on the pendingIntent. */
public void deliverResult(Context context, int resultCode, Intent data) {
ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
try {
@@ -105,7 +109,7 @@
}
public static final Parcelable.Creator<StartActivityParams> CREATOR =
- new Parcelable.Creator<StartActivityParams>() {
+ new Parcelable.Creator<>() {
public StartActivityParams createFromParcel(Parcel source) {
return new StartActivityParams(source);
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index d04f5e2..84ea871 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -239,6 +239,11 @@
};
}
+ /** Long-click callback used for All Apps items. */
+ default View.OnLongClickListener getAllAppsItemLongClickListener() {
+ return v -> false;
+ }
+
@Nullable
default PopupDataProvider getPopupDataProvider() {
return null;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index a3ef6e1..c9cd4b6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -891,6 +891,19 @@
return false;
}
+ /** Gets the sheet for widget picker, which is used for testing. */
+ @VisibleForTesting
+ public View getSheet() {
+ return mContent;
+ }
+
+ /** Opens the first header in widget picker and scrolls to the top of the RecyclerView. */
+ @VisibleForTesting
+ public void openFirstHeader() {
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.selectFirstHeaderEntry();
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
+ }
+
/** A holder class for holding adapters & their corresponding recycler view. */
final class AdapterHolder {
static final int PRIMARY = 0;
diff --git a/tests/Android.bp b/tests/Android.bp
index d518a0e..e7f4084 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -58,7 +58,6 @@
"src/com/android/launcher3/util/rule/SimpleActivityRule.java",
"src/com/android/launcher3/util/rule/TestStabilityRule.java",
"src/com/android/launcher3/util/rule/TISBindRule.java",
- "src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java",
"src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
"src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
"src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index b170061..c8b5a20 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -41,6 +41,17 @@
</receiver>
<receiver
+ android:name="com.android.launcher3.testcomponent.AppWidgetNoConfigLarge"
+ android:exported="true"
+ android:label="No Config Large">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_no_config_large"/>
+ </receiver>
+
+ <receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
android:exported="true"
android:label="Hidden widget">
diff --git a/tests/res/xml/appwidget_no_config_large.xml b/tests/res/xml/appwidget_no_config_large.xml
new file mode 100644
index 0000000..b3b69d9
--- /dev/null
+++ b/tests/res/xml/appwidget_no_config_large.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<appwidget-provider
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="1dp"
+ android:minHeight="1dp"
+ android:minResizeWidth="1dp"
+ android:maxResizeWidth="3000dp"
+ android:targetCellHeight="1"
+ android:targetCellWidth="5"
+ android:updatePeriodMillis="86400000"
+ android:initialLayout="@layout/test_layout_appwidget_red"
+ android:previewLayout="@layout/test_layout_appwidget_red"
+ android:resizeMode="horizontal|vertical"
+ android:widgetCategory="home_screen">
+</appwidget-provider>
\ No newline at end of file
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 36e4e76..4073517 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -110,6 +110,7 @@
public static final String REQUEST_GET_TEST_EVENTS = "get-test-events";
public static final String REQUEST_GET_HAD_NONTEST_EVENTS = "get-had-nontest-events";
public static final String REQUEST_STOP_EVENT_LOGGING = "stop-event-logging";
+ public static final String REQUEST_REINITIALIZE_DATA = "reinitialize-data";
public static final String REQUEST_CLEAR_DATA = "clear-data";
public static final String REQUEST_HOTSEAT_ICON_NAMES = "get-hotseat-icon-names";
public static final String REQUEST_IS_TABLET = "is-tablet";
@@ -153,7 +154,6 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
- public static final String WORK_TAB_MISSING = "b/243688989";
public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String FLAKY_ACTIVITY_COUNT = "b/260260325";
public static final String ICON_MISSING = "b/282963545";
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index ee05fe6..91a0634 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -164,7 +164,7 @@
Context c = new ActivityContextWrapper(getApplicationContext());
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
mPrevNumColumns = dp.inv.numColumns;
- mPrevNumRows = dp.inv.numColumns;
+ mPrevNumRows = dp.inv.numRows;
}
@After
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index 0a95771..270672f 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -64,8 +64,8 @@
"\tinv.numColumns: 5\n" +
"\tinv.numSearchContainerColumns: 5\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 165.0px (62.857143dp)\n" +
- "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 229.0px (87.2381dp)\n" +
"\tgetCellSize().x: 207.0px (78.85714dp)\n" +
"\tgetCellSize().y: 379.0px (144.38095dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -76,14 +76,14 @@
"\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
"\ticonSizePx: 147.0px (56.0dp)\n" +
"\ticonTextSizePx: 38.0px (14.476191dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 12.0px (4.571429dp)\n" +
"\tinv.numFolderRows: 4\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
"\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
"\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
"\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -139,8 +139,8 @@
"\tworkspacePadding.bottom: 203.0px (77.333336dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 722.0px (275.0476dp)\n" +
- "\tunscaled extraSpace: 722.0px (275.0476dp)\n" +
+ "\textraSpace: 752.0px (286.4762dp)\n" +
+ "\tunscaled extraSpace: 752.0px (286.4762dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -201,8 +201,8 @@
"\tinv.numColumns: 5\n" +
"\tinv.numSearchContainerColumns: 5\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 165.0px (62.857143dp)\n" +
- "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 229.0px (87.2381dp)\n" +
"\tgetCellSize().x: 207.0px (78.85714dp)\n" +
"\tgetCellSize().y: 383.0px (145.90475dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -213,14 +213,14 @@
"\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
"\ticonSizePx: 147.0px (56.0dp)\n" +
"\ticonTextSizePx: 38.0px (14.476191dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 12.0px (4.571429dp)\n" +
"\tinv.numFolderRows: 4\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
"\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
"\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
"\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -276,8 +276,8 @@
"\tworkspacePadding.bottom: 245.0px (93.333336dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 743.0px (283.0476dp)\n" +
- "\tunscaled extraSpace: 743.0px (283.0476dp)\n" +
+ "\textraSpace: 773.0px (294.4762dp)\n" +
+ "\tunscaled extraSpace: 773.0px (294.4762dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -338,7 +338,7 @@
"\tinv.numColumns: 5\n" +
"\tinv.numSearchContainerColumns: 5\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+ "\tcellWidthPx: 152.0px (57.904762dp)\n" +
"\tcellHeightPx: 166.0px (63.238094dp)\n" +
"\tgetCellSize().x: 368.0px (140.19048dp)\n" +
"\tgetCellSize().y: 193.0px (73.52381dp)\n" +
@@ -357,7 +357,7 @@
"\tfolderCellHeightPx: 205.0px (78.09524dp)\n" +
"\tfolderChildIconSizePx: 131.0px (49.904762dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
- "\tfolderChildDrawablePaddingPx: 9.0px (3.4285715dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 4.0px (1.5238096dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -475,7 +475,7 @@
"\tinv.numColumns: 5\n" +
"\tinv.numSearchContainerColumns: 5\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+ "\tcellWidthPx: 152.0px (57.904762dp)\n" +
"\tcellHeightPx: 166.0px (63.238094dp)\n" +
"\tgetCellSize().x: 393.0px (149.71428dp)\n" +
"\tgetCellSize().y: 180.0px (68.57143dp)\n" +
@@ -494,7 +494,7 @@
"\tfolderCellHeightPx: 192.0px (73.14286dp)\n" +
"\tfolderChildIconSizePx: 123.0px (46.857143dp)\n" +
"\tfolderChildTextSizePx: 32.0px (12.190476dp)\n" +
- "\tfolderChildDrawablePaddingPx: 8.0px (3.047619dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 3.0px (1.1428572dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -625,14 +625,14 @@
"\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
"\ticonSizePx: 120.0px (60.0dp)\n" +
"\ticonTextSizePx: 28.0px (14.0dp)\n" +
- "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 3\n" +
"\tfolderCellWidthPx: 240.0px (120.0dp)\n" +
"\tfolderCellHeightPx: 208.0px (104.0dp)\n" +
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
- "\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 11.0px (5.5dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -649,7 +649,7 @@
"\tallAppsCloseDuration: 500\n" +
"\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
"\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
- "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
"\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
"\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
@@ -763,14 +763,14 @@
"\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
"\ticonSizePx: 120.0px (60.0dp)\n" +
"\ticonTextSizePx: 28.0px (14.0dp)\n" +
- "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 3\n" +
"\tfolderCellWidthPx: 240.0px (120.0dp)\n" +
"\tfolderCellHeightPx: 208.0px (104.0dp)\n" +
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
- "\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 11.0px (5.5dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -787,7 +787,7 @@
"\tallAppsCloseDuration: 500\n" +
"\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
"\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
- "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
"\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
"\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
@@ -901,14 +901,14 @@
"\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
"\ticonSizePx: 120.0px (60.0dp)\n" +
"\ticonTextSizePx: 28.0px (14.0dp)\n" +
- "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 3\n" +
"\tfolderCellWidthPx: 204.0px (102.0dp)\n" +
"\tfolderCellHeightPx: 240.0px (120.0dp)\n" +
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
- "\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 22.0px (11.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -925,7 +925,7 @@
"\tallAppsCloseDuration: 500\n" +
"\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
"\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
- "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
"\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
"\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
@@ -1039,14 +1039,14 @@
"\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
"\ticonSizePx: 120.0px (60.0dp)\n" +
"\ticonTextSizePx: 28.0px (14.0dp)\n" +
- "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\ticonDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 3\n" +
"\tfolderCellWidthPx: 204.0px (102.0dp)\n" +
"\tfolderCellHeightPx: 240.0px (120.0dp)\n" +
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
- "\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 22.0px (11.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
@@ -1063,7 +1063,7 @@
"\tallAppsCloseDuration: 500\n" +
"\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
"\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
- "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 9.0px (4.5dp)\n" +
"\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
"\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
"\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
@@ -1170,8 +1170,8 @@
"\tinv.numColumns: 4\n" +
"\tinv.numSearchContainerColumns: 4\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 159.0px (60.57143dp)\n" +
- "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+ "\tcellHeightPx: 218.0px (83.04762dp)\n" +
"\tgetCellSize().x: 270.0px (102.85714dp)\n" +
"\tgetCellSize().y: 342.0px (130.28572dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1182,14 +1182,14 @@
"\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
"\ticonSizePx: 141.0px (53.714287dp)\n" +
"\ticonTextSizePx: 34.0px (12.952381dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
"\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1245,8 +1245,8 @@
"\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 478.0px (182.09525dp)\n" +
- "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+ "\textraSpace: 498.0px (189.71428dp)\n" +
+ "\tunscaled extraSpace: 498.0px (189.71428dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1312,8 +1312,8 @@
"\tinv.numColumns: 4\n" +
"\tinv.numSearchContainerColumns: 4\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 159.0px (60.57143dp)\n" +
- "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+ "\tcellHeightPx: 218.0px (83.04762dp)\n" +
"\tgetCellSize().x: 270.0px (102.85714dp)\n" +
"\tgetCellSize().y: 342.0px (130.28572dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1324,14 +1324,14 @@
"\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
"\ticonSizePx: 141.0px (53.714287dp)\n" +
"\ticonTextSizePx: 34.0px (12.952381dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
"\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1387,8 +1387,8 @@
"\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 478.0px (182.09525dp)\n" +
- "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+ "\textraSpace: 498.0px (189.71428dp)\n" +
+ "\tunscaled extraSpace: 498.0px (189.71428dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1454,8 +1454,8 @@
"\tinv.numColumns: 4\n" +
"\tinv.numSearchContainerColumns: 4\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 159.0px (60.57143dp)\n" +
- "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+ "\tcellHeightPx: 218.0px (83.04762dp)\n" +
"\tgetCellSize().x: 224.0px (85.333336dp)\n" +
"\tgetCellSize().y: 430.0px (163.80952dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1466,14 +1466,14 @@
"\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
"\ticonSizePx: 141.0px (53.714287dp)\n" +
"\ticonTextSizePx: 34.0px (12.952381dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
"\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1529,8 +1529,8 @@
"\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 829.0px (315.8095dp)\n" +
- "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+ "\textraSpace: 849.0px (323.42856dp)\n" +
+ "\tunscaled extraSpace: 849.0px (323.42856dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
@@ -1592,8 +1592,8 @@
"\tinv.numColumns: 4\n" +
"\tinv.numSearchContainerColumns: 4\n" +
"\tminCellSize: PointF(0.0, 0.0)dp\n" +
- "\tcellWidthPx: 159.0px (60.57143dp)\n" +
- "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tcellWidthPx: 154.0px (58.666668dp)\n" +
+ "\tcellHeightPx: 218.0px (83.04762dp)\n" +
"\tgetCellSize().x: 224.0px (85.333336dp)\n" +
"\tgetCellSize().y: 430.0px (163.80952dp)\n" +
"\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
@@ -1604,14 +1604,14 @@
"\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
"\ticonSizePx: 141.0px (53.714287dp)\n" +
"\ticonTextSizePx: 34.0px (12.952381dp)\n" +
- "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\ticonDrawablePaddingPx: 13.0px (4.952381dp)\n" +
"\tinv.numFolderRows: 3\n" +
"\tinv.numFolderColumns: 4\n" +
"\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
"\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
- "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 5.0px (1.9047619dp)\n" +
"\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
"\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
@@ -1667,8 +1667,8 @@
"\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
"\ticonScale: 1.0px (0.3809524dp)\n" +
"\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
- "\textraSpace: 829.0px (315.8095dp)\n" +
- "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+ "\textraSpace: 849.0px (323.42856dp)\n" +
+ "\tunscaled extraSpace: 849.0px (323.42856dp)\n" +
"\tmaxEmptySpace: 0.0px (0.0dp)\n" +
"\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
"\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 7f796e7..a82b005 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -70,7 +70,6 @@
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.util.rule.ViewCaptureAnalysisRule;
import com.android.launcher3.util.rule.ViewCaptureRule;
import org.junit.After;
@@ -209,8 +208,7 @@
final RuleChain inner = RuleChain
.outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule)
- .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
+ .around(viewCaptureRule);
return TestHelpers.isInLauncherProcess()
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
@@ -293,8 +291,16 @@
}
}
- protected void clearLauncherData() {
- mLauncher.clearLauncherData();
+ protected void reinitializeLauncherData() {
+ reinitializeLauncherData(false);
+ }
+
+ protected void reinitializeLauncherData(boolean clearWorkspace) {
+ if (clearWorkspace) {
+ mLauncher.clearLauncherData();
+ } else {
+ mLauncher.reinitializeLauncherData();
+ }
mLauncher.waitForLauncherInitialized();
}
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index fdba4eb..ba17fdc 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -18,6 +18,8 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static com.android.launcher3.BubbleTextView.DISPLAY_ALL_APPS;
+import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS;
import static org.junit.Assert.assertEquals;
@@ -79,7 +81,6 @@
mContext = new ActivityContextWrapper(getApplicationContext());
mBubbleTextView = new BubbleTextView(mContext);
mBubbleTextView.reset();
- mBubbleTextView.setDisplayAllApps();
BubbleTextView testView = new BubbleTextView(mContext);
testView.setTypeface(Typeface.MONOSPACE);
@@ -104,6 +105,7 @@
public void testEmptyString_flagOn() {
try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
mItemInfoWithIcon.title = EMPTY_STRING;
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
@@ -118,6 +120,7 @@
public void testEmptyString_flagOff() {
try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
mItemInfoWithIcon.title = EMPTY_STRING;
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
@@ -134,6 +137,7 @@
// test string: "Battery Stats"
mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -149,6 +153,7 @@
// test string: "Battery Stats"
mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -164,6 +169,7 @@
// test string: "flutterappflorafy"
mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -179,6 +185,7 @@
// test string: "flutterappflorafy"
mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -194,6 +201,7 @@
// test string: "System UWB Field Test"
mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -209,6 +217,7 @@
// test string: "System UWB Field Test"
mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -224,6 +233,7 @@
// test string: "LEGO®Builder"
mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -239,6 +249,7 @@
// test string: "LEGO®Builder"
mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
@@ -291,4 +302,20 @@
breakPoints);
assertEquals(TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT, newString);
}
+
+ @Test
+ public void testEnsurePredictionRowIsOneLine() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
+ // test string: "Battery Stats"
+ mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, 0);
+ mBubbleTextView.onPreDraw();
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 2c8acc4..c1f2bb6 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -97,7 +97,12 @@
}
public static void initialize(AbstractLauncherUiTest test) throws Exception {
- test.clearLauncherData();
+ initialize(test, false);
+ }
+
+ public static void initialize(
+ AbstractLauncherUiTest test, boolean clearWorkspace) throws Exception {
+ test.reinitializeLauncherData(clearWorkspace);
test.mDevice.pressHome();
test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
test.waitForState("Launcher internal state didn't switch to Home",
@@ -248,7 +253,7 @@
LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
.atHotseat(0).putApp("com.android.chrome", "com.google.android.apps.chrome.Main");
mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, builder);
- clearLauncherData();
+ reinitializeLauncherData();
final Workspace workspace = mLauncher.getWorkspace();
@@ -557,7 +562,7 @@
allApps.unfreeze();
}
// Reset the workspace for the next shortcut creation.
- initialize(this);
+ initialize(this, true);
endTime = SystemClock.uptimeMillis();
elapsedTime = endTime - startTime;
Log.d("testDragAppIconToWorkspaceCellTime",
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 026766c..7237387 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
-import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
import static com.android.launcher3.util.TestUtil.installDummyAppForUser;
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
@@ -39,7 +38,6 @@
import com.android.launcher3.allapps.WorkPausedCard;
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
@@ -78,8 +76,6 @@
installDummyAppForUser(mProfileUserId);
updateWorkProfileSetupSuccessful("am start-user", output);
- Log.d(WORK_TAB_MISSING, "workProfileSuccessful? " + mWorkProfileSetupSuccessful +
- " shellCmd: " + logStr);
if (!mWorkProfileSetupSuccessful) {
return; // no need to setup launcher since all tests will skip.
}
@@ -96,7 +92,6 @@
@After
public void removeWorkProfile() throws Exception {
- Log.d(TestProtocol.WORK_TAB_MISSING, "WorkProfileTest teardown");
executeOnLauncher(launcher -> {
if (launcher == null || launcher.getAppsView() == null) {
return;
@@ -112,7 +107,6 @@
mLauncher.getAllApps();
waitForLauncherCondition("Work tab not setup", launcher -> {
if (launcher.getAppsView().getContentView() instanceof AllAppsPagedView) {
- Log.d(WORK_TAB_MISSING, "Deferring AppsStore updates");
launcher.getAppsView().getAppsStore().enableDeferUpdates(DEFER_UPDATES_TEST);
return true;
}
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java b/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java
deleted file mode 100644
index 702757f..0000000
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureAnalysisRule.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.rule;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-
-import com.android.app.viewcapture.ViewCapture;
-import com.android.app.viewcapture.data.ExportedData;
-
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-
-import java.util.concurrent.ExecutionException;
-
-/**
- * After the test succeeds, the rule looks for anomalies in the data accumulated by ViewCapture
- * that's passed as a parameter. If anomalies are detected, throws an exception and fails the test.
- */
-public class ViewCaptureAnalysisRule extends TestWatcher {
- @NonNull
- private final ViewCapture mViewCapture;
-
- public ViewCaptureAnalysisRule(@NonNull ViewCapture viewCapture) {
- mViewCapture = viewCapture;
- }
-
- @Override
- protected void succeeded(Description description) {
- super.succeeded(description);
- try {
- analyzeViewCaptureData(mViewCapture.getExportedData(
- InstrumentationRegistry.getTargetContext()));
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static void analyzeViewCaptureData(ExportedData viewCaptureData) {
- }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index 6c06502..8e2aea8 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -36,7 +36,7 @@
* This rule will not work in OOP tests that don't have access to the activity under test.
*/
class ViewCaptureRule(var alreadyOpenActivitySupplier: Supplier<Activity?>) : TestRule {
- val viewCapture = SimpleViewCapture("test-view-capture")
+ private val viewCapture = SimpleViewCapture("test-view-capture")
var viewCaptureData: ExportedData? = null
private set
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
new file mode 100644
index 0000000..e40fb79
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -0,0 +1,91 @@
+/*
+ * 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 static com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.diagPathFromRoot;
+
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnalysisNode;
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnomalyDetector;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Anomaly detector that triggers an error when alpha of a view changes too rapidly.
+ * Invisible views are treated as if they had zero alpha.
+ */
+final class AlphaJumpDetector extends AnomalyDetector {
+ // Paths of nodes that are excluded from analysis.
+ private static final Collection<String> PATHS_TO_IGNORE = Set.of(
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
+ + "/search_results_list_view|SearchResultSmallIconRow",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
+ + "/search_results_list_view|SearchResultIcon",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|LauncherRecentsView:id/overview_panel|TaskView",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
+ + "|WidgetsRecyclerView:id/primary_widgets_list_view|WidgetsListHeader:id"
+ + "/widgets_list_header",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
+ + "|WidgetsRecyclerView:id/primary_widgets_list_view"
+ + "|StickyHeaderLayout$EmptySpaceView",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|SearchContainerView:id/apps_view|AllAppsRecyclerView:id"
+ + "/apps_list_view|BubbleTextView:id/icon",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|LauncherRecentsView:id/overview_panel|ClearAllButton:id"
+ + "/clear_all",
+ "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
+ + ":id/drag_layer|NexusOverviewActionsView:id/overview_actions_view"
+ + "|LinearLayout:id/action_buttons"
+ );
+ // Minimal increase or decrease of view's alpha between frames that triggers the error.
+ private static final float ALPHA_JUMP_THRESHOLD = 1f;
+
+ @Override
+ void initializeNode(AnalysisNode info) {
+ // If the parent view ignores alpha jumps, its descendants will too.
+ final boolean parentIgnoreAlphaJumps = info.parent != null && info.parent.ignoreAlphaJumps;
+ info.ignoreAlphaJumps = parentIgnoreAlphaJumps
+ || PATHS_TO_IGNORE.contains(diagPathFromRoot(info));
+ }
+
+ @Override
+ void detectAnomalies(AnalysisNode oldInfo, AnalysisNode newInfo, int frameN) {
+ // 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;
+
+ final AnalysisNode latestInfo = newInfo != null ? newInfo : oldInfo;
+ if (latestInfo.ignoreAlphaJumps) return;
+
+ final float oldAlpha = oldInfo != null ? oldInfo.alpha : 0;
+ final float newAlpha = newInfo != null ? newInfo.alpha : 0;
+ final float alphaDeltaAbs = Math.abs(newAlpha - oldAlpha);
+
+ if (alphaDeltaAbs >= ALPHA_JUMP_THRESHOLD) {
+ throw new AssertionError(
+ String.format(
+ "Alpha jump detected in ViewCapture data: alpha change: %s (%s -> %s)"
+ + ", threshold: %s, view: %s",
+ alphaDeltaAbs, oldAlpha, newAlpha, ALPHA_JUMP_THRESHOLD, latestInfo));
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
new file mode 100644
index 0000000..5a2611c
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
@@ -0,0 +1,238 @@
+/*
+ * 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 static android.view.View.VISIBLE;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.app.viewcapture.data.ExportedData;
+import com.android.app.viewcapture.data.FrameData;
+import com.android.app.viewcapture.data.ViewNode;
+import com.android.app.viewcapture.data.WindowData;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility that analyzes ViewCapture data and finds anomalies such as views appearing or
+ * disappearing without alpha-fading.
+ */
+public class ViewCaptureAnalyzer {
+ private static final String SCRIM_VIEW_CLASS = "com.android.launcher3.views.ScrimView";
+
+ /**
+ * Detector of one kind of anomaly.
+ */
+ abstract static class AnomalyDetector {
+ /**
+ * Initializes fields of the node that are specific to the anomaly detected by this
+ * detector.
+ */
+ abstract void initializeNode(@NonNull AnalysisNode info);
+
+ /**
+ * Detects anomalies by looking at the last occurrence of a view, and the current one.
+ * 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 earlier
+ * frames.
+ * @param frameN number of the current frame.
+ */
+ abstract void detectAnomalies(
+ @Nullable AnalysisNode oldInfo, @Nullable AnalysisNode newInfo, int frameN);
+ }
+
+ // All detectors. They will be invoked in the order listed here.
+ private static final Iterable<AnomalyDetector> ANOMALY_DETECTORS = Arrays.asList(
+ new AlphaJumpDetector()
+ );
+
+ // A view from view capture data converted to a form that's convenient for detecting anomalies.
+ static class AnalysisNode {
+ public String className;
+ public String resourceId;
+ public AnalysisNode parent;
+
+ // Window coordinates of the view.
+ public float left;
+ public float top;
+
+ // Visible scale and alpha, build recursively from the ancestor list.
+ public float scaleX;
+ public float scaleY;
+ public float alpha;
+
+ public int frameN;
+ public ViewNode viewCaptureNode;
+
+ public boolean ignoreAlphaJumps;
+
+ @Override
+ public String toString() {
+ return String.format("window coordinates: (%s, %s), class path from the root: %s",
+ left, top, diagPathFromRoot(this));
+ }
+ }
+
+ /**
+ * Scans a view capture record and throws an error if an anomaly is found.
+ */
+ public static void assertNoAnomalies(ExportedData viewCaptureData) {
+ final int scrimClassIndex = viewCaptureData.getClassnameList().indexOf(SCRIM_VIEW_CLASS);
+
+ final int windowDataCount = viewCaptureData.getWindowDataCount();
+ for (int i = 0; i < windowDataCount; ++i) {
+ analyzeWindowData(viewCaptureData, viewCaptureData.getWindowData(i), scrimClassIndex);
+ }
+ }
+
+ private static void analyzeWindowData(ExportedData viewCaptureData, WindowData windowData,
+ int scrimClassIndex) {
+ // View hash code => Last seen node with this hash code.
+ // The view is added when we analyze the first frame where it's visible.
+ // After that, it gets updated for every frame where it's visible.
+ // As we go though frames, if a view becomes invisible, it stays in the map.
+ final Map<Integer, AnalysisNode> lastSeenNodes = new HashMap<>();
+
+ for (int frameN = 0; frameN < windowData.getFrameDataCount(); ++frameN) {
+ analyzeFrame(frameN, windowData.getFrameData(frameN), viewCaptureData, lastSeenNodes,
+ scrimClassIndex);
+ }
+ }
+
+ private static void analyzeFrame(int frameN, FrameData frame, ExportedData viewCaptureData,
+ Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex) {
+ // Analyze the node tree starting from the root.
+ analyzeView(
+ frame.getNode(),
+ /* parent = */ null,
+ frameN,
+ /* leftShift = */ 0,
+ /* topShift = */ 0,
+ viewCaptureData,
+ lastSeenNodes,
+ scrimClassIndex);
+
+ // Analyze transitions when a view visible in the last frame become invisible in the
+ // current one.
+ for (AnalysisNode info : lastSeenNodes.values()) {
+ if (info.frameN == frameN - 1) {
+ if (!info.viewCaptureNode.getWillNotDraw()) {
+ ANOMALY_DETECTORS.forEach(
+ detector -> detector.detectAnomalies(
+ /* oldInfo = */ info,
+ /* newInfo = */ null,
+ frameN));
+ }
+ }
+ }
+ }
+
+ private static void analyzeView(ViewNode viewCaptureNode, AnalysisNode parent, int frameN,
+ float leftShift, float topShift, ExportedData viewCaptureData,
+ Map<Integer, AnalysisNode> lastSeenNodes, int scrimClassIndex) {
+ // Skip analysis of invisible views
+ final float parentAlpha = parent != null ? parent.alpha : 1;
+ final float alpha = getVisibleAlpha(viewCaptureNode, parentAlpha);
+ if (alpha <= 0.0) return;
+
+ // Calculate analysis node parameters
+ final int hashcode = viewCaptureNode.getHashcode();
+ final int classIndex = viewCaptureNode.getClassnameIndex();
+
+ final float parentScaleX = parent != null ? parent.scaleX : 1;
+ final float parentScaleY = parent != null ? parent.scaleY : 1;
+ final float scaleX = parentScaleX * viewCaptureNode.getScaleX();
+ final float scaleY = parentScaleY * viewCaptureNode.getScaleY();
+
+ final float left = leftShift
+ + (viewCaptureNode.getLeft() + viewCaptureNode.getTranslationX()) * parentScaleX
+ + viewCaptureNode.getWidth() * (parentScaleX - scaleX) / 2;
+ final float top = topShift
+ + (viewCaptureNode.getTop() + viewCaptureNode.getTranslationY()) * parentScaleY
+ + viewCaptureNode.getHeight() * (parentScaleY - scaleY) / 2;
+
+ // Initialize new analysis node
+ final AnalysisNode newAnalysisNode = new AnalysisNode();
+ newAnalysisNode.className = viewCaptureData.getClassname(classIndex);
+ newAnalysisNode.resourceId = viewCaptureNode.getId();
+ newAnalysisNode.parent = parent;
+ newAnalysisNode.left = left;
+ newAnalysisNode.top = top;
+ newAnalysisNode.scaleX = scaleX;
+ newAnalysisNode.scaleY = scaleY;
+ newAnalysisNode.alpha = alpha;
+ newAnalysisNode.frameN = frameN;
+ newAnalysisNode.viewCaptureNode = viewCaptureNode;
+ ANOMALY_DETECTORS.forEach(detector -> detector.initializeNode(newAnalysisNode));
+
+ // Detect anomalies for the view
+ final AnalysisNode oldAnalysisNode = lastSeenNodes.get(hashcode); // may be null
+ if (frameN != 0 && !viewCaptureNode.getWillNotDraw()) {
+ ANOMALY_DETECTORS.forEach(
+ detector -> detector.detectAnomalies(oldAnalysisNode, newAnalysisNode, frameN));
+ }
+ lastSeenNodes.put(hashcode, newAnalysisNode);
+
+ // Enumerate children starting from the topmost one. Stop at ScrimView, if present.
+ final float leftShiftForChildren = left - viewCaptureNode.getScrollX();
+ final float topShiftForChildren = top - viewCaptureNode.getScrollY();
+ for (int i = viewCaptureNode.getChildrenCount() - 1; i >= 0; --i) {
+ final ViewNode child = viewCaptureNode.getChildren(i);
+
+ // Don't analyze anything under scrim view because we don't know whether it's
+ // transparent.
+ if (child.getClassnameIndex() == scrimClassIndex) break;
+
+ analyzeView(child, newAnalysisNode, frameN, leftShiftForChildren, topShiftForChildren,
+ viewCaptureData, lastSeenNodes,
+ scrimClassIndex);
+ }
+ }
+
+ private static float getVisibleAlpha(ViewNode node, float parenVisibleAlpha) {
+ return node.getVisibility() == VISIBLE
+ ? parenVisibleAlpha * Math.max(0, Math.min(node.getAlpha(), 1))
+ : 0f;
+ }
+
+ private static String classNameToSimpleName(String className) {
+ return className.substring(className.lastIndexOf(".") + 1);
+ }
+
+ static String diagPathFromRoot(AnalysisNode nodeBox) {
+ final StringBuilder path = new StringBuilder(diagPathElement(nodeBox));
+ for (AnalysisNode ancestor = nodeBox.parent; ancestor != null; ancestor = ancestor.parent) {
+ path.insert(0, diagPathElement(ancestor) + "|");
+ }
+ return path.toString();
+ }
+
+ private static String diagPathElement(AnalysisNode nodeBox) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(classNameToSimpleName(nodeBox.className));
+ if (!"NO_ID".equals(nodeBox.resourceId)) sb.append(":" + nodeBox.resourceId);
+ return sb.toString();
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 2286d7e..ce50e22 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.DONT_KILL_APP;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
@@ -197,11 +198,18 @@
private boolean mCheckEventsForSuccessfulGestures = false;
private Runnable mOnLauncherCrashed;
+ private boolean mSwipeFromTrackpad = false;
+ private int mPointerCount = 0;
+
private static Pattern getTouchEventPattern(String prefix, String action) {
- // The pattern includes checks that we don't get a multi-touch events or other surprises.
+ return getTouchEventPattern(prefix, action, 1);
+ }
+
+ private static Pattern getTouchEventPattern(String prefix, String action, int pointerCount) {
return Pattern.compile(
prefix + ": MotionEvent.*?action=" + action + ".*?id\\[0\\]=0"
- + ".*?toolType\\[0\\]=TOOL_TYPE_FINGER.*?buttonState=0.*?pointerCount=1");
+ + ".*?toolType\\[0\\]=TOOL_TYPE_FINGER.*?buttonState=0.*?pointerCount="
+ + pointerCount);
}
private static Pattern getTouchEventPattern(String action) {
@@ -212,6 +220,10 @@
return getTouchEventPattern("TouchInteractionService.onInputEvent", action);
}
+ private static Pattern getTouchEventPatternTIS(String action, int pointerCount) {
+ return getTouchEventPattern("TouchInteractionService.onInputEvent", action, pointerCount);
+ }
+
private static Pattern getKeyEventPattern(String action, String keyCode) {
return Pattern.compile("Key event: KeyEvent.*action=" + action + ".*keyCode=" + keyCode);
}
@@ -703,6 +715,10 @@
mIgnoreTaskbarVisibility = ignoreTaskbarVisibility;
}
+ public void setSwipeFromTrackpad(boolean swipeFromTrackpad) {
+ mSwipeFromTrackpad = swipeFromTrackpad;
+ }
+
/**
* Sets expected rotation.
* TAPL periodically checks that Launcher didn't suddenly change the rotation to unexpected one.
@@ -993,7 +1009,7 @@
// otherwise waitForIdle may return immediately in case when there was a big enough
// pause in accessibility events prior to pressing Home.
final String action;
- if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON || mSwipeFromTrackpad) {
checkForAnomaly(false, true);
final Point displaySize = getRealDisplaySize();
@@ -1009,9 +1025,11 @@
} else {
action = "swiping up to home";
+ int startY = mSwipeFromTrackpad ? displaySize.y * 3 / 4 : displaySize.y - 1;
+ int endY = mSwipeFromTrackpad ? displaySize.y / 4 : displaySize.y / 2;
swipeToState(
- displaySize.x / 2, displaySize.y - 1,
- displaySize.x / 2, displaySize.y / 2,
+ 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);
@@ -1052,14 +1070,16 @@
waitForLauncherInitialized();
final boolean launcherVisible =
isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
- if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON || mSwipeFromTrackpad) {
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.
- linearGesture(0, displaySize.y / 4, displaySize.x / 2, displaySize.y / 4,
+ int startX = mSwipeFromTrackpad ? displaySize.x / 4 : 0;
+ int endX = mSwipeFromTrackpad ? displaySize.x * 3 / 4 : displaySize.x / 2;
+ linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
10, false, gestureScope);
} else {
waitForNavigationUiObject("back").click();
@@ -1589,18 +1609,33 @@
// Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
// fixed interval each time.
public void linearGesture(int startX, int startY, int endX, int endY, int steps,
- boolean slowDown,
- GestureScope gestureScope) {
+ boolean slowDown, GestureScope gestureScope) {
log("linearGesture: " + startX + ", " + startY + " -> " + endX + ", " + endY);
final long downTime = SystemClock.uptimeMillis();
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
+ if (mSwipeFromTrackpad) {
+ sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
+ start, gestureScope);
+ sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+ start, gestureScope);
+ }
final long endTime = movePointer(
start, end, steps, false, downTime, downTime, slowDown, gestureScope);
+ if (mSwipeFromTrackpad) {
+ sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_UP, 2),
+ start, gestureScope);
+ sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_UP, 1),
+ start, gestureScope);
+ }
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
+ private static int getPointerAction(int action, int index) {
+ return action + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ }
+
long movePointer(Point start, Point end, int steps, boolean isDecelerating, long downTime,
long startTime, boolean slowDown, GestureScope gestureScope) {
long endTime = movePointer(downTime, startTime, steps * GESTURE_STEP_MS,
@@ -1624,22 +1659,44 @@
return getContext().getResources();
}
+ private static MotionEvent getTrackpadThreeFingerMotionEvent(long downTime, long eventTime,
+ int action, float x, float y, int pointerCount) {
+ MotionEvent.PointerProperties[] pointerProperties =
+ new MotionEvent.PointerProperties[pointerCount];
+ MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
+ for (int i = 0; i < pointerCount; i++) {
+ pointerProperties[i] = getPointerProperties(i);
+ pointerCoords[i] = getPointerCoords(x, y);
+ pointerCoords[i].setAxisValue(AXIS_GESTURE_SWIPE_FINGER_COUNT, 3);
+ }
+ return MotionEvent.obtain(downTime, eventTime, action, pointerCount, pointerProperties,
+ pointerCoords, 0, 0, 1.0f, 1.0f, 0, 0,
+ InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_CLASS_POINTER, 0, 0,
+ MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE);
+ }
+
private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
float x, float y) {
- MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
- properties.id = 0;
- properties.toolType = Configurator.getInstance().getToolType();
+ 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);
+ }
+ private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
+ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = pointerId;
+ properties.toolType = Configurator.getInstance().getToolType();
+ return properties;
+ }
+
+ private static MotionEvent.PointerCoords getPointerCoords(float x, float y) {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
coords.pressure = 1;
coords.size = 1;
coords.x = x;
coords.y = y;
-
- return MotionEvent.obtain(downTime, eventTime, action, 1,
- new MotionEvent.PointerProperties[]{properties},
- new MotionEvent.PointerCoords[]{coords},
- 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ return coords;
}
private boolean hasTIS() {
@@ -1655,17 +1712,23 @@
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope) {
final boolean hasTIS = hasTIS();
- switch (action) {
+ int pointerCount = 1;
+
+ 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) {
+ && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
+ && !mSwipeFromTrackpad) {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
}
if (hasTIS && (isTrackpadGestureEnabled()
|| getNavigationModel() != NavigationModel.THREE_BUTTON)) {
expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
}
+ if (mSwipeFromTrackpad) {
+ mPointerCount = 1;
+ }
break;
case MotionEvent.ACTION_UP:
if (hasTIS && gestureScope != GestureScope.INSIDE
@@ -1676,7 +1739,8 @@
}
if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
&& gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
- && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE) {
+ && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
+ && !mSwipeFromTrackpad) {
expectEvent(TestProtocol.SEQUENCE_MAIN,
gestureScope == GestureScope.INSIDE
|| gestureScope == GestureScope.OUTSIDE_WITHOUT_PILFER
@@ -1696,9 +1760,29 @@
case MotionEvent.ACTION_HOVER_EXIT:
expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_HOVER_EXIT_TIS);
break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ mPointerCount++;
+ expectEvent(TestProtocol.SEQUENCE_TIS, getTouchEventPatternTIS(
+ "ACTION_POINTER_DOWN", mPointerCount));
+ pointerCount = mPointerCount;
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ pointerCount = mPointerCount;
+
+ // When the gesture is handled outside, it's cancelled within launcher.
+ if (gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
+ && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE) {
+ expectEvent(TestProtocol.SEQUENCE_TIS, getTouchEventPatternTIS(
+ "ACTION_POINTER_UP", mPointerCount));
+ }
+ mPointerCount--;
+ break;
}
- final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
+ final MotionEvent event = mSwipeFromTrackpad
+ ? getTrackpadThreeFingerMotionEvent(
+ downTime, currentTime, action, point.x, point.y, pointerCount)
+ : getMotionEvent(downTime, currentTime, action, point.x, point.y);
assertTrue("injectInputEvent failed",
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
event.recycle();
@@ -1706,8 +1790,7 @@
public long movePointer(long downTime, long startTime, long duration, Point from, Point to,
GestureScope gestureScope) {
- return movePointer(
- downTime, startTime, duration, false, from, to, gestureScope);
+ return movePointer(downTime, startTime, duration, false, from, to, gestureScope);
}
public long movePointer(long downTime, long startTime, long duration, boolean isDecelerating,
@@ -1855,6 +1938,12 @@
return tasks;
}
+ /** Reinitializes the workspace to its default layout. */
+ public void reinitializeLauncherData() {
+ getTestInfo(TestProtocol.REQUEST_REINITIALIZE_DATA);
+ }
+
+ /** Clears the workspace, leaving it empty. */
public void clearLauncherData() {
getTestInfo(TestProtocol.REQUEST_CLEAR_DATA);
}