Merge "Pass in dbFile from idpGridState for grid migration" into tm-dev
diff --git a/Android.bp b/Android.bp
index c980a2e..5a153a7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -31,7 +31,6 @@
"androidx.test.uiautomator_uiautomator",
"androidx.preference_preference",
"SystemUISharedLib",
- "SystemUIAnimationLib",
],
srcs: [
"tests/tapl/**/*.java",
@@ -197,7 +196,6 @@
"lottie",
"SystemUISharedLib",
"SystemUI-statsd",
- "SystemUIAnimationLib",
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
@@ -210,6 +208,8 @@
srcs: [
"ext_tests/src/**/*.java",
"ext_tests/src/**/*.kt",
+ "quickstep/ext_tests/src/**/*.java",
+ "quickstep/ext_tests/src/**/*.kt",
],
}
@@ -226,6 +226,21 @@
],
}
+// Common source files used to build go launcher
+filegroup {
+ name: "launcher-go-src-no-build-config",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ "quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
+ "go/src/**/*.java",
+ "go/src/**/*.kt",
+ "go/quickstep/src/**/*.java",
+ "go/quickstep/src/**/*.kt",
+ ],
+}
+
// Proguard files for Launcher3
filegroup {
name: "launcher-proguard-rules",
@@ -289,7 +304,6 @@
"SystemUISharedLib",
"Launcher3CommonDepsLib",
"QuickstepResLib",
- "SystemUIAnimationLib",
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
diff --git a/OWNERS b/OWNERS
index 05fa502..7f98ea6 100644
--- a/OWNERS
+++ b/OWNERS
@@ -39,6 +39,7 @@
xuqiu@google.com
sreyasr@google.com
thiruram@google.com
+brianji@google.com
per-file FeatureFlags.java, globs = set noparent
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 02206c0..d16e12c 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -29,8 +29,10 @@
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutAndWidgetContainer;
import java.util.ArrayList;
import java.util.Collection;
@@ -205,6 +207,32 @@
}
}
+ case TestProtocol.REQUEST_USE_TEST_WORKSPACE_LAYOUT: {
+ useTestWorkspaceLayout(true);
+ return response;
+ }
+
+ case TestProtocol.REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT: {
+ useTestWorkspaceLayout(false);
+ return response;
+ }
+
+ case TestProtocol.REQUEST_HOTSEAT_ICON_NAMES: {
+ return getLauncherUIProperty(Bundle::putStringArrayList, l -> {
+ ShortcutAndWidgetContainer hotseatIconsContainer =
+ l.getHotseat().getShortcutsAndWidgets();
+ ArrayList<String> hotseatIconNames = new ArrayList<>();
+
+ for (int i = 0; i < hotseatIconsContainer.getChildCount(); i++) {
+ // Use unchecked cast to catch changes in hotseat layout
+ BubbleTextView icon = (BubbleTextView) hotseatIconsContainer.getChildAt(i);
+ hotseatIconNames.add((String) icon.getText());
+ }
+
+ return hotseatIconNames;
+ });
+ }
+
case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
return response;
@@ -223,4 +251,15 @@
return super.call(method, arg, extras);
}
}
+
+ private void useTestWorkspaceLayout(boolean useTestWorkspaceLayout) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ LauncherSettings.Settings.call(mContext.getContentResolver(), useTestWorkspaceLayout
+ ? LauncherSettings.Settings.METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG
+ : LauncherSettings.Settings.METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
diff --git a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
new file mode 100644
index 0000000..e5f0295
--- /dev/null
+++ b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.taskbar.LauncherTaskbarUIController;
+import com.android.launcher3.testing.DebugTestInformationHandler;
+import com.android.launcher3.testing.TestProtocol;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Class to handle requests from tests, including debug ones, to Quickstep Launcher builds.
+ */
+public abstract class DebugQuickstepTestInformationHandler extends QuickstepTestInformationHandler {
+
+ private final DebugTestInformationHandler mDebugTestInformationHandler;
+
+ public DebugQuickstepTestInformationHandler(Context context) {
+ super(context);
+ mDebugTestInformationHandler = new DebugTestInformationHandler(context);
+ }
+
+ @Override
+ public Bundle call(String method, String arg, @Nullable Bundle extras) {
+ Bundle response = new Bundle();
+ switch (method) {
+ case TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING:
+ runOnUIThread(l -> {
+ enableManualTaskbarStashing(l, true);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING:
+ runOnUIThread(l -> {
+ enableManualTaskbarStashing(l, false);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED:
+ runOnUIThread(l -> {
+ enableManualTaskbarStashing(l, true);
+
+ BaseQuickstepLauncher quickstepLauncher = (BaseQuickstepLauncher) l;
+ LauncherTaskbarUIController taskbarUIController =
+ quickstepLauncher.getTaskbarUIController();
+
+ // Allow null-pointer to catch illegal states.
+ taskbarUIController.unstashTaskbarIfStashed();
+
+ enableManualTaskbarStashing(l, false);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT: {
+ final Resources resources = mContext.getResources();
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size));
+ return response;
+ }
+
+ default:
+ response = super.call(method, arg, extras);
+ if (response != null) return response;
+ return mDebugTestInformationHandler.call(method, arg, extras);
+ }
+ }
+
+ private void enableManualTaskbarStashing(Launcher launcher, boolean enable) {
+ BaseQuickstepLauncher quickstepLauncher = (BaseQuickstepLauncher) launcher;
+ LauncherTaskbarUIController taskbarUIController =
+ quickstepLauncher.getTaskbarUIController();
+
+ // Allow null-pointer to catch illegal states.
+ taskbarUIController.enableManualStashingForTests(enable);
+ }
+
+ /**
+ * Runs the given command on the UI thread.
+ */
+ private static void runOnUIThread(UIThreadCommand command) {
+ try {
+ MAIN_EXECUTOR.submit(() -> {
+ command.execute(Launcher.ACTIVITY_TRACKER.getCreatedActivity());
+ return null;
+ }).get();
+ } catch (ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private interface UIThreadCommand {
+
+ void execute(Launcher launcher);
+ }
+}
+
diff --git a/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
index 57423c2..710482f 100644
--- a/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
+++ b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?android:attr/dialogCornerRadius"/>
- <solid android:color="@color/gesture_tutorial_primary_color"/>
+ <solid android:color="?android:attr/colorAccent"/>
</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/bg_sandbox_feedback.xml b/quickstep/res/drawable/bg_sandbox_feedback.xml
index 83a3dea..83d7e43 100644
--- a/quickstep/res/drawable/bg_sandbox_feedback.xml
+++ b/quickstep/res/drawable/bg_sandbox_feedback.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<corners android:radius="28dp"/>
- <solid android:color="?android:attr/colorBackgroundFloating"/>
+ <solid android:color="?androidprv:attr/colorSurface"/>
</shape>
diff --git a/quickstep/res/drawable/gesture_tutorial_action_button_background.xml b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml
index ac6a52a..98dc1a5 100644
--- a/quickstep/res/drawable/gesture_tutorial_action_button_background.xml
+++ b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml
@@ -25,7 +25,7 @@
<shape
android:shape="rectangle">
<corners android:radius="50dp"/>
- <solid android:color="@color/gesture_tutorial_primary_color"/>
+ <solid android:color="?android:attr/colorAccent"/>
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_cancel_button_background.xml b/quickstep/res/drawable/gesture_tutorial_cancel_button_background.xml
index 0a34af6..7762615 100644
--- a/quickstep/res/drawable/gesture_tutorial_cancel_button_background.xml
+++ b/quickstep/res/drawable/gesture_tutorial_cancel_button_background.xml
@@ -17,5 +17,5 @@
android:shape="rectangle">
<corners android:radius="50dp"/>
<solid android:color="@android:color/transparent"/>
- <stroke android:width="1dp" android:color="@color/gesture_tutorial_primary_color"/>
+ <stroke android:width="1dp" android:color="?android:attr/colorAccent"/>
</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_finger_dot.xml b/quickstep/res/drawable/gesture_tutorial_finger_dot.xml
index 5f8aafd..cbb2612 100644
--- a/quickstep/res/drawable/gesture_tutorial_finger_dot.xml
+++ b/quickstep/res/drawable/gesture_tutorial_finger_dot.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
- <solid android:color="@color/gesture_tutorial_primary_color" />
+ <solid android:color="?android:attr/colorAccent" />
<size android:width="92dp" android:height="92dp"/>
</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_loop_back.xml b/quickstep/res/drawable/gesture_tutorial_loop_back.xml
index d2909ff..ae47709 100644
--- a/quickstep/res/drawable/gesture_tutorial_loop_back.xml
+++ b/quickstep/res/drawable/gesture_tutorial_loop_back.xml
@@ -85,7 +85,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_0"
android:fillAlpha="0.25"
- android:fillColor="@color/gesture_tutorial_primary_color"
+ android:fillColor="?android:attr/colorAccent"
android:fillType="nonZero"
android:pathData=" M12.5 -446 C12.5,-446 12.5,446 12.5,446 C12.5,446 -12.5,446 -12.5,446 C-12.5,446 -12.5,-446 -12.5,-446 C-12.5,-446 12.5,-446 12.5,-446c " />
</group>
diff --git a/quickstep/res/drawable/gesture_tutorial_loop_home.xml b/quickstep/res/drawable/gesture_tutorial_loop_home.xml
index 931f8c0..bed35dd 100644
--- a/quickstep/res/drawable/gesture_tutorial_loop_home.xml
+++ b/quickstep/res/drawable/gesture_tutorial_loop_home.xml
@@ -81,7 +81,7 @@
<path
android:name="_R_G_L_1_G_D_0_P_0"
android:fillAlpha="0.25"
- android:fillColor="@color/gesture_tutorial_primary_color"
+ android:fillColor="?android:attr/colorAccent"
android:fillType="nonZero"
android:pathData=" M206 -12.5 C206,-12.5 206,12.5 206,12.5 C206,12.5 -206,12.5 -206,12.5 C-206,12.5 -206,-12.5 -206,-12.5 C-206,-12.5 206,-12.5 206,-12.5c " />
</group>
diff --git a/quickstep/res/drawable/gesture_tutorial_loop_overview.xml b/quickstep/res/drawable/gesture_tutorial_loop_overview.xml
index a4c532b..53e8b5f 100644
--- a/quickstep/res/drawable/gesture_tutorial_loop_overview.xml
+++ b/quickstep/res/drawable/gesture_tutorial_loop_overview.xml
@@ -81,7 +81,7 @@
<path
android:name="_R_G_L_1_G_D_0_P_0"
android:fillAlpha="0.25"
- android:fillColor="@color/gesture_tutorial_primary_color"
+ android:fillColor="?android:attr/colorAccent"
android:fillType="nonZero"
android:pathData=" M206 -12.5 C206,-12.5 206,12.5 206,12.5 C206,12.5 -206,12.5 -206,12.5 C-206,12.5 -206,-12.5 -206,-12.5 C-206,-12.5 206,-12.5 206,-12.5c " />
</group>
diff --git a/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
new file mode 100644
index 0000000..20d2ecc
--- /dev/null
+++ b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingTop="26dp"
+ android:paddingBottom="26dp"
+ android:paddingStart="56dp"
+ android:paddingEnd="56dp">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_1"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintVertical_chainStyle="spread_inside"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/hotseat_icon_2"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_2"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_2"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
+ app:layout_constraintBottom_toTopOf="@id/hotseat_icon_3"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_3"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_3"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_icon_2"
+ app:layout_constraintBottom_toTopOf="@id/hotseat_icon_4"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_4"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_4"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_icon_3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
new file mode 100644
index 0000000..6877b89
--- /dev/null
+++ b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="32dp"
+ android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
+ android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_search_bar"
+ android:layout_width="200dp"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
+ app:cardBackgroundColor="@color/mock_search_bar"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_1"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_1"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_search_bar"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_2"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_2"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_3"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_3"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_4"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_5"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_4"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_6"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_6"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_2"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_5"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 9ad10dc..06dfa37 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -60,7 +60,7 @@
<TextView
android:id="@+id/title"
- style="@style/TextAppearance.GestureTutorial.Feedback.Title"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Title.AllSet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/allset_title_margin_top"
@@ -71,15 +71,14 @@
<TextView
android:id="@+id/subtitle"
- style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle.AllSet"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/allset_subtitle_margin_top"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_max="@dimen/allset_subtitle_width_max"
- android:gravity="start"
- android:text="@string/allset_description"/>
+ android:gravity="start"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/navigation_settings_guideline_bottom"
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml
index 5612666..027e4a0 100644
--- a/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml
@@ -1,12 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="32dp"
- android:paddingStart="170dp"
- android:paddingEnd="170dp">
+ android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
+ android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
<androidx.cardview.widget.CardView
android:id="@+id/hotseat_search_bar"
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 08e6178..b3ca297 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -27,10 +27,8 @@
<FrameLayout
android:id="@+id/gesture_tutorial_fake_hotseat_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"/>
+ android:layout_width="@dimen/gesture_tutorial_hotseat_width"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_height"/>
</RelativeLayout>
@@ -102,7 +100,7 @@
android:background="@drawable/gesture_tutorial_ripple"/>
<include
- layout="@layout/gesture_tutorial_foldable_mock_taskbar"
+ layout="@layout/gesture_tutorial_tablet_mock_taskbar"
android:id="@+id/gesture_tutorial_fake_taskbar_view"
android:layout_width="match_parent"
android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height"
@@ -121,33 +119,23 @@
android:scaleType="fitXY"
android:visibility="gone"/>
- <ImageView
- android:id="@+id/gesture_tutorial_finger_dot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gesture_tutorial_finger_dot"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:visibility="gone"/>
-
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/gesture_tutorial_fragment_feedback_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
- android:layout_marginTop="24dp"
android:paddingTop="24dp"
android:paddingBottom="16dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
android:background="@drawable/bg_sandbox_feedback">
<TextView
android:id="@+id/gesture_tutorial_fragment_feedback_title"
style="@style/TextAppearance.GestureTutorial.Feedback.Title"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -158,9 +146,7 @@
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginTop="24dp"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
+ android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -182,7 +168,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
- android:layout_marginEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="26dp"
@@ -201,11 +186,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
- android:layout_marginEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
- android:paddingStart="26dp"
- android:paddingEnd="26dp"
android:text="@string/gesture_tutorial_action_button_label_skip"
android:background="?android:attr/selectableItemBackgroundBorderless"
@@ -214,4 +196,13 @@
</androidx.constraintlayout.widget.ConstraintLayout>
+ <ImageView
+ android:id="@+id/gesture_tutorial_finger_dot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/gesture_tutorial_finger_dot"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:visibility="gone"/>
+
</com.android.quickstep.interaction.RootSandboxLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_mock_conversation.xml b/quickstep/res/layout/gesture_tutorial_mock_conversation.xml
index e8d5d79..5550389 100644
--- a/quickstep/res/layout/gesture_tutorial_mock_conversation.xml
+++ b/quickstep/res/layout/gesture_tutorial_mock_conversation.xml
@@ -34,8 +34,8 @@
android:layout_height="0dp"
android:layout_marginTop="43dp"
android:layout_marginBottom="22dp"
- android:layout_marginStart="34dp"
- android:layout_marginEnd="211dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_top_bar_margin_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_top_bar_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="4dp"
@@ -84,7 +84,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/mock_conversation_background"
- android:paddingBottom="66dp"
+ android:paddingBottom="@dimen/gesture_tutorial_conversation_bottom_padding"
app:layout_constraintTop_toBottomOf="@id/top_bar"
app:layout_constraintBottom_toBottomOf="parent"
@@ -108,6 +108,7 @@
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
android:layout_marginStart="124dp"
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
+ android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -122,6 +123,7 @@
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
android:layout_marginStart="@dimen/gesture_tutorial_message_padding_start"
+ android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
@@ -135,6 +137,7 @@
android:layout_height="36dp"
android:layout_marginStart="17dp"
android:layout_marginEnd="112dp"
+ android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -151,6 +154,7 @@
android:layout_marginBottom="@dimen/gesture_tutorial_message_small_margin_bottom"
android:layout_marginStart="280dp"
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
+ android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -164,7 +168,7 @@
android:layout_width="0dp"
android:layout_height="74dp"
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
- android:layout_marginStart="124dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_message_margin_start"
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
app:cardElevation="0dp"
@@ -192,7 +196,7 @@
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginStart="17dp"
- android:layout_marginEnd="144dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_reply_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -206,7 +210,7 @@
android:id="@+id/message_4"
android:layout_width="0dp"
android:layout_height="74dp"
- android:layout_marginStart="124dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_message_margin_start"
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
app:cardElevation="0dp"
diff --git a/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml b/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml
index 364ad6d..a172ad3 100644
--- a/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml
+++ b/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml
@@ -35,7 +35,7 @@
android:layout_marginTop="43dp"
android:layout_marginBottom="22dp"
android:layout_marginStart="34dp"
- android:layout_marginEnd="35dp"
+ android:layout_marginEnd="34dp"
app:cardElevation="0dp"
app:cardCornerRadius="4dp"
@@ -51,337 +51,336 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/mock_list_background"
- android:paddingBottom="66dp"
+ android:paddingTop="@dimen/gesture_tutorial_conversation_list_padding_top"
+ android:paddingStart="26dp"
app:layout_constraintTop_toBottomOf="@id/top_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:paddingTop="@dimen/gesture_tutorial_conversation_list_padding_top"
- android:paddingStart="26dp"
- android:paddingBottom="14dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_1"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/mock_button">
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_1"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_1"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_1_margin_end"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_1"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_2"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_1"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="217dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_2"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_2_margin_end"
+ android:layout_marginTop="4dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_1"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_2"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_1"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_1"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_2"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="142dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_2"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_1"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_1"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_1"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_2"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_3"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_3_margin_end"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_1"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_2"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_4"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_3"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="190dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_4"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_4_margin_end"
+ android:layout_marginTop="4dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_2"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_4"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_3"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_2"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_4"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="171dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_3"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_3"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_2"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_2"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_3"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_5"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_5_margin_end"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_2"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_3"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_6"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_5"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="198dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_6"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_6_margin_end"
+ android:layout_marginTop="4dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_3"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_6"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_5"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_3"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_6"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="79dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_4"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_5"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_3"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_3"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_4"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_7"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_7_margin_end"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_3"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_4"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_8"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_7"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="174dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_8"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_8_margin_end"
+ android:layout_marginTop="4dp"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_4"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_8"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_7"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_4"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_8"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="117dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_5"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_7"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_4"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_4"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_5"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_9"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="244dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_4"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_5"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_10"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_9"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="244dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_10"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="143dp"
+ android:layout_marginTop="4dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_5"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_10"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_9"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_5"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_10"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="143dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_6"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_9"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_5"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_5"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_6"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_11"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="177dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_5"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_6"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_12"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_11"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="177dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_12"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="117dp"
+ android:layout_marginTop="4dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_6"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_12"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_11"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_6"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_12"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="117dp"
- android:layout_marginTop="4dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_icon_7"
+ android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
+ android:layout_marginTop="32dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_11"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_6"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_list_profile_icon"
+ app:layout_constraintTop_toBottomOf="@id/conversation_icon_6"
+ app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_icon_7"
- android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
- android:layout_marginTop="32dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_13"
+ android:layout_width="0dp"
+ android:layout_height="18dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="189dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_list_profile_icon"
- app:layout_constraintTop_toBottomOf="@id/conversation_icon_6"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="@id/conversation_icon_7"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/conversation_line_14"/>
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_13"
- android:layout_width="0dp"
- android:layout_height="18dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="189dp"
+ <androidx.cardview.widget.CardView
+ android:id="@+id/conversation_line_14"
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
+ android:layout_marginEnd="166dp"
+ android:layout_marginTop="4dp"
+ android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="@id/conversation_icon_7"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/conversation_line_14"/>
-
- <androidx.cardview.widget.CardView
- android:id="@+id/conversation_line_14"
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="166dp"
- android:layout_marginTop="4dp"
-
- app:cardElevation="0dp"
- app:cardCornerRadius="4dp"
- app:cardBackgroundColor="@color/mock_list_preview_message"
- app:layout_constraintTop_toBottomOf="@id/conversation_line_13"
- app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
+ app:cardElevation="0dp"
+ app:cardCornerRadius="4dp"
+ app:cardBackgroundColor="@color/mock_list_preview_message"
+ app:layout_constraintTop_toBottomOf="@id/conversation_line_13"
+ app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
<androidx.cardview.widget.CardView
android:id="@+id/mock_button"
android:layout_width="149dp"
android:layout_height="56dp"
- android:layout_marginEnd="24dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_mock_button_margin_end"
+ android:layout_marginBottom="@dimen/gesture_tutorial_mock_button_margin_bottom"
app:cardElevation="0dp"
app:cardCornerRadius="164dp"
diff --git a/quickstep/res/layout/gesture_tutorial_mock_webpage.xml b/quickstep/res/layout/gesture_tutorial_mock_webpage.xml
index bb20968..0b1b40d 100644
--- a/quickstep/res/layout/gesture_tutorial_mock_webpage.xml
+++ b/quickstep/res/layout/gesture_tutorial_mock_webpage.xml
@@ -34,8 +34,8 @@
android:layout_height="0dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_webpage_url_margin_start_end"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_url_margin_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="100dp"
@@ -63,7 +63,7 @@
android:layout_height="0dp"
android:layout_marginTop="22dp"
android:layout_marginBottom="22dp"
- android:layout_marginStart="24dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_webpage_top_bar_button_margin_start"
app:cardElevation="0dp"
app:cardCornerRadius="8dp"
@@ -78,8 +78,8 @@
android:layout_height="0dp"
android:layout_marginTop="28dp"
android:layout_marginBottom="28dp"
- android:layout_marginStart="97dp"
- android:layout_marginEnd="97dp"
+ android:layout_marginStart="@dimen/gesture_tutorial_webpage_top_bar_margin_start"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_top_bar_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="2dp"
@@ -107,7 +107,7 @@
android:id="@+id/mock_line_1"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
- android:layout_marginEnd="126dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_1_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
@@ -121,7 +121,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
- android:layout_marginEnd="64dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_2_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
@@ -135,7 +135,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
- android:layout_marginEnd="151dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_3_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
@@ -174,7 +174,7 @@
android:layout_width="0dp"
android:layout_height="240dp"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
- android:layout_marginEnd="24dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_webpage_block_margin_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_large_corner_radius"
@@ -189,6 +189,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
android:layout_marginEnd="52dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
@@ -203,6 +204,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
android:layout_marginEnd="41dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
@@ -217,6 +219,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
android:layout_marginEnd="71dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
@@ -231,6 +234,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
android:layout_marginEnd="198dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
@@ -245,6 +249,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
android:layout_marginEnd="64dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
@@ -258,6 +263,7 @@
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
android:layout_marginEnd="71dp"
+ android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_conversation.xml
similarity index 93%
rename from quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml
rename to quickstep/res/layout/gesture_tutorial_tablet_mock_conversation.xml
index b0cc00b..c8cf8c3 100644
--- a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml
+++ b/quickstep/res/layout/gesture_tutorial_tablet_mock_conversation.xml
@@ -106,8 +106,8 @@
android:layout_width="0dp"
android:layout_height="112dp"
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
- android:layout_marginStart="445dp"
- android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_1_margin"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -121,7 +121,7 @@
android:layout_width="@dimen/gesture_tutorial_message_icon_size"
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
- android:layout_marginStart="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
@@ -134,7 +134,7 @@
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginStart="17dp"
- android:layout_marginEnd="441dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_reply_1_margin"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -149,8 +149,8 @@
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginBottom="@dimen/gesture_tutorial_message_small_margin_bottom"
- android:layout_marginStart="601dp"
- android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_2_margin"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -164,8 +164,8 @@
android:layout_width="0dp"
android:layout_height="74dp"
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
- android:layout_marginStart="445dp"
- android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_3_margin"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -179,7 +179,7 @@
android:layout_width="@dimen/gesture_tutorial_message_icon_size"
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
android:layout_marginBottom="32dp"
- android:layout_marginStart="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
@@ -192,7 +192,7 @@
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginStart="17dp"
- android:layout_marginEnd="473dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_reply_2_margin"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
@@ -206,8 +206,8 @@
android:id="@+id/message_4"
android:layout_width="0dp"
android:layout_height="74dp"
- android:layout_marginStart="445dp"
- android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
+ android:layout_marginStart="345dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
app:cardElevation="0dp"
app:cardCornerRadius="18dp"
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_conversation_list.xml
similarity index 95%
rename from quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
rename to quickstep/res/layout/gesture_tutorial_tablet_mock_conversation_list.xml
index e5cd9bc..0fb0677 100644
--- a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
+++ b/quickstep/res/layout/gesture_tutorial_tablet_mock_conversation_list.xml
@@ -67,7 +67,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/mock_button">
+ app:layout_constraintEnd_toEndOf="parent">
<androidx.cardview.widget.CardView
android:id="@+id/conversation_icon_1"
@@ -189,7 +189,7 @@
android:layout_width="0dp"
android:layout_height="16dp"
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="15dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_6_margin_end"
android:layout_marginTop="4dp"
app:cardElevation="0dp"
@@ -233,7 +233,7 @@
android:layout_width="0dp"
android:layout_height="16dp"
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="72dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_8_margin_end"
android:layout_marginTop="4dp"
app:cardElevation="0dp"
@@ -277,7 +277,7 @@
android:layout_width="0dp"
android:layout_height="16dp"
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
- android:layout_marginEnd="111dp"
+ android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_10_margin_end"
android:layout_marginTop="4dp"
app:cardElevation="0dp"
@@ -376,21 +376,21 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
+ <androidx.cardview.widget.CardView
+ android:id="@+id/mock_button"
+ android:layout_width="149dp"
+ android:layout_height="56dp"
+ android:layout_marginEnd="126dp"
+ android:layout_marginBottom="24dp"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="164dp"
+ app:cardBackgroundColor="@color/mock_list_button"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
</androidx.constraintlayout.widget.ConstraintLayout>
- <androidx.cardview.widget.CardView
- android:id="@+id/mock_button"
- android:layout_width="149dp"
- android:layout_height="56dp"
- android:layout_marginEnd="126dp"
- android:layout_marginBottom="24dp"
-
- app:cardElevation="0dp"
- app:cardCornerRadius="164dp"
- app:cardBackgroundColor="@color/mock_list_button"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
new file mode 100644
index 0000000..027e4a0
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="32dp"
+ android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
+ android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_search_bar"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
+ app:cardBackgroundColor="@color/mock_search_bar"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_1"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_2"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_2"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_3"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_3"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_4"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_1"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_5"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_4"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
+ app:layout_constraintEnd_toStartOf="@id/hotseat_icon_6"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/hotseat_icon_6"
+ android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+
+ app:cardElevation="0dp"
+ app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
+ app:cardBackgroundColor="@color/mock_app_icon_2"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
+ app:layout_constraintStart_toEndOf="@id/hotseat_icon_5"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_taskbar.xml
similarity index 100%
rename from quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml
rename to quickstep/res/layout/gesture_tutorial_tablet_mock_taskbar.xml
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_webpage.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_webpage.xml
similarity index 100%
rename from quickstep/res/layout/gesture_tutorial_foldable_mock_webpage.xml
rename to quickstep/res/layout/gesture_tutorial_tablet_mock_webpage.xml
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index 668aea2..f233bde 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -16,4 +16,61 @@
-->
<resources>
<dimen name="overview_task_margin">8dp</dimen>
+
+ <!-- Tips Gesture Tutorial -->
+ <dimen name="gesture_tutorial_feedback_margin_start_end">126dp</dimen>
+ <dimen name="gesture_tutorial_feedback_margin_top">24dp</dimen>
+
+ <!-- Gesture Tutorial mock conversations -->
+ <dimen name="gesture_tutorial_message_padding_start">42dp</dimen>
+ <dimen name="gesture_tutorial_message_padding_end">60dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_margin_start">42dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_margin_end">683dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_button_margin_end">42dp</dimen>
+ <dimen name="gesture_tutorial_conversation_bottom_padding">35dp</dimen>
+ <integer name="gesture_tutorial_extra_messages_visibility">2</integer> <!-- GONE -->
+ <dimen name="gesture_tutorial_message_margin_start">505dp</dimen>
+ <dimen name="gesture_tutorial_reply_margin_end">462dp</dimen>
+ <dimen name="gesture_tutorial_input_margin_start">103dp</dimen>
+ <dimen name="gesture_tutorial_input_margin_end">103dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_1_margin">345dp</dimen>
+ <dimen name="gesture_tutorial_tablet_reply_1_margin">341dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_2_margin">501dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_3_margin">345dp</dimen>
+ <dimen name="gesture_tutorial_tablet_reply_2_margin">373dp</dimen>
+
+ <!-- Gesture Tutorial mock conversation lists -->
+ <dimen name="gesture_tutorial_conversation_line_1_margin_end">607dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_2_margin_end">460dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_3_margin_end">554dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_4_margin_end">517dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_5_margin_end">570dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_6_margin_end">336dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_7_margin_end">523dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_8_margin_end">500dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_6_margin_end">15dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_8_margin_end">72dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_10_margin_end">111dp</dimen>
+ <integer name="gesture_tutorial_extra_conversations_visibility">2</integer> <!-- GONE -->
+ <dimen name="gesture_tutorial_mock_button_margin_end">34dp</dimen>
+ <dimen name="gesture_tutorial_mock_button_margin_bottom">42dp</dimen>
+
+ <!-- Gesture Tutorial mock hotseats -->
+ <dimen name="gesture_tutorial_hotseat_width">-2px</dimen> <!-- wrap_content -->
+ <dimen name="gesture_tutorial_hotseat_height">-1px</dimen> <!-- match_parent -->
+ <dimen name="gesture_tutorial_hotseat_padding_start_end">170dp</dimen>
+
+ <!-- Gesture Tutorial mock webpages -->
+ <dimen name="gesture_tutorial_webpage_url_margin_start_end">24dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_button_margin_start">48dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_margin_start">121dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_margin_end">355dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_1_margin_end">355dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_2_margin_end">208dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_3_margin_end">439dp</dimen>
+ <dimen name="gesture_tutorial_webpage_block_margin_end">311dp</dimen>
+ <integer name="gesture_tutorial_webpage_extra_lines_visibility">2</integer> <!-- GONE -->
+
+ <!-- Gesture Tutorial mock taskbar -->
+ <dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 671a617..8f439a2 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<color name="chip_hint_foreground_color">#fff</color>
<color name="chip_scrim_start_color">#39000000</color>
@@ -41,8 +41,6 @@
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
<!-- Must contrast gesture_tutorial_fake_wallpaper_color -->
<color name="gesture_tutorial_fake_previous_task_view_color">#3C4043</color> <!-- Gray -->
- <color name="gesture_tutorial_action_button_label_color">#FF000000</color>
- <color name="gesture_tutorial_primary_color">#B7F29F</color> <!-- Light Green -->
<color name="gesture_tutorial_taskbar_color">#202124</color>
<!-- Mock hotseat -->
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 3a4bb10..3b4a28b 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -23,8 +23,8 @@
</string-array>
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
-
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
+ <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
<!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
determines how many thumbnails will be fetched in the background. -->
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 926e10c..2b71768 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -110,8 +110,10 @@
<dimen name="gestures_overscroll_finish_threshold">136dp</dimen>
<!-- Tips Gesture Tutorial -->
- <dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
- <dimen name="gesture_tutorial_foldable_feedback_margin_start_end">140dp</dimen>
+ <dimen name="gesture_tutorial_feedback_margin_start_end">8dp</dimen>
+ <dimen name="gesture_tutorial_tablet_feedback_margin_start_end">140dp</dimen>
+ <dimen name="gesture_tutorial_feedback_margin_top">16dp</dimen>
+ <dimen name="gesture_tutorial_tablet_feedback_margin_top">24dp</dimen>
<dimen name="gesture_tutorial_multi_row_task_view_spacing">72dp</dimen>
<dimen name="gesture_tutorial_small_task_view_corner_radius">18dp</dimen>
<dimen name="gesture_tutorial_mock_taskbar_height">80dp</dimen>
@@ -124,15 +126,46 @@
<dimen name="gesture_tutorial_message_small_margin_bottom">4dp</dimen>
<dimen name="gesture_tutorial_message_padding_start">26dp</dimen>
<dimen name="gesture_tutorial_message_padding_end">18dp</dimen>
- <dimen name="gesture_tutorial_foldable_message_padding_start_end">126dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_margin_start">34dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_margin_end">211dp</dimen>
+ <dimen name="gesture_tutorial_top_bar_button_margin_end">24dp</dimen>
+ <dimen name="gesture_tutorial_conversation_bottom_padding">66dp</dimen>
+ <integer name="gesture_tutorial_extra_messages_visibility">0</integer> <!-- VISIBLE -->
+ <dimen name="gesture_tutorial_message_margin_start">124dp</dimen>
+ <dimen name="gesture_tutorial_reply_margin_end">144dp</dimen>
+ <dimen name="gesture_tutorial_input_margin_start">34dp</dimen>
+ <dimen name="gesture_tutorial_input_margin_end">24dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_padding_start_end">126dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_1_margin">245dp</dimen>
+ <dimen name="gesture_tutorial_tablet_reply_1_margin">241dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_2_margin">401dp</dimen>
+ <dimen name="gesture_tutorial_tablet_message_3_margin">245dp</dimen>
+ <dimen name="gesture_tutorial_tablet_reply_2_margin">273dp</dimen>
<!-- Gesture Tutorial mock conversation lists -->
<dimen name="gesture_tutorial_conversation_icon_size">56dp</dimen>
<dimen name="gesture_tutorial_conversation_icon_corner_radius">100dp</dimen>
<dimen name="gesture_tutorial_conversation_list_padding_top">28dp</dimen>
<dimen name="gesture_tutorial_conversation_line_padding_start">20dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_1_margin_end">217dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_2_margin_end">142dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_3_margin_end">190dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_4_margin_end">171dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_5_margin_end">198dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_6_margin_end">79dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_7_margin_end">174dp</dimen>
+ <dimen name="gesture_tutorial_conversation_line_8_margin_end">117dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_6_margin_end">65dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_8_margin_end">132dp</dimen>
+ <dimen name="gesture_tutorial_tablet_conversation_line_10_margin_end">161dp</dimen>
+ <integer name="gesture_tutorial_extra_conversations_visibility">0</integer> <!-- VISIBLE -->
+ <dimen name="gesture_tutorial_mock_button_margin_end">24dp</dimen>
+ <dimen name="gesture_tutorial_mock_button_margin_bottom">66dp</dimen>
<!-- Gesture Tutorial mock hotseats -->
+ <dimen name="gesture_tutorial_hotseat_width">-1px</dimen> <!-- match_parent -->
+ <dimen name="gesture_tutorial_hotseat_height">-2px</dimen> <!-- wrap_content -->
+ <dimen name="gesture_tutorial_hotseat_padding_start_end">26dp</dimen>
<dimen name="gesture_tutorial_hotseat_icon_size">60dp</dimen>
<dimen name="gesture_tutorial_hotseat_icon_corner_radius">100dp</dimen>
<dimen name="gesture_tutorial_hotseat_search_height">50dp</dimen>
@@ -148,11 +181,20 @@
<dimen name="gesture_tutorial_webpage_small_corner_radius">4dp</dimen>
<dimen name="gesture_tutorial_webpage_large_line_height">36dp</dimen>
<dimen name="gesture_tutorial_webpage_small_line_height">22dp</dimen>
+ <dimen name="gesture_tutorial_webpage_url_margin_start_end">16dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_button_margin_start">24dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_margin_start">97dp</dimen>
+ <dimen name="gesture_tutorial_webpage_top_bar_margin_end">97dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_1_margin_end">126dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_2_margin_end">64dp</dimen>
+ <dimen name="gesture_tutorial_webpage_line_3_margin_end">151dp</dimen>
+ <dimen name="gesture_tutorial_webpage_block_margin_end">24dp</dimen>
+ <integer name="gesture_tutorial_webpage_extra_lines_visibility">0</integer> <!-- VISIBLE -->
<!-- Gesture Tutorial mock taskbar -->
<dimen name="gesture_tutorial_taskbar_icon_size">44dp</dimen>
<dimen name="gesture_tutorial_taskbar_icon_corner_radius">100dp</dimen>
- <dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
+ <dimen name="gesture_tutorial_taskbar_padding_start_end">52dp</dimen>
<!-- All Set page -->
<dimen name="allset_page_margin_horizontal">40dp</dimen>
@@ -217,6 +259,7 @@
<dimen name="taskbar_contextual_buttons_size">35dp</dimen>
<dimen name="taskbar_stashed_size">24dp</dimen>
<dimen name="taskbar_stashed_handle_width">220dp</dimen>
+ <dimen name="taskbar_unstash_input_area">316dp</dimen>
<dimen name="taskbar_stashed_handle_height">4dp</dimen>
<dimen name="taskbar_edu_wave_anim_trans_y">25dp</dimen>
<dimen name="taskbar_edu_wave_anim_trans_y_return_overshoot">4dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 3ee2af0..f80deeb 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -182,8 +182,10 @@
<string name="allset_title">All set!</string>
<!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_hint">Swipe up to go Home</string>
- <!-- Description of "All Set" page [CHAR LIMIT=NONE] -->
+ <!-- Description of "All Set" page on phones [CHAR LIMIT=NONE] -->
<string name="allset_description">You\u2019re ready to start using your phone</string>
+ <!-- Description of "All Set" page on tablets [CHAR LIMIT=NONE] -->
+ <string name="allset_description_tablet">You\u2019re ready to start using your tablet</string>
<!-- String linking to navigation settings on "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_navigation_settings"><annotation id="link">System navigation settings</annotation></string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 2efe72e..7225220 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -47,6 +47,12 @@
<item name="android:lineHeight">44sp</item>
</style>
+ <style name="TextAppearance.GestureTutorial.Feedback.Title.AllSet"
+ parent="TextAppearance.GestureTutorial.Feedback.Title">
+ <item name="android:letterSpacing">0.03</item>
+ <item name="android:lineHeight">44sp</item>
+ </style>
+
<style name="TextAppearance.GestureTutorial.Dialog.Title"
parent="TextAppearance.GestureTutorial.Feedback.Title">
<item name="android:gravity">center_horizontal</item>
@@ -61,6 +67,12 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">google-sans-text</item>
<item name="android:letterSpacing">0.03</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ </style>
+
+ <style name="TextAppearance.GestureTutorial.Feedback.Subtitle.AllSet"
+ parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
<item name="android:textSize">18sp</item>
<item name="android:lineHeight">24sp</item>
</style>
@@ -77,8 +89,8 @@
<style name="TextAppearance.GestureTutorial.Feedback.Subtext"
parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
<item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/gesture_tutorial_primary_color</item>
- <item name="android:gravity">center</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
+ <item name="android:gravity">start</item>
</style>
<style name="TextAppearance.GestureTutorial.Feedback.Subtext.Dark"
@@ -89,7 +101,7 @@
<style name="TextAppearance.GestureTutorial.ButtonLabel"
parent="TextAppearance.GestureTutorial.CallToAction">
<item name="android:gravity">center</item>
- <item name="android:textColor">@color/gesture_tutorial_action_button_label_color</item>
+ <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:letterSpacing">0.02</item>
<item name="android:textSize">16sp</item>
<item name="android:textAllCaps">false</item>
@@ -97,12 +109,12 @@
<style name="TextAppearance.GestureTutorial.CancelButtonLabel"
parent="TextAppearance.GestureTutorial.ButtonLabel">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="TextAppearance.GestureTutorial.TextButtonLabel"
parent="TextAppearance.GestureTutorial.ButtonLabel">
- <item name="android:textColor">@color/gesture_tutorial_primary_color</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="TextAppearance.GestureTutorial.LinkText"
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 8fb085d..6f0f993 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
-import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -38,7 +37,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.graphics.Insets;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
@@ -46,7 +44,6 @@
import android.os.IBinder;
import android.view.Display;
import android.view.View;
-import android.view.WindowInsets;
import android.window.SplashScreen;
import androidx.annotation.Nullable;
@@ -295,8 +292,8 @@
mActionsView = findViewById(R.id.overview_actions_view);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
SplitSelectStateController controller =
- new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
- getStateManager(), getDepthController());
+ new SplitSelectStateController(this, mHandler, getStateManager(),
+ getDepthController());
overviewPanel.init(mActionsView, controller);
mActionsView.setDp(getDeviceProfile());
mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
@@ -614,17 +611,4 @@
mDepthController.dump(prefix, writer);
}
}
-
- @Override
- public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
- WindowInsets oldInsets) {
- // Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
- // would count towards it). This is used for the bottom protection in All Apps for example.
- if (DisplayController.getNavigationMode(this) == NO_BUTTON) {
- Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
- Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
- oldTappableInsets.right, 0);
- updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 803dee4..f14e2a2 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -44,6 +44,7 @@
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
@@ -77,6 +78,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.Log;
import android.util.Pair;
import android.util.Size;
import android.view.SurfaceControl;
@@ -109,6 +111,7 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.ScrimView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.quickstep.LauncherBackAnimationController;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
@@ -135,6 +138,7 @@
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
@@ -213,6 +217,7 @@
private RemoteAnimationFactory mWallpaperOpenTransitionRunner;
private RemoteTransitionCompat mLauncherOpenTransition;
+ private LauncherBackAnimationController mBackAnimationController;
private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -238,6 +243,8 @@
mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS);
mHandler = new Handler(Looper.getMainLooper());
mDeviceProfile = mLauncher.getDeviceProfile();
+ mBackAnimationController = new LauncherBackAnimationController(
+ mDeviceProfile, mLauncher, this);
Resources res = mLauncher.getResources();
mContentScale = res.getFloat(R.dimen.content_scale);
@@ -611,9 +618,28 @@
RecentsView overview = mLauncher.getOverviewPanel();
ObjectAnimator alpha = ObjectAnimator.ofFloat(overview,
RecentsView.CONTENT_ALPHA, alphas);
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator alphas=" + Arrays.toString(alphas));
+ alpha.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator onStart");
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ float alpha = overview == null ? -1 : RecentsView.CONTENT_ALPHA.get(overview);
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator onCancel, alpha=" + alpha);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator onEnd");
+ }
+ });
alpha.setDuration(CONTENT_ALPHA_DURATION);
alpha.setInterpolator(LINEAR);
anim.play(alpha);
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator setFreezeVisibility=true");
overview.setFreezeViewVisibility(true);
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(overview, SCALE_PROPERTY, scales);
@@ -622,6 +648,7 @@
anim.play(scaleAnim);
return () -> {
+ Log.d(BAD_STATE, "QTM composeViewContentAnimator onEnd setFreezeVisibility=false");
overview.setFreezeViewVisibility(false);
SCALE_PROPERTY.set(overview, 1f);
mLauncher.getStateManager().reapplyState();
@@ -1136,6 +1163,9 @@
mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
}
+ if (mBackAnimationController != null) {
+ mBackAnimationController.registerBackCallbacks(mHandler);
+ }
}
public void onActivityDestroyed() {
@@ -1171,6 +1201,10 @@
mLauncherOpenTransition = null;
mWallpaperOpenTransitionRunner = null;
}
+ if (mBackAnimationController != null) {
+ mBackAnimationController.unregisterBackCallbacks();
+ mBackAnimationController = null;
+ }
}
private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
@@ -1186,6 +1220,19 @@
return false;
}
+ private boolean hasMultipleTargetsWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
+ int numTargets = 0;
+ for (RemoteAnimationTargetCompat target : targets) {
+ if (target.mode == mode) {
+ numTargets++;
+ }
+ if (numTargets > 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* @return Runner that plays when user goes to Launcher
* ie. pressing home, swiping up from nav bar.
@@ -1288,8 +1335,8 @@
}
}
- return mLauncher.getFirstMatchForAppClose(launchCookieItemId,
- packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
+ return mLauncher.getFirstMatchForAppClose(launchCookieItemId, packageName,
+ UserHandle.of(runningTaskTarget.taskInfo.userId), true /* supportsAllAppsState */);
}
private @NonNull RectF getDefaultWindowTargetRect() {
@@ -1310,8 +1357,9 @@
/**
* Closing animator that animates the window into its final location on the workspace.
*/
- private void getClosingWindowAnimators(AnimatorSet animation,
- RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS) {
+ private RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
+ RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS,
+ RectF closingWindowStartRect) {
FloatingIconView floatingIconView = null;
FloatingWidgetView floatingWidget = null;
RectF targetRect = new RectF();
@@ -1343,8 +1391,7 @@
targetRect.set(getDefaultWindowTargetRect());
}
- final RectF startRect = new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
- RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher,
+ RectFSpringAnim anim = new RectFSpringAnim(closingWindowStartRect, targetRect, mLauncher,
mDeviceProfile);
// Hook up floating views to the closing window animators.
@@ -1378,7 +1425,7 @@
final float floatingWidgetAlpha = isTransluscent ? 0 : 1;
FloatingWidgetView finalFloatingWidget = floatingWidget;
- RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
+ RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
windowTargetBounds) {
@Override
public void onUpdate(RectF currentRectF, float progress) {
@@ -1402,6 +1449,7 @@
anim.start(mLauncher, velocityPxPerS);
}
});
+ return anim;
}
/**
@@ -1526,6 +1574,97 @@
}
/**
+ * Creates the {@link RectFSpringAnim} and {@link AnimatorSet} required to animate
+ * the transition.
+ */
+ public Pair<RectFSpringAnim, AnimatorSet> createWallpaperOpenAnimations(
+ RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ boolean fromUnlock,
+ RectF startRect) {
+ AnimatorSet anim = null;
+ RectFSpringAnim rectFSpringAnim = null;
+
+ RemoteAnimationProvider provider = mRemoteAnimationProvider;
+ if (provider != null) {
+ anim = provider.createWindowAnimation(appTargets, wallpaperTargets);
+ }
+
+ if (anim == null) {
+ anim = new AnimatorSet();
+
+ final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
+ || launcherIsATargetWithMode(appTargets, MODE_OPENING);
+
+ View launcherView = findLauncherView(appTargets);
+ boolean playFallBackAnimation = (launcherView == null
+ && launcherIsForceInvisibleOrOpening)
+ || mLauncher.getWorkspace().isOverlayShown()
+ || hasMultipleTargetsWithMode(appTargets, MODE_CLOSING);
+
+ boolean playWorkspaceReveal = true;
+ boolean skipAllAppsScale = false;
+ if (fromUnlock) {
+ anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
+ } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
+ && !playFallBackAnimation) {
+ // Use a fixed velocity to start the animation.
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
+ .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+ PointF velocity = new PointF(0, -velocityPxPerS);
+ rectFSpringAnim = getClosingWindowAnimators(
+ anim, appTargets, launcherView, velocity, startRect);
+ if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
+ anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+ true /* animateOverviewScrim */, launcherView).getAnimators());
+ // We play StaggeredWorkspaceAnim as a part of the closing window animation.
+ playWorkspaceReveal = false;
+ } else {
+ // Skip scaling all apps, otherwise FloatingIconView will get wrong
+ // layout bounds.
+ skipAllAppsScale = true;
+ }
+ } else {
+ anim.play(getFallbackClosingWindowAnimators(appTargets));
+ }
+
+ // Normally, we run the launcher content animation when we are transitioning
+ // home, but if home is already visible, then we don't want to animate the
+ // contents of launcher unless we know that we are animating home as a result
+ // of the home button press with quickstep, which will result in launcher being
+ // started on touch down, prior to the animation home (and won't be in the
+ // targets list because it is already visible). In that case, we force
+ // invisibility on touch down, and only reset it after the animation to home
+ // is initialized.
+ if (launcherIsForceInvisibleOrOpening) {
+ addCujInstrumentation(
+ anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(anim);
+
+ if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+ Pair<AnimatorSet, Runnable> contentAnimator =
+ getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
+ skipAllAppsScale);
+ anim.play(contentAnimator.first);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ contentAnimator.second.run();
+ }
+ });
+ } else {
+ if (playWorkspaceReveal) {
+ anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
+ }
+ }
+ }
+ }
+
+ return new Pair(rectFSpringAnim, anim);
+ }
+
+ /**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory {
@@ -1565,83 +1704,12 @@
mLauncher.getStateManager().moveToRestState();
}
- AnimatorSet anim = null;
- RemoteAnimationProvider provider = mRemoteAnimationProvider;
- if (provider != null) {
- anim = provider.createWindowAnimation(appTargets, wallpaperTargets);
- }
-
- if (anim == null) {
- anim = new AnimatorSet();
-
- final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
- || launcherIsATargetWithMode(appTargets, MODE_OPENING);
-
- View launcherView = findLauncherView(appTargets);
- boolean playFallBackAnimation = (launcherView == null
- && launcherIsForceInvisibleOrOpening)
- || mLauncher.getWorkspace().isOverlayShown();
-
- boolean playWorkspaceReveal = true;
- boolean skipAllAppsScale = false;
- if (mFromUnlock) {
- anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
- } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
- && !playFallBackAnimation) {
- // Use a fixed velocity to start the animation.
- float velocityPxPerS = DynamicResource.provider(mLauncher)
- .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
- PointF velocity = new PointF(0, -velocityPxPerS);
- getClosingWindowAnimators(anim, appTargets, launcherView, velocity);
- if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
- anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
- true /* animateOverviewScrim */, launcherView).getAnimators());
- // We play StaggeredWorkspaceAnim as a part of the closing window animation.
- playWorkspaceReveal = false;
- } else {
- // Skip scaling all apps, otherwise FloatingIconView will get wrong
- // layout bounds.
- skipAllAppsScale = true;
- }
- } else {
- anim.play(getFallbackClosingWindowAnimators(appTargets));
- }
-
- // Normally, we run the launcher content animation when we are transitioning
- // home, but if home is already visible, then we don't want to animate the
- // contents of launcher unless we know that we are animating home as a result
- // of the home button press with quickstep, which will result in launcher being
- // started on touch down, prior to the animation home (and won't be in the
- // targets list because it is already visible). In that case, we force
- // invisibility on touch down, and only reset it after the animation to home
- // is initialized.
- if (launcherIsForceInvisibleOrOpening) {
- addCujInstrumentation(
- anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
- // Only register the content animation for cancellation when state changes
- mLauncher.getStateManager().setCurrentAnimation(anim);
-
- if (mLauncher.isInState(LauncherState.ALL_APPS)) {
- Pair<AnimatorSet, Runnable> contentAnimator =
- getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
- skipAllAppsScale);
- anim.play(contentAnimator.first);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- contentAnimator.second.run();
- }
- });
- } else {
- if (playWorkspaceReveal) {
- anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
- }
- }
- }
- }
+ Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations(
+ appTargets, wallpaperTargets, mFromUnlock,
+ new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx));
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
- result.setAnimation(anim, mLauncher);
+ result.setAnimation(pair.second, mLauncher);
}
}
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index d37e530..0284ae4 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -194,7 +194,7 @@
@Override
protected void onDraw(Canvas canvas) {
if (mDividerType == DividerType.LINE) {
- int l = (getWidth() - getPaddingLeft() - mDividerSize[0]) / 2;
+ int l = (getWidth() - mDividerSize[0]) / 2;
int t = getHeight() - (getPaddingBottom() / 2);
int radius = mDividerSize[1];
canvas.drawRoundRect(l, t, l + mDividerSize[0], t + mDividerSize[1], radius, radius,
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 768a348..793d987 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -27,6 +27,7 @@
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
@@ -118,6 +119,24 @@
}
/**
+ * Enables manual taskbar stashing. This method should only be used for tests that need to
+ * stash/unstash the taskbar.
+ */
+ @VisibleForTesting
+ public void enableManualStashingForTests(boolean enableManualStashing) {
+ mControllers.taskbarStashController.enableManualStashingForTests(enableManualStashing);
+ }
+
+ /**
+ * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
+ * taskbar at the end of a test.
+ */
+ @VisibleForTesting
+ public void unstashTaskbarIfStashed() {
+ mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+ }
+
+ /**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
public void onLauncherResumedOrPaused(boolean isResumed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5387b1a..6c74ae3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -71,6 +71,8 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.NavigationMode;
@@ -646,12 +648,16 @@
Toast.makeText(this, R.string.safemode_shortcut_error,
Toast.LENGTH_SHORT).show();
} else if (info.isPromise()) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
intent = new PackageManagerHelper(this)
.getMarketIntent(info.getTargetPackage())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut");
String id = info.getDeepShortcutId();
String packageName = intent.getPackage();
getSystemService(LauncherApps.class)
@@ -680,6 +686,7 @@
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
if (info.user.equals(Process.myUserHandle())) {
// TODO(b/216683257): Use startActivityForResult for search results that require it.
startActivity(intent);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d2e24e5..a5999cc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -116,7 +116,7 @@
taskbarEduController.init(this);
taskbarPopupController.init(this);
taskbarForceVisibleImmersiveController.init(this);
- taskbarAllAppsController.init(this);
+ taskbarAllAppsController.init(this, sharedState);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -152,6 +152,7 @@
taskbarAutohideSuspendController.onDestroy();
taskbarPopupController.onDestroy();
taskbarForceVisibleImmersiveController.onDestroy();
+ taskbarAllAppsController.onDestroy();
mControllersToLog = null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index af98b7f..e2ab443 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -63,6 +63,8 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.systemui.shared.recents.model.Task;
@@ -128,7 +130,7 @@
if (!(view instanceof BubbleTextView)) {
return false;
}
-
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick");
BubbleTextView btv = (BubbleTextView) view;
mActivity.onDragStart();
btv.post(() -> {
@@ -164,24 +166,7 @@
dragLayerY += dragRect.top;
DragOptions dragOptions = new DragOptions();
- dragOptions.preDragCondition = new DragOptions.PreDragCondition() {
- private DragView mDragView;
-
- @Override
- public boolean shouldStartDrag(double distanceDragged) {
- return mDragView != null && mDragView.isAnimationFinished();
- }
-
- @Override
- public void onPreDragStart(DropTarget.DragObject dragObject) {
- mDragView = dragObject.dragView;
- }
-
- @Override
- public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
- mDragView = null;
- }
- };
+ dragOptions.preDragCondition = null;
if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
PopupContainerWithArrow<BaseTaskbarContext> popupContainer =
mControllers.taskbarPopupController.showForIcon(btv);
@@ -189,6 +174,32 @@
dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
}
}
+ if (dragOptions.preDragCondition == null) {
+ dragOptions.preDragCondition = new DragOptions.PreDragCondition() {
+ private DragView mDragView;
+
+ @Override
+ public boolean shouldStartDrag(double distanceDragged) {
+ return mDragView != null && mDragView.isAnimationFinished();
+ }
+
+ @Override
+ public void onPreDragStart(DropTarget.DragObject dragObject) {
+ mDragView = dragObject.dragView;
+
+ if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()
+ && !shouldStartDrag(0)) {
+ // Immediately close the popup menu.
+ mDragView.setOnAnimationEndCallback(() -> callOnDragStart());
+ }
+ }
+
+ @Override
+ public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
+ mDragView = null;
+ }
+ };
+ }
return startDrag(
drawable,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index cdac497..c7330d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -184,6 +185,9 @@
} else if (mControllers.taskbarDragController.isSystemDragInProgress()) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ } else if (AbstractFloatingView.getOpenView(mActivity, TYPE_TASKBAR_ALL_APPS) != null) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
} else if (mControllers.taskbarViewController.areIconsVisible()
|| AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null
|| mActivity.isNavBarKidsModeActive()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index 991bcec..56648ea 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -1,5 +1,6 @@
package com.android.launcher3.taskbar;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
@@ -14,6 +15,7 @@
import android.content.Intent;
import android.content.IntentFilter;
+import com.android.launcher3.AbstractFloatingView;
import com.android.systemui.shared.system.QuickStepContract;
import java.io.PrintWriter;
@@ -39,6 +41,7 @@
@Override
public void onReceive(Context context, Intent intent) {
mIsScreenOff = true;
+ AbstractFloatingView.closeOpenViews(mContext, false, TYPE_ALL);
}
};
@@ -71,6 +74,10 @@
mNavbarButtonsViewController.setKeyguardVisible(keyguardShowing || dozing,
keyguardOccluded);
updateIconsForBouncer();
+
+ if (keyguardShowing) {
+ AbstractFloatingView.closeOpenViews(mContext, true, TYPE_ALL);
+ }
}
public boolean isScreenOff() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ce468d0..ebe6a04 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -29,7 +29,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.MultiValueAlpha;
@@ -37,7 +36,6 @@
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.views.RecentsView;
-import com.android.systemui.animation.ViewRootSync;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.HashMap;
@@ -78,9 +76,6 @@
private boolean mShouldDelayLauncherStateAnim;
- // We skip any view synchronizations during init/destroy.
- private boolean mCanSyncViews;
-
private final StateManager.StateListener<LauncherState> mStateListener =
new StateManager.StateListener<LauncherState>() {
@@ -107,8 +102,6 @@
};
public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
- mCanSyncViews = false;
-
mControllers = controllers;
mLauncher = launcher;
@@ -128,13 +121,9 @@
updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
mLauncherState = launcher.getStateManager().getState();
applyState(0);
-
- mCanSyncViews = true;
}
public void onDestroy() {
- mCanSyncViews = false;
-
mIconAlignmentForResumedState.finishAnimation();
mIconAlignmentForGestureState.finishAnimation();
mIconAlignmentForLauncherState.finishAnimation();
@@ -142,8 +131,6 @@
mIconAlphaForHome.setConsumer(null);
mLauncher.getHotseat().setIconsAlpha(1f);
mLauncher.getStateManager().removeStateListener(mStateListener);
-
- mCanSyncViews = true;
}
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@@ -393,27 +380,6 @@
return;
}
float alignment = alignmentSupplier.get();
- float currentValue = mIconAlphaForHome.getValue();
- boolean taskbarWillBeVisible = alignment < 1;
- boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0)
- || (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
-
- // Sync the first frame where we swap taskbar and hotseat.
- if (firstFrameVisChanged && mCanSyncViews) {
- DeviceProfile dp = mLauncher.getDeviceProfile();
-
- // Do all the heavy work before the sync.
- mControllers.taskbarViewController.createIconAlignmentControllerIfNotExists(dp);
-
- ViewRootSync.synchronizeNextDraw(mLauncher.getHotseat(),
- mControllers.taskbarActivityContext.getDragLayer(),
- () -> updateIconAlignment(alignment));
- } else {
- updateIconAlignment(alignment);
- }
- }
-
- private void updateIconAlignment(float alignment) {
mControllers.taskbarViewController.setLauncherIconAlignment(
alignment, mLauncher.getDeviceProfile());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index ea4fe34..f9c8062 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -145,6 +145,7 @@
});
// TODO (b/198438631): configure for taskbar/context
container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
+ mControllers.taskbarDragController.addDragListener(container);
container.populateAndShow(icon,
mPopupDataProvider.getShortcutCountForItem(item),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 23beef0..a5c55b0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -24,4 +24,6 @@
public boolean setupUIVisible = false;
+ public boolean allAppsVisible = false;
+
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 6bc4c0a..f9a282b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -136,6 +136,8 @@
private boolean mIsSystemGestureInProgress;
private boolean mIsImeShowing;
+ private boolean mEnableManualStashingForTests = false;
+
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
flags -> {
@@ -199,12 +201,15 @@
*/
protected boolean supportsManualStashing() {
return supportsVisualStashing()
- && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || supportsStashingForTests());
+ && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || mEnableManualStashingForTests);
}
- private boolean supportsStashingForTests() {
- // TODO: enable this for tests that specifically check stash/unstash behavior.
- return false;
+ /**
+ * Enables support for manual stashing. This should only be used to add this functionality
+ * to Launcher specific tests.
+ */
+ public void enableManualStashingForTests(boolean enableManualStashing) {
+ mEnableManualStashingForTests = enableManualStashing;
}
/**
@@ -250,7 +255,11 @@
* Returns whether the taskbar is currently visible and in an app.
*/
public boolean isInAppAndNotStashed() {
- return !mIsStashed && (mState & FLAG_IN_APP) != 0;
+ return !mIsStashed && isInApp();
+ }
+
+ private boolean isInApp() {
+ return hasAnyFlag(FLAG_IN_APP);
}
/**
@@ -266,8 +275,15 @@
return mUnstashedHeight;
}
boolean isAnimating = mAnimator != null && mAnimator.isStarted();
- return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
- ? mStashedHeight : 0;
+ if (!mControllers.stashedHandleViewController.isStashedHandleVisible()
+ && isInApp()
+ && !isAnimating) {
+ // We are in a settled state where we're not showing the handle even though taskbar
+ // is stashed. This can happen for example when home button is disabled (see
+ // StashedHandleViewController#setIsHomeButtonDisabled()).
+ return 0;
+ }
+ return mStashedHeight;
}
return mUnstashedHeight;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 1320060..a89061b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -183,23 +183,15 @@
}
/**
- * Creates the icon alignment controller if it does not already exist.
- * @param launcherDp Launcher device profile.
- */
- public void createIconAlignmentControllerIfNotExists(DeviceProfile launcherDp) {
- if (mIconAlignControllerLazy == null) {
- mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
- }
- }
-
- /**
* Sets the taskbar icon alignment relative to Launcher hotseat icons
* @param alignmentRatio [0, 1]
* 0 => not aligned
* 1 => fully aligned
*/
public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
- createIconAlignmentControllerIfNotExists(launcherDp);
+ if (mIconAlignControllerLazy == null) {
+ mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+ }
mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
if (alignmentRatio <= 0 || alignmentRatio >= 1) {
// Cleanup lazy controller so that it is created again in next animation
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index b36b9f1..37cd753 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -25,6 +25,9 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.AlphabeticalAppsList;
+import com.android.launcher3.allapps.BaseAdapterProvider;
+import com.android.launcher3.allapps.BaseAllAppsAdapter;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
@@ -79,4 +82,11 @@
setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
return super.onApplyWindowInsets(insets);
}
+
+ @Override
+ protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<TaskbarAllAppsContext> mAppsList,
+ BaseAdapterProvider[] adapterProviders) {
+ return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
+ adapterProviders);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
index a67ca70..22fffdf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.graphics.Insets;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
@@ -38,6 +39,8 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarDragController;
import com.android.launcher3.taskbar.TaskbarStashController;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
@@ -166,7 +169,6 @@
super.onAttachedToWindow();
ViewTreeObserverWrapper.addOnComputeInsetsListener(
getViewTreeObserver(), this);
- mActivity.mAllAppsViewController.show();
}
@Override
@@ -181,6 +183,12 @@
}
@Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index cf9d778..9fca8eb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -38,6 +38,9 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.TaskbarSharedState;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.List;
import java.util.Optional;
@@ -61,7 +64,15 @@
private final TaskbarAllAppsProxyView mProxyView;
private final LayoutParams mLayoutParams;
+ private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ @Override
+ public void onTaskStackChanged() {
+ mProxyView.close(false);
+ }
+ };
+
private TaskbarControllers mControllers;
+ private TaskbarSharedState mSharedState;
/** Window context for all apps if it is open. */
private @Nullable TaskbarAllAppsContext mAllAppsContext;
@@ -77,9 +88,19 @@
}
/** Initialize the controller. */
- public void init(TaskbarControllers controllers) {
- if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
- mControllers = controllers;
+ public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
+ if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
+ return;
+ }
+ mControllers = controllers;
+ mSharedState = sharedState;
+
+ /*
+ * Recreate All Apps if it was open in the previous Taskbar instance (e.g. the configuration
+ * changed).
+ */
+ if (mSharedState.allAppsVisible) {
+ show(false);
}
}
@@ -112,16 +133,22 @@
/** Opens the {@link TaskbarAllAppsContainerView} in a new window. */
public void show() {
+ show(true);
+ }
+
+ private void show(boolean animate) {
if (mProxyView.isOpen()) {
return;
}
mProxyView.show();
+ mSharedState.allAppsVisible = true;
mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext,
this,
mControllers.taskbarStashController);
mAllAppsContext.getDragController().init(mControllers);
mTaskbarContext.addOnDeviceProfileChangeListener(this);
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
Optional.ofNullable(mAllAppsContext.getSystemService(WindowManager.class))
.ifPresent(m -> m.addView(mAllAppsContext.getDragLayer(), mLayoutParams));
@@ -129,6 +156,7 @@
mAllAppsContext.getAppsView().getFloatingHeaderView()
.findFixedRowByType(PredictionRowView.class)
.setPredictedApps(mPredictedApps);
+ mAllAppsContext.getAllAppsViewController().show(animate);
}
/** Closes the {@link TaskbarAllAppsContainerView}. */
@@ -148,6 +176,13 @@
return;
}
mProxyView.close(false);
+ mSharedState.allAppsVisible = false;
+ onDestroy();
+ }
+
+ /** Destroys the controller and any All Apps window if present. */
+ public void onDestroy() {
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
mTaskbarContext.removeOnDeviceProfileChangeListener(this);
Optional.ofNullable(mAllAppsContext)
.map(c -> c.getSystemService(WindowManager.class))
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 02aa3f2..5d2d72a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -50,17 +50,21 @@
}
/** Opens the all apps view. */
- void show() {
+ void show(boolean animate) {
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
return;
}
mIsOpen = true;
attachToContainer();
- mOpenCloseAnimator.setValues(
- PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
- mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
- mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start();
+ if (animate) {
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
+ mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start();
+ } else {
+ mTranslationShift = TRANSLATION_SHIFT_OPENED;
+ }
}
/** The apps container inside this view. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 648c486..4597422 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -53,8 +53,8 @@
}
/** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */
- void show() {
- mSlideInView.show();
+ void show(boolean animate) {
+ mSlideInView.show(animate);
}
/** Closes the {@link TaskbarAllAppsSlideInView}. */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 9240fb8..2f8e4d9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
-import android.view.Display;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -37,20 +36,6 @@
}
/**
- * Returns true if the display is an internal displays
- */
- public static boolean isInternalDisplay(Display display) {
- return display.getType() == Display.TYPE_INTERNAL;
- }
-
- /**
- * Returns a unique ID representing the display
- */
- public static String getUniqueId(Display display) {
- return display.getUniqueId();
- }
-
- /**
* Returns the minimum space that should be left empty at the end of hotseat
*/
public static int getHotseatEndOffset(Context context) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 0eaea83..84b3839 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -26,12 +26,14 @@
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.launcher3.testing.TestProtocol.BAD_STATE;
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 android.util.FloatProperty;
+import android.util.Log;
import androidx.annotation.NonNull;
@@ -65,7 +67,10 @@
ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, scaleAndOffset[1]);
TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
- getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
+ float recentsAlpha = state.overviewUi ? 1f : 0;
+ Log.d(BAD_STATE, "BaseRecentsViewStateController setState state=" + state
+ + ", alpha=" + recentsAlpha);
+ getContentAlphaProperty().set(mRecentsView, recentsAlpha);
getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
RECENTS_GRID_PROGRESS.set(mRecentsView,
state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
@@ -74,6 +79,8 @@
@Override
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation builder) {
+ Log.d(BAD_STATE, "BaseRecentsViewStateController setStateWithAnimation state=" + toState
+ + ", config.skipOverview=" + config.hasAnimationFlag(SKIP_OVERVIEW));
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
@@ -97,7 +104,10 @@
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
- setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
+ float recentsAlpha = toState.overviewUi ? 1 : 0;
+ Log.d(BAD_STATE, "BaseRecentsViewStateController setStateWithAnimationInternal toState="
+ + toState + ", alpha=" + recentsAlpha);
+ setter.setFloat(mRecentsView, getContentAlphaProperty(), recentsAlpha,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
setter.setFloat(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 32ce1c4..947d3e2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -118,8 +118,8 @@
if (isSplitSelectionState(currentState, toState)) {
// Animation to "dismiss" selected taskView
- PendingAnimation splitSelectInitAnimation =
- mRecentsView.createSplitSelectInitAnimation();
+ PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
+ toState.getTransitionDuration(mLauncher));
// Add properties to shift remaining taskViews to get out of placeholder view
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
toState.getSplitSelectTranslation(mLauncher), LINEAR);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index d8f694e..2ca59eb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -38,6 +38,7 @@
import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
@@ -54,6 +55,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.PointF;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -224,6 +226,7 @@
// Set RecentView's initial properties.
RECENTS_SCALE_PROPERTY.set(mRecentsView, fromState.getOverviewScaleAndOffset(mLauncher)[0]);
ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, 1f);
+ Log.d(BAD_STATE, "NBQSTC setupOverviewAnimators setContentAlpha=1");
mRecentsView.setContentAlpha(1);
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
mLauncher.getActionsView().getVisibilityAlpha().setValue(
@@ -242,6 +245,24 @@
QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR);
if (mRecentsView.getTaskViewCount() == 0) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
+ Log.d(BAD_STATE, "NBQSTC setupOverviewAnimators from: 0 to: 1");
+ xAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.d(BAD_STATE, "NBQSTC setupOverviewAnimators onStart");
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ float alpha = mRecentsView == null ? -1 : CONTENT_ALPHA.get(mRecentsView);
+ Log.d(BAD_STATE, "NBQSTC setupOverviewAnimators onCancel, alpha=" + alpha);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.d(BAD_STATE, "NBQSTC setupOverviewAnimators onEnd");
+ }
+ });
}
mXOverviewAnim = xAnim.createPlaybackController();
mXOverviewAnim.dispatchOnStart();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index e5cd53a..d1b0a9c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -36,6 +37,7 @@
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Launcher;
@@ -112,6 +114,7 @@
RECENTS_SCALE_PROPERTY.set(mOverviewPanel,
QUICK_SWITCH.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f);
ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mOverviewPanel, 1f);
+ Log.d(BAD_STATE, "QuickSwitchTouchController initCurrentAnimation setContentAlpha=1");
mOverviewPanel.setContentAlpha(1);
mCurrentAnimation = mLauncher.getStateManager()
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 6584f88..9686510 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -362,10 +362,9 @@
/** Gets the space that the overview actions will take, including bottom margin. */
private int getOverviewActionsHeight(Context context, DeviceProfile dp) {
- Resources res = context.getResources();
return OverviewActionsView.getOverviewActionsBottomMarginPx(getNavigationMode(context), dp)
+ OverviewActionsView.getOverviewActionsTopMarginPx(getNavigationMode(context), dp)
- + res.getDimensionPixelSize(R.dimen.overview_actions_height);
+ + dp.overviewActionsHeight;
}
/**
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
new file mode 100644
index 0000000..7abcbdb
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
+import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
+import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Handler;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.Pair;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.window.BackEvent;
+import android.window.IOnBackInvokedCallback;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.QuickstepTransitionManager;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+/**
+ * Controls the animation of swiping back and returning to launcher.
+ *
+ * This is a two part animation. The first part is an animation that tracks gesture location to
+ * scale and move the leaving app window. Once the gesture is committed, the second part takes over
+ * the app window and plays the rest of app close transitions in one go.
+ *
+ * This animation is used only for apps that enable back dispatching via
+ * {@link android.view.OnBackInvokedDispatcher}. The controller registers
+ * an {@link IOnBackInvokedCallback} with WM Shell and receives back dispatches when a back
+ * navigation to launcher starts.
+ *
+ * Apps using the legacy back dispatching will keep triggering the WALLPAPER_OPEN remote
+ * transition registered in {@link QuickstepTransitionManager}.
+ *
+ */
+public class LauncherBackAnimationController {
+ private static final int CANCEL_TRANSITION_DURATION = 150;
+ private static final String TAG = "LauncherBackAnimationController";
+ private final DeviceProfile mDeviceProfile;
+ private final QuickstepTransitionManager mQuickstepTransitionManager;
+ private final Matrix mTransformMatrix = new Matrix();
+ private final RectF mTargetRectF = new RectF();
+ private final RectF mStartRectF = new RectF();
+ private final RectF mCurrentRect = new RectF();
+ private final BaseQuickstepLauncher mLauncher;
+ private final int mWindowScaleMarginX;
+ private final int mWindowScaleMarginY;
+ private final float mWindowScaleEndCornerRadius;
+ private final float mWindowScaleStartCornerRadius;
+
+ private RemoteAnimationTargetCompat mBackTarget;
+ private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private boolean mSpringAnimationInProgress = false;
+ private boolean mAnimatorSetInProgress = false;
+ @BackEvent.SwipeEdge
+ private int mSwipeEdge;
+ private float mBackProgress = 0;
+ private boolean mBackInProgress = false;
+
+ public LauncherBackAnimationController(
+ DeviceProfile deviceProfile,
+ BaseQuickstepLauncher launcher,
+ QuickstepTransitionManager quickstepTransitionManager) {
+ mDeviceProfile = deviceProfile;
+ mLauncher = launcher;
+ mQuickstepTransitionManager = quickstepTransitionManager;
+ mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
+ mLauncher.getResources())
+ ? mLauncher.getResources().getDimensionPixelSize(
+ R.dimen.swipe_back_window_corner_radius)
+ : 0;
+ mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+ mWindowScaleMarginX = mLauncher.getResources().getDimensionPixelSize(
+ R.dimen.swipe_back_window_scale_x_margin);
+ mWindowScaleMarginY = mLauncher.getResources().getDimensionPixelSize(
+ R.dimen.swipe_back_window_scale_y_margin);
+ }
+
+ /**
+ * Registers {@link IOnBackInvokedCallback} to receive back dispatches from shell.
+ * @param handler Handler to the thread to run the animations on.
+ */
+ public void registerBackCallbacks(Handler handler) {
+ SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+ if (systemUiProxy == null) {
+ Log.e(TAG, "SystemUiProxy is null. Skip registering back invocation callbacks");
+ return;
+ }
+ systemUiProxy.setBackToLauncherCallback(
+ new IOnBackInvokedCallback.Stub() {
+ @Override
+ public void onBackCancelled() {
+ handler.post(() -> resetPositionAnimated());
+ }
+
+ @Override
+ public void onBackInvoked() {
+ handler.post(() -> startTransition());
+ }
+
+ @Override
+ public void onBackProgressed(BackEvent backEvent) {
+ mBackProgress = backEvent.getProgress();
+ // TODO: Update once the interpolation curve spec is finalized.
+ mBackProgress =
+ 1 - (1 - mBackProgress) * (1 - mBackProgress) * (1
+ - mBackProgress);
+ if (!mBackInProgress) {
+ startBack(backEvent);
+ } else {
+ updateBackProgress(mBackProgress);
+ }
+ }
+
+ public void onBackStarted() { }
+ });
+ }
+
+ private void resetPositionAnimated() {
+ ValueAnimator cancelAnimator = ValueAnimator.ofFloat(mBackProgress, 0);
+ cancelAnimator.setDuration(CANCEL_TRANSITION_DURATION);
+ cancelAnimator.addUpdateListener(
+ animation -> {
+ updateBackProgress((float) animation.getAnimatedValue());
+ });
+ cancelAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishAnimation();
+ }
+ });
+ cancelAnimator.start();
+ }
+
+ /** Unregisters the back to launcher callback in shell. */
+ public void unregisterBackCallbacks() {
+ SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+ if (systemUiProxy != null) {
+ systemUiProxy.clearBackToLauncherCallback();
+ }
+ }
+
+ private void startBack(BackEvent backEvent) {
+ mBackInProgress = true;
+ RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget();
+
+ if (appTarget == null) {
+ return;
+ }
+
+ mTransaction.show(appTarget.leash).apply();
+ mTransaction.setAnimationTransaction();
+ mBackTarget = new RemoteAnimationTargetCompat(appTarget);
+ mSwipeEdge = backEvent.getSwipeEdge();
+ float screenWidth = mDeviceProfile.widthPx;
+ float screenHeight = mDeviceProfile.heightPx;
+ float targetHeight = screenHeight - 2 * mWindowScaleMarginY;
+ float targetWidth = targetHeight * screenWidth / screenHeight;
+ float left;
+ if (mSwipeEdge == BackEvent.EDGE_LEFT) {
+ left = screenWidth - targetWidth - mWindowScaleMarginX;
+ } else {
+ left = mWindowScaleMarginX;
+ }
+ float top = mWindowScaleMarginY;
+ // TODO(b/218916755): Offset start rectangle in multiwindow mode.
+ mStartRectF.set(0, 0, screenWidth, screenHeight);
+ mTargetRectF.set(left, top, targetWidth + left, targetHeight + top);
+ }
+
+ private void updateBackProgress(float progress) {
+ if (mBackTarget == null) {
+ return;
+ }
+
+ mCurrentRect.set(
+ MathUtils.lerp(mStartRectF.left, mTargetRectF.left, progress),
+ MathUtils.lerp(mStartRectF.top, mTargetRectF.top, progress),
+ MathUtils.lerp(mStartRectF.right, mTargetRectF.right, progress),
+ MathUtils.lerp(mStartRectF.bottom, mTargetRectF.bottom, progress));
+ SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder builder =
+ new SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder(mBackTarget.leash);
+
+ Rect currentRect = new Rect();
+ mCurrentRect.round(currentRect);
+
+ // Scale the target window to match the currentRectF.
+ final float scale = mCurrentRect.width() / mStartRectF.width();
+ mTransformMatrix.reset();
+ mTransformMatrix.setScale(scale, scale);
+ mTransformMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top);
+ Rect startRect = new Rect();
+ mStartRectF.round(startRect);
+ float cornerRadius = Utilities.mapRange(
+ progress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
+ builder.withMatrix(mTransformMatrix)
+ .withWindowCrop(startRect)
+ .withCornerRadius(cornerRadius);
+ SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams = builder.build();
+
+ if (surfaceParams.surface.isValid()) {
+ surfaceParams.applyTo(mTransaction);
+ }
+ mTransaction.apply();
+ }
+
+ private void startTransition() {
+ if (mBackTarget == null) {
+ // Trigger transition system instead of custom transition animation.
+ finishAnimation();
+ return;
+ }
+ if (mLauncher.isDestroyed()) {
+ return;
+ }
+ // TODO: Catch the moment when launcher becomes visible after the top app un-occludes
+ // launcher and start animating afterwards. Currently we occasionally get a flicker from
+ // animating when launcher is still invisible.
+ if (mLauncher.hasSomeInvisibleFlag(PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION)) {
+ mLauncher.addForceInvisibleFlag(INVISIBLE_BY_PENDING_FLAGS);
+ mLauncher.getStateManager().moveToRestState();
+ }
+
+ Pair<RectFSpringAnim, AnimatorSet> pair =
+ mQuickstepTransitionManager.createWallpaperOpenAnimations(
+ new RemoteAnimationTargetCompat[]{mBackTarget},
+ new RemoteAnimationTargetCompat[]{},
+ false /* fromUnlock */,
+ mCurrentRect);
+ startTransitionAnimations(pair.first, pair.second);
+ mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
+ }
+
+ private void finishAnimation() {
+ mBackTarget = null;
+ mBackInProgress = false;
+ mBackProgress = 0;
+ mSwipeEdge = BackEvent.EDGE_LEFT;
+ mTransformMatrix.reset();
+ mTargetRectF.setEmpty();
+ mCurrentRect.setEmpty();
+ mStartRectF.setEmpty();
+ mAnimatorSetInProgress = false;
+ mSpringAnimationInProgress = false;
+ SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+ if (systemUiProxy != null) {
+ SystemUiProxy.INSTANCE.getNoCreate().onBackToLauncherAnimationFinished();
+ }
+ }
+
+ private void startTransitionAnimations(RectFSpringAnim springAnim, AnimatorSet anim) {
+ mAnimatorSetInProgress = anim != null;
+ mSpringAnimationInProgress = springAnim != null;
+ if (springAnim != null) {
+ springAnim.addAnimatorListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSpringAnimationInProgress = false;
+ tryFinishBackAnimation();
+ }
+ }
+ );
+ }
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimatorSetInProgress = false;
+ tryFinishBackAnimation();
+ }
+ });
+ anim.start();
+ }
+
+ private void tryFinishBackAnimation() {
+ if (!mSpringAnimationInProgress && !mAnimatorSetInProgress) {
+ finishAnimation();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index af6cb84..bc7a6ae 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -233,7 +233,8 @@
return mActivity.getFirstMatchForAppClose(launchCookieItemId,
runningTaskView.getTask().key.getComponent().getPackageName(),
- UserHandle.of(runningTaskView.getTask().key.userId));
+ UserHandle.of(runningTaskView.getTask().key.userId),
+ false /* supportsAllAppsState */);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index e5c7b0e..895cf89 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -35,11 +35,11 @@
import com.android.launcher3.ResourceUtils;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.DisplayController.NavigationMode;
+import com.android.launcher3.util.window.CachedDisplayInfo;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
-import java.util.Objects;
/**
* Maintains state for supporting nav bars and tracking their gestures in multiple orientations.
@@ -51,55 +51,17 @@
*/
class OrientationTouchTransformer {
- private static class CurrentDisplay {
- public Point size;
- public int rotation;
-
- CurrentDisplay() {
- this.size = new Point(0, 0);
- this.rotation = 0;
- }
-
- CurrentDisplay(Point size, int rotation) {
- this.size = size;
- this.rotation = rotation;
- }
-
- @Override
- public String toString() {
- return "CurrentDisplay:"
- + " rotation: " + rotation
- + " size: " + size;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- CurrentDisplay display = (CurrentDisplay) o;
- if (rotation != display.rotation) return false;
-
- return Objects.equals(size, display.size);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(size, rotation);
- }
- };
-
private static final String TAG = "OrientationTouchTransformer";
private static final boolean DEBUG = false;
private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
- private final Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
- new HashMap<CurrentDisplay, OrientationRectF>();
+ private final Map<CachedDisplayInfo, OrientationRectF> mSwipeTouchRegions =
+ new HashMap<CachedDisplayInfo, OrientationRectF>();
private final RectF mAssistantLeftRegion = new RectF();
private final RectF mAssistantRightRegion = new RectF();
private final RectF mOneHandedModeRegion = new RectF();
- private CurrentDisplay mCurrentDisplay = new CurrentDisplay();
+ private CachedDisplayInfo mCachedDisplayInfo = new CachedDisplayInfo();
private int mNavBarGesturalHeight;
private final int mNavBarLargerGesturalHeight;
private boolean mEnableMultipleRegions;
@@ -184,22 +146,22 @@
* @see #enableMultipleRegions(boolean, Info)
*/
void createOrAddTouchRegion(Info info) {
- mCurrentDisplay = new CurrentDisplay(info.currentSize, info.rotation);
+ mCachedDisplayInfo = new CachedDisplayInfo(info.currentSize, info.rotation);
if (mQuickStepStartingRotation > QUICKSTEP_ROTATION_UNINITIALIZED
- && mCurrentDisplay.rotation == mQuickStepStartingRotation) {
+ && mCachedDisplayInfo.rotation == mQuickStepStartingRotation) {
// User already was swiping and the current screen is same rotation as the starting one
// Remove active nav bars in other rotations except for the one we started out in
resetSwipeRegions(info);
return;
}
- OrientationRectF region = mSwipeTouchRegions.get(mCurrentDisplay);
+ OrientationRectF region = mSwipeTouchRegions.get(mCachedDisplayInfo);
if (region != null) {
return;
}
if (mEnableMultipleRegions) {
- mSwipeTouchRegions.put(mCurrentDisplay, createRegionForDisplay(info));
+ mSwipeTouchRegions.put(mCachedDisplayInfo, createRegionForDisplay(info));
} else {
resetSwipeRegions(info);
}
@@ -245,31 +207,31 @@
*/
private void resetSwipeRegions(Info region) {
if (DEBUG) {
- Log.d(TAG, "clearing all regions except rotation: " + mCurrentDisplay.rotation);
+ Log.d(TAG, "clearing all regions except rotation: " + mCachedDisplayInfo.rotation);
}
- mCurrentDisplay = new CurrentDisplay(region.currentSize, region.rotation);
- OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
+ mCachedDisplayInfo = new CachedDisplayInfo(region.currentSize, region.rotation);
+ OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCachedDisplayInfo);
if (regionToKeep == null) {
regionToKeep = createRegionForDisplay(region);
}
mSwipeTouchRegions.clear();
- mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
+ mSwipeTouchRegions.put(mCachedDisplayInfo, regionToKeep);
updateAssistantRegions(regionToKeep);
}
private void resetSwipeRegions() {
- OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
+ OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCachedDisplayInfo);
mSwipeTouchRegions.clear();
if (regionToKeep != null) {
- mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
+ mSwipeTouchRegions.put(mCachedDisplayInfo, regionToKeep);
updateAssistantRegions(regionToKeep);
}
}
private OrientationRectF createRegionForDisplay(Info display) {
if (DEBUG) {
- Log.d(TAG, "creating rotation region for: " + mCurrentDisplay.rotation
+ Log.d(TAG, "creating rotation region for: " + mCachedDisplayInfo.rotation
+ " with mode: " + mMode + " displayRotation: " + display.rotation);
}
@@ -368,7 +330,7 @@
true);
}
} else {
- mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation,
+ mLastRectTouched.applyTransformFromRotation(event, mCachedDisplayInfo.rotation,
true);
}
break;
@@ -387,7 +349,7 @@
true);
}
} else {
- mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation,
+ mLastRectTouched.applyTransformFromRotation(event, mCachedDisplayInfo.rotation,
true);
}
mLastRectTouched = null;
@@ -403,11 +365,12 @@
if (rect == null) {
continue;
}
- if (rect.applyTransformFromRotation(event, mCurrentDisplay.rotation, false)) {
+ if (rect.applyTransformFromRotation(
+ event, mCachedDisplayInfo.rotation, false)) {
mLastRectTouched = rect;
mActiveTouchRotation = rect.getRotation();
if (mEnableMultipleRegions
- && mCurrentDisplay.rotation == mActiveTouchRotation) {
+ && mCachedDisplayInfo.rotation == mActiveTouchRotation) {
// TODO(b/154580671) might make this block unnecessary
// Start a touch session for the default nav region for the display
mQuickStepStartingRotation = mLastRectTouched.getRotation();
@@ -430,7 +393,7 @@
pw.println(" lastTouchedRegion=" + mLastRectTouched);
pw.println(" multipleRegionsEnabled=" + mEnableMultipleRegions);
StringBuilder regions = new StringBuilder(" currentTouchableRotations=");
- for (CurrentDisplay key: mSwipeTouchRegions.keySet()) {
+ for (CachedDisplayInfo key: mSwipeTouchRegions.keySet()) {
OrientationRectF rectF = mSwipeTouchRegions.get(key);
regions.append(rectF).append(" ");
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index db92e33..4f0b976 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.Utilities.createHomeIntent;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
@@ -38,6 +39,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
import android.view.Display;
import android.view.SurfaceControl.Transaction;
import android.view.View;
@@ -135,8 +137,8 @@
SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
SplitSelectStateController controller =
- new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
- getStateManager(), null /*depthController*/);
+ new SplitSelectStateController(this, mHandler, getStateManager(),
+ null /* depthController */);
mDragLayer.recreateControllers();
mFallbackRecentsView.init(mActionsView, controller);
@@ -312,6 +314,7 @@
protected void onStart() {
// Set the alpha to 1 before calling super, as it may get set back to 0 due to
// onActivityStart callback.
+ Log.d(BAD_STATE, "RecentsActivity onStart mFallbackRecentsView.setContentAlpha(1)");
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
mFallbackRecentsView.updateLocusId();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 667ea14..5ef89d3 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -39,6 +39,7 @@
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import android.window.IOnBackInvokedCallback;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
@@ -50,6 +51,7 @@
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
+import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.pip.IPipAnimationListener;
@@ -82,6 +84,7 @@
private IShellTransitions mShellTransitions;
private IStartingWindow mStartingWindow;
private IRecentTasks mRecentTasks;
+ private IBackAnimation mBackAnimation;
private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
MAIN_EXECUTOR.execute(() -> clearProxy());
};
@@ -96,6 +99,7 @@
private ILauncherUnlockAnimationController mPendingLauncherUnlockAnimationController;
private IRecentTasksListener mRecentTasksListener;
private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
+ private IOnBackInvokedCallback mBackToLauncherCallback;
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -162,8 +166,8 @@
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
IOneHanded oneHanded, IShellTransitions shellTransitions,
IStartingWindow startingWindow, IRecentTasks recentTasks,
- ISysuiUnlockAnimationController sysuiUnlockAnimationController) {
-
+ ISysuiUnlockAnimationController sysuiUnlockAnimationController,
+ IBackAnimation backAnimation) {
unlinkToDeath();
mSystemUiProxy = proxy;
mPip = pip;
@@ -173,6 +177,7 @@
mStartingWindow = startingWindow;
mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
mRecentTasks = recentTasks;
+ mBackAnimation = backAnimation;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
if (mPipAnimationListener != null && mPip != null) {
@@ -195,6 +200,9 @@
if (mRecentTasksListener != null && mRecentTasks != null) {
registerRecentTasksListener(mRecentTasksListener);
}
+ if (mBackAnimation != null && mBackToLauncherCallback != null) {
+ setBackToLauncherCallback(mBackToLauncherCallback);
+ }
if (mPendingSetNavButtonAlpha != null) {
mPendingSetNavButtonAlpha.run();
@@ -203,7 +211,7 @@
}
public void clearProxy() {
- setProxy(null, null, null, null, null, null, null, null);
+ setProxy(null, null, null, null, null, null, null, null, null);
}
// TODO(141886704): Find a way to remove this
@@ -822,6 +830,50 @@
mRecentTasksListener = null;
}
+ //
+ // Back navigation transitions
+ //
+
+ /** Sets the launcher {@link android.window.IOnBackInvokedCallback} to shell */
+ public void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
+ mBackToLauncherCallback = callback;
+ if (mBackAnimation == null) {
+ return;
+ }
+ try {
+ mBackAnimation.setBackToLauncherCallback(callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed call setBackToLauncherCallback", e);
+ }
+ }
+
+ /** Clears the previously registered {@link IOnBackInvokedCallback}. */
+ public void clearBackToLauncherCallback() {
+ mBackToLauncherCallback = null;
+ if (mBackAnimation == null) {
+ return;
+ }
+ try {
+ mBackAnimation.clearBackToLauncherCallback();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed call clearBackToLauncherCallback", e);
+ }
+ }
+
+ /**
+ * Notifies shell that all back to launcher animations have finished (including the transition
+ * that plays after the gesture is committed and before the app is closed.
+ */
+ public void onBackToLauncherAnimationFinished() {
+ if (mBackAnimation != null) {
+ try {
+ mBackAnimation.onBackToLauncherAnimationFinished();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onBackAnimationFinished", e);
+ }
+ }
+ }
+
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
if (mRecentTasks != null) {
try {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index e67b0a5..516ecd4 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -37,6 +37,7 @@
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -55,6 +56,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
+import android.util.Log;
import android.view.SurfaceControl;
import android.view.View;
import android.window.TransitionInfo;
@@ -577,6 +579,29 @@
launcherAnim = dp.isTablet
? ObjectAnimator.ofFloat(recentsView, RecentsView.CONTENT_ALPHA, 0)
: recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
+ if (dp.isTablet) {
+ Log.d(BAD_STATE, "TVU composeRecentsLaunchAnimator alpha=" + 0);
+ launcherAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.d(BAD_STATE, "TVU composeRecentsLaunchAnimator onStart");
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ float alpha = recentsView == null
+ ? -1
+ : RecentsView.CONTENT_ALPHA.get(recentsView);
+ Log.d(BAD_STATE, "TVU composeRecentsLaunchAnimator onCancel, alpha="
+ + alpha);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.d(BAD_STATE, "TVU composeRecentsLaunchAnimator onEnd");
+ }
+ });
+ }
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 021048a..ff67b09 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -26,6 +26,7 @@
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -106,6 +107,7 @@
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.shared.tracing.ProtoTraceable;
+import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.recents.IRecentTasks;
@@ -166,10 +168,12 @@
bundle.getBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER));
IRecentTasks recentTasks = IRecentTasks.Stub.asInterface(
bundle.getBinder(KEY_EXTRA_RECENT_TASKS));
+ IBackAnimation backAnimation = IBackAnimation.Stub.asInterface(
+ bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION));
MAIN_EXECUTOR.execute(() -> {
SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
splitscreen, onehanded, shellTransitions, startingWindow, recentTasks,
- launcherUnlockAnimationController);
+ launcherUnlockAnimationController, backAnimation);
TouchInteractionService.this.initInputMonitor();
preloadOverview(true /* fromInit */);
});
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index ff175f1..5094d49 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -111,7 +111,8 @@
RecentsState currentState = mActivity.getStateManager().getState();
if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
- setter.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
+ setter.add(mRecentsView.createSplitSelectInitAnimation(
+ state.getTransitionDuration(mActivity)).buildAnim());
}
Pair<FloatProperty, FloatProperty> taskViewsFloat =
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index c7a8382..e6f73dc 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.fallback;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
@@ -27,6 +28,7 @@
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -221,6 +223,7 @@
setOverviewStateEnabled(true);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.isFullScreen());
+ Log.d(BAD_STATE, "FRV onStateTransitionStart setFreezeVisibility=true, toState=" + toState);
setFreezeViewVisibility(true);
}
@@ -232,6 +235,8 @@
}
boolean isOverlayEnabled = finalState == DEFAULT || finalState == MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
+ Log.d(BAD_STATE, "FRV onStateTransitionComplete setFreezeVisibility=false, finalState="
+ + finalState);
setFreezeViewVisibility(false);
if (isOverlayEnabled) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
index dbe260a..7836ece 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
@@ -22,6 +22,7 @@
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.quickstep.InputConsumer;
@@ -36,14 +37,20 @@
private final GestureDetector mLongPressDetector;
private final float mSquaredTouchSlop;
+
private float mDownX, mDownY;
private boolean mCanceledUnstashHint;
+ private final float mUnstashArea;
+ private final float mScreenWidth;
public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
super(delegate, inputMonitor);
mTaskbarActivityContext = taskbarActivityContext;
mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
+ mScreenWidth = context.getResources().getDisplayMetrics().widthPixels;
+ mUnstashArea = context.getResources()
+ .getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
@@ -69,11 +76,13 @@
final float y = ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
- mDownX = x;
- mDownY = y;
- mTaskbarActivityContext.startTaskbarUnstashHint(
- /* animateForward = */ true);
- mCanceledUnstashHint = false;
+ if (isInArea(x)) {
+ mDownX = x;
+ mDownY = y;
+ mTaskbarActivityContext.startTaskbarUnstashHint(
+ /* animateForward = */ true);
+ mCanceledUnstashHint = false;
+ }
break;
case MotionEvent.ACTION_MOVE:
if (!mCanceledUnstashHint
@@ -95,10 +104,18 @@
}
}
+ private boolean isInArea(float x) {
+ float areaFromMiddle = mUnstashArea / 2.0f;
+ float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);
+ return distFromMiddle < areaFromMiddle;
+ }
+
private void onLongPressDetected(MotionEvent motionEvent) {
- if (mTaskbarActivityContext != null
- && mTaskbarActivityContext.onLongPressToUnstashTaskbar()) {
- setActive(motionEvent);
+ if (mTaskbarActivityContext != null && isInArea(motionEvent.getRawX())) {
+ boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar();
+ if (taskBarPressed) {
+ setActive(motionEvent);
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 1c3e784..5ef9a9b 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -52,6 +52,7 @@
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.quickstep.AnimatedFloat;
@@ -110,6 +111,12 @@
mContentView = findViewById(R.id.content_view);
mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift);
+ boolean isTablet = InvariantDeviceProfile.INSTANCE.get(getApplicationContext())
+ .getDeviceProfile(this).isTablet;
+ TextView subtitle = findViewById(R.id.subtitle);
+ subtitle.setText(isTablet
+ ? R.string.allset_description_tablet : R.string.allset_description);
+
TextView tv = findViewById(R.id.navigation_settings);
tv.setTextColor(accentColor);
tv.setOnClickListener(v -> {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 49d8203..b686505 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -57,14 +57,14 @@
@LayoutRes
int getMockAppTaskCurrentPageLayoutResId() {
return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_foldable_mock_conversation
+ ? R.layout.gesture_tutorial_tablet_mock_conversation
: R.layout.gesture_tutorial_mock_conversation;
}
@LayoutRes
int getMockAppTaskPreviousPageLayoutResId() {
return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_foldable_mock_conversation_list
+ ? R.layout.gesture_tutorial_tablet_mock_conversation_list
: R.layout.gesture_tutorial_mock_conversation_list;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 0bc3691..6254313 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -51,7 +51,7 @@
@Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_foldable_mock_webpage
+ ? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index f308f27..09640c6 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -61,7 +61,7 @@
@Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_foldable_mock_conversation_list
+ ? R.layout.gesture_tutorial_tablet_mock_conversation_list
: R.layout.gesture_tutorial_mock_conversation_list;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 2db4c20..b70c411 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -280,6 +280,15 @@
super(context, deviceState, gestureState);
mRemoteTargetHandles[0] = new RemoteTargetGluer.RemoteTargetHandle(
mRemoteTargetHandles[0].getTaskViewSimulator(), new FakeTransformParams());
+
+ for (RemoteTargetGluer.RemoteTargetHandle handle
+ : mTargetGluer.getRemoteTargetHandles()) {
+ // Override home screen rotation preference so that home and overview animations
+ // work properly
+ handle.getTaskViewSimulator()
+ .getOrientationState()
+ .ignoreAllowHomeRotationPreference();
+ }
}
void initDp(DeviceProfile dp) {
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 4145393..3c88988 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -49,6 +49,7 @@
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
@@ -63,7 +64,7 @@
private static final String TAG = "TutorialController";
- private static final float FINGER_DOT_VISIBLE_ALPHA = 0.6f;
+ private static final float FINGER_DOT_VISIBLE_ALPHA = 0.7f;
private static final float FINGER_DOT_SMALL_SCALE = 0.7f;
private static final int FINGER_DOT_ANIMATION_DURATION_MILLIS = 500;
@@ -73,7 +74,7 @@
private static final int FEEDBACK_ANIMATION_MS = 133;
private static final int RIPPLE_VISIBLE_MS = 300;
private static final int GESTURE_ANIMATION_DELAY_MS = 1500;
- private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 4000;
+ private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 2000;
private static final long GESTURE_ANIMATION_PAUSE_DURATION_MILLIS = 1000;
final TutorialFragment mTutorialFragment;
@@ -185,7 +186,9 @@
@LayoutRes
protected int getMockHotseatResId() {
return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_foldable_mock_hotseat
+ ? (mTutorialFragment.isFoldable()
+ ? R.layout.gesture_tutorial_foldable_mock_hotseat
+ : R.layout.gesture_tutorial_tablet_mock_hotseat)
: R.layout.gesture_tutorial_mock_hotseat;
}
@@ -319,6 +322,9 @@
}
void hideFeedback() {
+ if (mFeedbackView.getVisibility() != View.VISIBLE) {
+ return;
+ }
cancelQueuedGestureAnimation();
mFeedbackView.clearAnimation();
mFeedbackView.setVisibility(View.INVISIBLE);
@@ -515,20 +521,45 @@
}
private void updateLayout() {
- if (mContext != null) {
- RelativeLayout.LayoutParams feedbackLayoutParams =
- (RelativeLayout.LayoutParams) mFeedbackView.getLayoutParams();
- feedbackLayoutParams.setMarginStart(mContext.getResources().getDimensionPixelSize(
- mTutorialFragment.isLargeScreen()
- ? R.dimen.gesture_tutorial_foldable_feedback_margin_start_end
- : R.dimen.gesture_tutorial_feedback_margin_start_end));
- feedbackLayoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize(
- mTutorialFragment.isLargeScreen()
- ? R.dimen.gesture_tutorial_foldable_feedback_margin_start_end
- : R.dimen.gesture_tutorial_feedback_margin_start_end));
-
- mFakeTaskbarView.setVisibility(mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
+ if (mContext == null) {
+ return;
}
+ RelativeLayout.LayoutParams feedbackLayoutParams =
+ (RelativeLayout.LayoutParams) mFeedbackView.getLayoutParams();
+ feedbackLayoutParams.setMarginStart(mContext.getResources().getDimensionPixelSize(
+ mTutorialFragment.isLargeScreen()
+ ? R.dimen.gesture_tutorial_tablet_feedback_margin_start_end
+ : R.dimen.gesture_tutorial_feedback_margin_start_end));
+ feedbackLayoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize(
+ mTutorialFragment.isLargeScreen()
+ ? R.dimen.gesture_tutorial_tablet_feedback_margin_start_end
+ : R.dimen.gesture_tutorial_feedback_margin_start_end));
+ feedbackLayoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
+ mTutorialFragment.isLargeScreen()
+ ? R.dimen.gesture_tutorial_tablet_feedback_margin_top
+ : R.dimen.gesture_tutorial_feedback_margin_top);
+
+ mFakeTaskbarView.setVisibility(mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
+
+ RelativeLayout.LayoutParams hotseatLayoutParams =
+ (RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
+ if (!mTutorialFragment.isLargeScreen()) {
+ DeviceProfile dp = mTutorialFragment.getDeviceProfile();
+ dp.updateIsSeascape(mContext);
+
+ hotseatLayoutParams.addRule(dp.isLandscape
+ ? (dp.isSeascape()
+ ? RelativeLayout.ALIGN_PARENT_START
+ : RelativeLayout.ALIGN_PARENT_END)
+ : RelativeLayout.ALIGN_PARENT_BOTTOM);
+ } else {
+ hotseatLayoutParams.width = RelativeLayout.LayoutParams.MATCH_PARENT;
+ hotseatLayoutParams.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
+ hotseatLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ hotseatLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
+ hotseatLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
+ }
+ mFakeHotseatView.setLayoutParams(hotseatLayoutParams);
}
private AlertDialog createSkipTutorialDialog() {
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 2fd7cde..4b836e3 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -20,7 +20,6 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.graphics.Insets;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -41,6 +40,7 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
@@ -67,7 +67,9 @@
private boolean mFragmentStopped = false;
+ private DeviceProfile mDeviceProfile;
private boolean mIsLargeScreen;
+ private boolean mIsFoldable;
public static TutorialFragment newInstance(TutorialType tutorialType, boolean gestureComplete) {
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
@@ -139,22 +141,24 @@
mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
mNavBarGestureHandler = new NavBarGestureHandler(getContext());
- mIsLargeScreen = InvariantDeviceProfile.INSTANCE.get(getContext())
- .getDeviceProfile(getContext()).isTablet;
-
- if (mIsLargeScreen) {
- ((Activity) getContext()).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
- } else {
- // Temporary until UI mocks for landscape mode for phones are created.
- ((Activity) getContext()).setRequestedOrientation(
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
+ mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(getContext())
+ .getDeviceProfile(getContext());
+ mIsLargeScreen = mDeviceProfile.isTablet;
+ mIsFoldable = mDeviceProfile.isTwoPanels;
}
public boolean isLargeScreen() {
return mIsLargeScreen;
}
+ public boolean isFoldable() {
+ return mIsFoldable;
+ }
+
+ DeviceProfile getDeviceProfile() {
+ return mDeviceProfile;
+ }
+
@Override
public void onDestroy() {
super.onDestroy();
@@ -296,6 +300,9 @@
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (mTutorialController != null) {
+ mTutorialController.hideFeedback();
+ }
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
| mNavBarGestureHandler.onTouch(view, motionEvent);
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java b/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java
index d880d74..ae0e725 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialStepIndicator.java
@@ -23,7 +23,6 @@
import android.widget.LinearLayout;
import androidx.appcompat.content.res.AppCompatResources;
-import androidx.core.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -87,8 +86,10 @@
for (int i = mTotalSteps; i < getChildCount(); i++) {
removeViewAt(i);
}
- int stepIndicatorColor = GraphicsUtils.getAttrColor(
+ int activeStepIndicatorColor = GraphicsUtils.getAttrColor(
getContext(), android.R.attr.textColorPrimary);
+ int inactiveStepIndicatorColor = GraphicsUtils.getAttrColor(
+ getContext(), android.R.attr.textColorSecondaryInverse);
for (int i = 0; i < mTotalSteps; i++) {
Drawable pageIndicatorPillDrawable = AppCompatResources.getDrawable(
getContext(), R.drawable.tutorial_step_indicator_pill);
@@ -107,10 +108,9 @@
}
if (pageIndicatorPillDrawable != null) {
if (i < mCurrentStep) {
- pageIndicatorPillDrawable.setTint(stepIndicatorColor);
+ pageIndicatorPillDrawable.setTint(activeStepIndicatorColor);
} else {
- pageIndicatorPillDrawable.setTint(
- ColorUtils.setAlphaComponent(stepIndicatorColor, 0x22));
+ pageIndicatorPillDrawable.setTint(inactiveStepIndicatorColor);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index d85515a..f6002ec 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -19,6 +19,7 @@
import static androidx.core.util.Preconditions.checkNotNull;
import static androidx.core.util.Preconditions.checkState;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
@@ -82,6 +83,7 @@
public class StatsLogCompatManager extends StatsLogManager {
private static final String TAG = "StatsLog";
+ private static final String LATENCY_TAG = "StatsLatencyLog";
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
@@ -196,7 +198,9 @@
private static class StatsCompatLogger implements StatsLogger {
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
-
+ static {
+ DEFAULT_ITEM_INFO.itemType = ITEM_TYPE_NON_ACTIONABLE;
+ }
private final Context mContext;
private final Optional<ActivityContext> mActivityContext;
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
@@ -388,13 +392,21 @@
if (IS_VERBOSE) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
event.getId() + "";
-
- Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
- ? String.format("\n%s (State:%s->%s)\n%s", name, getStateString(srcState),
- getStateString(dstState), atomInfo)
- : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name,
- getStateString(srcState), getStateString(dstState), instanceId,
- atomInfo));
+ StringBuilder logStringBuilder = new StringBuilder("\n");
+ if (instanceId != DEFAULT_INSTANCE_ID) {
+ logStringBuilder.append(String.format("InstanceId:%s ", instanceId));
+ }
+ logStringBuilder.append(name);
+ if (srcState != LAUNCHER_STATE_UNSPECIFIED
+ || dstState != LAUNCHER_STATE_UNSPECIFIED) {
+ logStringBuilder.append(
+ String.format("(State:%s->%s)", getStateString(srcState),
+ getStateString(dstState)));
+ }
+ if (mItemInfo != DEFAULT_ITEM_INFO) {
+ logStringBuilder.append("\n").append(atomInfo);
+ }
+ Log.d(TAG, logStringBuilder.toString());
}
for (StatsLogConsumer consumer : LOGS_CONSUMER) {
@@ -479,11 +491,12 @@
if (IS_VERBOSE) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
event.getId() + "";
-
- Log.d(TAG, mInstanceId == DEFAULT_INSTANCE_ID
- ? String.format("\n%s = %dms\n", name, mLatencyInMillis)
- : String.format("\n%s = %dms (InstanceId:%s)\n", name,
- mLatencyInMillis, mInstanceId));
+ StringBuilder logStringBuilder = new StringBuilder("\n");
+ if (mInstanceId != DEFAULT_INSTANCE_ID) {
+ logStringBuilder.append(String.format("InstanceId:%s ", mInstanceId));
+ }
+ logStringBuilder.append(String.format("%s=%sms", name, mLatencyInMillis));
+ Log.d(LATENCY_TAG, logStringBuilder.toString());
}
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_LATENCY,
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 5c72c8f..edaa326 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -15,10 +15,13 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.util.Log;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -27,6 +30,8 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.views.RecentsView;
+import java.util.Arrays;
+
public class RecentsAtomicAnimationFactory<ACTIVITY_TYPE extends StatefulActivity, STATE_TYPE>
extends AtomicAnimationFactory<STATE_TYPE> {
@@ -46,8 +51,30 @@
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_RECENTS_FADE_ANIM:
- return ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
+ Log.d(BAD_STATE, "RAAF createStateElementAnimation alpha="
+ + Arrays.toString(values));
+ alpha.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.d(BAD_STATE, "RAAF createStateElementAnimation onStart");
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ RecentsView recent = mActivity.getOverviewPanel();
+ float alpha = recent == null ? -1 : RecentsView.CONTENT_ALPHA.get(recent);
+ Log.d(BAD_STATE, "RAAF createStateElementAnimation onCancel, alpha="
+ + alpha);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.d(BAD_STATE, "RAAF createStateElementAnimation onEnd");
+ }
+ });
+ return alpha;
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mActivity.getOverviewPanel();
return new SpringAnimationBuilder(mActivity)
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 4f5c368..1631be0 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -102,6 +102,8 @@
// Whether the swipe gesture is running, so the recents would stay locked in the
// current orientation
private static final int FLAG_SWIPE_UP_NOT_RUNNING = 1 << 8;
+ // Ignore shared prefs for home rotation rotation, allowing it in if the activity supports it
+ private static final int FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF = 1 << 9;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@@ -371,12 +373,17 @@
== MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE;
}
+ public void ignoreAllowHomeRotationPreference() {
+ setFlag(FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF, true);
+ }
+
public boolean isRecentsActivityRotationAllowed() {
// Activity rotation is allowed if the multi-simulated-rotation is not supported
// (fallback recents or tablets) or activity rotation is enabled by various settings.
return ((mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
!= MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
- || (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS
+ || (mFlags & (FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF
+ | FLAG_HOME_ROTATION_ALLOWED_IN_PREFS
| FLAG_MULTIWINDOW_ROTATION_ALLOWED
| FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING)) != 0;
}
@@ -599,7 +606,7 @@
width = Math.min(currentSize.x, currentSize.y);
height = Math.max(currentSize.x, currentSize.y);
}
- return idp.getBestMatch(width, height);
+ return idp.getBestMatch(width, height, mRecentsActivityRotation);
}
private static String nameAndAddress(Object obj) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index fff55a1..21e3ea0 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -17,6 +17,7 @@
package com.android.quickstep.util;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.PendingIntent.FLAG_MUTABLE;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -27,9 +28,11 @@
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
+import android.text.TextUtils;
import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -45,6 +48,7 @@
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -59,12 +63,13 @@
*/
public class SplitSelectStateController {
+ private final Context mContext;
private final Handler mHandler;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
private final DepthController mDepthController;
private @StagePosition int mStagePosition;
- private PendingIntent mInitialTaskPendingIntent;
+ private Intent mInitialTaskIntent;
private int mInitialTaskId = INVALID_TASK_ID;
private int mSecondTaskId = INVALID_TASK_ID;
private boolean mRecentsAnimationRunning;
@@ -72,10 +77,11 @@
@Nullable
private GroupedTaskView mLaunchingTaskView;
- public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy,
- StateManager stateManager, DepthController depthController) {
+ public SplitSelectStateController(Context context, Handler handler, StateManager stateManager,
+ DepthController depthController) {
+ mContext = context;
mHandler = handler;
- mSystemUiProxy = systemUiProxy;
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(mContext);
mStateManager = stateManager;
mDepthController = depthController;
}
@@ -86,12 +92,11 @@
public void setInitialTaskSelect(int taskId, @StagePosition int stagePosition) {
mInitialTaskId = taskId;
mStagePosition = stagePosition;
- mInitialTaskPendingIntent = null;
+ mInitialTaskIntent = null;
}
- public void setInitialTaskSelect(PendingIntent pendingIntent,
- @StagePosition int stagePosition) {
- mInitialTaskPendingIntent = pendingIntent;
+ public void setInitialTaskSelect(Intent intent, @StagePosition int stagePosition) {
+ mInitialTaskIntent = intent;
mStagePosition = stagePosition;
mInitialTaskId = INVALID_TASK_ID;
}
@@ -99,9 +104,22 @@
/**
* To be called after second task selected
*/
- public void setSecondTaskId(int taskId, Consumer<Boolean> callback) {
- mSecondTaskId = taskId;
- launchTasks(mInitialTaskId, mInitialTaskPendingIntent, mSecondTaskId, mStagePosition,
+ public void setSecondTask(Task task, Consumer<Boolean> callback) {
+ mSecondTaskId = task.key.id;
+ final Intent fillInIntent;
+ if (mInitialTaskIntent != null) {
+ fillInIntent = new Intent();
+ if (TextUtils.equals(mInitialTaskIntent.getComponent().getPackageName(),
+ task.topActivity.getPackageName())) {
+ fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ } else {
+ fillInIntent = null;
+ }
+ final PendingIntent pendingIntent =
+ mInitialTaskIntent == null ? null : PendingIntent.getActivity(mContext, 0,
+ mInitialTaskIntent, FLAG_MUTABLE);
+ launchTasks(mInitialTaskId, pendingIntent, fillInIntent, mSecondTaskId, mStagePosition,
callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
}
@@ -113,18 +131,32 @@
mLaunchingTaskView = groupedTaskView;
TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
groupedTaskView.getTaskIdAttributeContainers();
- launchTasks(taskIdAttributeContainers[0].getTask().key.id, null,
+ launchTasks(taskIdAttributeContainers[0].getTask().key.id,
taskIdAttributeContainers[1].getTask().key.id,
taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList,
groupedTaskView.getSplitRatio());
}
/**
+ * To be called when we want to launch split pairs from Overview when split is initiated from
+ * Overview.
+ */
+ public void launchTasks(int taskId1, int taskId2, @StagePosition int stagePosition,
+ Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+ launchTasks(taskId1, null /* taskPendingIntent */, null /* fillInIntent */, taskId2,
+ stagePosition, callback, freezeTaskList, splitRatio);
+ }
+
+ /**
+ * To be called when we want to launch split pairs from Overview. Split can be initiated from
+ * either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
+ * fill in intent with a taskId2 are set.
+ * @param taskPendingIntent is null when split is initiated from Overview
* @param stagePosition representing location of task1
*/
public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent,
- int taskId2, @StagePosition int stagePosition, Consumer<Boolean> callback,
- boolean freezeTaskList, float splitRatio) {
+ @Nullable Intent fillInIntent, int taskId2, @StagePosition int stagePosition,
+ Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
// Assume initial task is for top/left part of screen
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
? new int[]{taskId1, taskId2}
@@ -156,7 +188,7 @@
splitRatio, adapter);
} else {
mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent,
- new Intent(), taskId2, mainOpts.toBundle(), null /* sideOptions */,
+ fillInIntent, taskId2, mainOpts.toBundle(), null /* sideOptions */,
stagePosition, splitRatio, adapter);
}
}
@@ -250,7 +282,7 @@
*/
public void resetState() {
mInitialTaskId = INVALID_TASK_ID;
- mInitialTaskPendingIntent = null;
+ mInitialTaskIntent = null;
mSecondTaskId = INVALID_TASK_ID;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mRecentsAnimationRunning = false;
@@ -262,7 +294,7 @@
* chosen
*/
public boolean isSplitSelectActive() {
- return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskPendingIntent != null)
+ return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskIntent != null)
&& mSecondTaskId == INVALID_TASK_ID;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
new file mode 100644
index 0000000..19a48db
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.content.Context;
+import android.view.Display;
+
+import com.android.launcher3.util.window.WindowManagerProxy;
+
+/**
+ * Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher
+ */
+public class SystemWindowManagerProxy extends WindowManagerProxy {
+
+ public SystemWindowManagerProxy(Context context) {
+ super(true);
+ }
+
+ @Override
+ protected String getDisplayId(Display display) {
+ return display.getUniqueId();
+ }
+
+ @Override
+ public boolean isInternalDisplay(Display display) {
+ return display.getType() == Display.TYPE_INTERNAL;
+ }
+
+ @Override
+ public int getRotation(Context context) {
+ return context.getResources().getConfiguration().windowConfiguration.getRotation();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 04af3c1..d9f668d 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -182,9 +182,8 @@
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
- getRecentsView().getSplitPlaceholder().launchTasks(mTask.key.id, null,
- mSecondaryTask.key.id, STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
- getSplitRatio());
+ getRecentsView().getSplitPlaceholder().launchTasks(mTask.key.id, mSecondaryTask.key.id,
+ STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList, getSplitRatio());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index e8f3324..8d717d2 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -21,11 +21,13 @@
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface;
@@ -65,6 +67,7 @@
public void init(OverviewActionsView actionsView,
SplitSelectStateController splitPlaceholderView) {
super.init(actionsView, splitPlaceholderView);
+ Log.d(BAD_STATE, "LauncherRecentsView init setContentAlpha=0");
setContentAlpha(0);
}
@@ -97,6 +100,7 @@
setOverviewStateEnabled(toState.overviewUi);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
+ Log.d(BAD_STATE, "LRV onStateTransitionStart setFreezeVisibility=true, toState=" + toState);
setFreezeViewVisibility(true);
}
@@ -108,6 +112,8 @@
}
boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
+ Log.d(BAD_STATE, "LRV onStateTransitionComplete setFreezeVisibility=false, finalState="
+ + finalState);
setFreezeViewVisibility(false);
if (isOverlayEnabled) {
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 0fa2b24..6b15807 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -216,14 +216,12 @@
// Align vertically, using taskbar height + mDp.taskbarOffsetY() to estimate where
// the button nav top is.
- View startActionView = findViewById(R.id.action_screenshot);
int marginBottom = getOverviewActionsBottomMarginPx(
DisplayController.getNavigationMode(getContext()), mDp);
int actionsTop =
- (mDp.heightPx - marginBottom - mInsets.bottom) - startActionView.getHeight();
+ (mDp.heightPx - marginBottom - mInsets.bottom) - mDp.overviewActionsHeight;
int navTop = mDp.heightPx - (mDp.taskbarSize + mDp.getTaskbarOffsetY());
- int transY = navTop - actionsTop
- + ((mDp.taskbarSize - startActionView.getHeight()) / 2);
+ int transY = navTop - actionsTop + ((mDp.taskbarSize - mDp.overviewActionsHeight) / 2);
setTranslationY(transY);
} else {
setPadding(mInsets.left, 0, mInsets.right, 0);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5e331e2..6bb20fc 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -16,7 +16,6 @@
package com.android.quickstep.views;
-import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
@@ -28,7 +27,6 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
-import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
@@ -45,7 +43,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
-import static com.android.launcher3.testing.TestProtocol.TASK_VIEW_ID_CRASH;
import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -69,8 +66,6 @@
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
import android.content.res.Configuration;
@@ -2013,22 +2008,6 @@
return null;
}
- @Nullable
- private TaskView getTaskViewByComponentName(ComponentName componentName) {
- if (componentName == null) {
- return null;
- }
-
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
- if (taskView.getItemInfo().getIntent().getComponent().getPackageName().equals(
- componentName.getPackageName())) {
- return taskView;
- }
- }
- return null;
- }
-
public int getRunningTaskIndex() {
TaskView taskView = getRunningTaskView();
return taskView == null ? -1 : indexOfChild(taskView);
@@ -2282,8 +2261,6 @@
* Sets the running task id, cleaning up the old running task if necessary.
*/
public void setCurrentTask(int runningTaskViewId) {
- Log.d(TASK_VIEW_ID_CRASH, "currentRunningTaskViewId: " + mRunningTaskViewId
- + " requestedTaskViewId: " + runningTaskViewId);
if (mRunningTaskViewId == runningTaskViewId) {
return;
}
@@ -3973,28 +3950,17 @@
}
public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
- // Remove the task if it exists in Overview
- TaskView matchingTaskView = getTaskViewByComponentName(
- splitSelectSource.intent.getComponent());
- if (matchingTaskView != null) {
- removeTaskInternal(matchingTaskView.getTaskViewId());
- }
-
mSplitSelectSource = splitSelectSource;
- mSplitSelectStateController.setInitialTaskSelect(
- PendingIntent.getActivity(
- mContext, 0, splitSelectSource.intent, FLAG_MUTABLE),
+ mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
splitSelectSource.position.stagePosition);
}
- public PendingAnimation createSplitSelectInitAnimation() {
+ public PendingAnimation createSplitSelectInitAnimation(int duration) {
if (mSplitHiddenTaskView != null) {
- int duration = mActivity.getStateManager().getState().getTransitionDuration(
- getContext());
return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
true /* dismissingForSplitSelection*/);
} else {
- PendingAnimation anim = new PendingAnimation(SPLIT_LAUNCH_DURATION);
+ PendingAnimation anim = new PendingAnimation(duration);
createInitialSplitSelectAnimation(anim);
return anim;
}
@@ -4039,8 +4005,8 @@
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isInitialSplit */);
pendingAnimation.addEndListener(aBoolean ->
- mSplitSelectStateController.setSecondTaskId(task.key.id,
- aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
+ mSplitSelectStateController.setSecondTask(
+ task, aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
if (containerTaskView.containsMultipleTasks()) {
// If we are launching from a child task, then only hide the thumbnail itself
mSecondSplitHiddenView = thumbnailView;
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 3e84a76..3bd3722 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -48,7 +48,7 @@
Duration.ofSeconds(600), Duration.ofSeconds(300),
PendingIntent.getActivity(mTargetContext, -1, new Intent(), 0)));
- mLauncher.pressHome();
+ mLauncher.goHome();
final DigitalWellBeingToast toast = getToast();
waitForLauncherCondition("Toast is not visible", launcher -> toast.hasLimit());
@@ -58,7 +58,7 @@
runWithShellPermission(
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
- mLauncher.pressHome();
+ mLauncher.goHome();
assertFalse("Toast is visible", getToast().hasLimit());
} finally {
runWithShellPermission(
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 5351963..6ec6269 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -41,7 +41,7 @@
super.setUp();
TaplTestsLauncher3.initialize(this);
// b/143488140
- mLauncher.pressHome();
+ mLauncher.goHome();
// Start an activity where the gestures start.
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
}
@@ -54,7 +54,7 @@
// The test action.
eventProcessor.startIteration();
- mLauncher.pressHome();
+ mLauncher.goHome();
eventProcessor.finishIteration();
}
@@ -66,7 +66,7 @@
closeLauncherActivity();
// The test action.
- mLauncher.pressHome();
+ mLauncher.goHome();
}
}
@@ -81,6 +81,6 @@
mLauncher.getLaunchedAppState().switchToOverview();
}
closeLauncherActivity();
- mLauncher.pressHome();
+ mLauncher.goHome();
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 396cb1b..399cd10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -102,7 +102,7 @@
public void testOverview() throws Exception {
startTestAppsWithCheck();
// mLauncher.pressHome() also tests an important case of pressing home while in background.
- Overview overview = mLauncher.pressHome().switchToOverview();
+ Overview overview = mLauncher.goHome().switchToOverview();
assertTrue("Launcher internal state didn't switch to Overview",
isInState(() -> LauncherState.OVERVIEW));
executeOnLauncher(
@@ -127,7 +127,7 @@
getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
// Test opening a task.
- OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
+ OverviewTask task = mLauncher.goHome().switchToOverview().getCurrentTask();
assertNotNull("overview.getCurrentTask() returned null (1)", task);
assertNotNull("OverviewTask.open returned null", task.open());
assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject(
@@ -139,7 +139,7 @@
isInLaunchedApp(launcher)));
// Test dismissing a task.
- overview = mLauncher.pressHome().switchToOverview();
+ overview = mLauncher.goHome().switchToOverview();
assertTrue("Launcher internal state didn't switch to Overview",
isInState(() -> LauncherState.OVERVIEW));
final Integer numTasks = getFromLauncher(launcher -> getTaskCount(launcher));
@@ -151,7 +151,7 @@
numTasks - 1, getTaskCount(launcher)));
// Test dismissing all tasks.
- mLauncher.pressHome().switchToOverview().dismissAllTasks();
+ mLauncher.goHome().switchToOverview().dismissAllTasks();
assertTrue("Launcher internal state is not Home",
isInState(() -> LauncherState.NORMAL));
executeOnLauncher(
@@ -168,14 +168,14 @@
@ScreenRecord // b/195673272
public void testOverviewActions() throws Exception {
// Experimenting for b/165029151:
- final Overview overview = mLauncher.pressHome().switchToOverview();
+ final Overview overview = mLauncher.goHome().switchToOverview();
if (overview.hasTasks()) overview.dismissAllTasks();
- mLauncher.pressHome();
+ mLauncher.goHome();
//
startTestAppsWithCheck();
OverviewActions actionsView =
- mLauncher.pressHome().switchToOverview().getOverviewActions();
+ mLauncher.goHome().switchToOverview().getOverviewActions();
actionsView.clickAndDismissScreenshot();
}
@@ -200,7 +200,7 @@
@PortraitLandscape
public void testSwitchToOverview() throws Exception {
assertNotNull("Workspace.switchToOverview() returned null",
- mLauncher.pressHome().switchToOverview());
+ mLauncher.goHome().switchToOverview());
assertTrue("Launcher internal state didn't switch to Overview",
isInState(() -> LauncherState.OVERVIEW));
}
@@ -240,7 +240,7 @@
// Testing pressHome.
assertTrue("Launcher internal state is not All Apps",
isInState(() -> LauncherState.ALL_APPS));
- assertNotNull("pressHome returned null", mLauncher.pressHome());
+ assertNotNull("pressHome returned null", mLauncher.goHome());
assertTrue("Launcher internal state is not Home",
isInState(() -> LauncherState.NORMAL));
assertNotNull("getHome returned null", mLauncher.getWorkspace());
@@ -289,7 +289,7 @@
@PortraitLandscape
public void testQuickSwitchFromHome() throws Exception {
startTestActivity(2);
- mLauncher.pressHome().quickSwitchToPreviousApp();
+ mLauncher.goHome().quickSwitchToPreviousApp();
assertTrue("The most recent task is not running after quick switching from home",
isTestActivityRunning(2));
getAndAssertLaunchedApp();
@@ -329,7 +329,7 @@
startTestActivity(i);
}
- Overview overview = mLauncher.pressHome().switchToOverview();
+ Overview overview = mLauncher.goHome().switchToOverview();
executeOnLauncher(
launcher -> assertTrue("Don't have at least 13 tasks",
getTaskCount(launcher) >= 13));
@@ -348,7 +348,7 @@
DEFAULT_UI_TIMEOUT));
// Scroll the task offscreen as it is now first
- overview = mLauncher.pressHome().switchToOverview();
+ overview = mLauncher.goHome().switchToOverview();
overview.scrollCurrentTaskOffScreen();
assertTrue("Launcher internal state is not Overview",
isInState(() -> LauncherState.OVERVIEW));
@@ -377,7 +377,7 @@
launcher)) <= 1)));
// Test dismissing all tasks.
- mLauncher.pressHome().switchToOverview().dismissAllTasks();
+ mLauncher.goHome().switchToOverview().dismissAllTasks();
assertTrue("Launcher internal state is not Home",
isInState(() -> LauncherState.NORMAL));
executeOnLauncher(
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
new file mode 100644
index 0000000..ba93975
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.content.Intent;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.tapl.Taskbar;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplTestsTaskbar extends AbstractQuickStepTest {
+
+ private static final String TEST_APP_NAME = "LauncherTestApp";
+ private static final String TEST_APP_PACKAGE =
+ getInstrumentation().getContext().getPackageName();
+ private static final String CALCULATOR_APP_PACKAGE =
+ resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
+
+ @Override
+ public void setUp() throws Exception {
+ Assume.assumeTrue(mLauncher.isTablet());
+ super.setUp();
+ mLauncher.useTestWorkspaceLayoutOnReload();
+ TaplTestsLauncher3.initialize(this);
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
+ mLauncher.showTaskbarIfHidden();
+ }
+
+ @After
+ public void tearDown() {
+ mLauncher.useDefaultWorkspaceLayoutOnReload();
+ }
+
+ @Test
+ public void testHideShowTaskbar() {
+ getTaskbar().hide();
+ mLauncher.getLaunchedAppState().showTaskbar();
+ }
+
+ @Test
+ public void testLaunchApp() throws Exception {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ }
+
+ @Test
+ public void testOpenMenu() throws Exception {
+ getTaskbar().getAppIcon(TEST_APP_NAME).openMenu();
+ }
+
+ @Test
+ public void testLaunchShortcut() throws Exception {
+ getTaskbar().getAppIcon(TEST_APP_NAME)
+ .openDeepShortcutMenu()
+ .getMenuItem("Shortcut 1")
+ .launch(TEST_APP_PACKAGE);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testLaunchAppInSplitscreen() throws Exception {
+ getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
+ TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testLaunchShortcutInSplitscreen() throws Exception {
+ getTaskbar().getAppIcon(TEST_APP_NAME)
+ .openDeepShortcutMenu()
+ .getMenuItem("Shortcut 1")
+ .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ }
+
+ @Test
+ public void testLaunchApp_FromTaskbarAllApps() throws Exception {
+ getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ }
+
+ @Test
+ public void testOpenMenu_FromTaskbarAllApps() throws Exception {
+ getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu();
+ }
+
+ @Test
+ public void testLaunchShortcut_FromTaskbarAllApps() throws Exception {
+ getTaskbar().openAllApps()
+ .getAppIcon(TEST_APP_NAME)
+ .openDeepShortcutMenu()
+ .getMenuItem("Shortcut 1")
+ .launch(TEST_APP_PACKAGE);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception {
+ getTaskbar().openAllApps()
+ .getAppIcon(TEST_APP_NAME)
+ .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception {
+ getTaskbar().openAllApps()
+ .getAppIcon(TEST_APP_NAME)
+ .openDeepShortcutMenu()
+ .getMenuItem("Shortcut 1")
+ .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ }
+
+ private Taskbar getTaskbar() {
+ Taskbar taskbar = mLauncher.getLaunchedAppState().getTaskbar();
+ List<String> taskbarIconNames = taskbar.getIconNames();
+ List<String> hotseatIconNames = mLauncher.getHotseatIconNames();
+
+ assertEquals("Taskbar and hotseat icon counts do not match",
+ taskbarIconNames.size(), hotseatIconNames.size());
+
+ for (int i = 0; i < taskbarIconNames.size(); i++) {
+ assertEquals("Taskbar and Hotseat icons do not match",
+ taskbarIconNames, hotseatIconNames);
+ }
+
+ return taskbar;
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
index 661beda..7e408a8 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
@@ -197,7 +197,7 @@
addItemToScreen(item);
assertTrue("Widget is not present",
- mLauncher.pressHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
+ mLauncher.goHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
int widgetId = item.appWidgetId;
// Verify widget id
@@ -221,7 +221,7 @@
// Widget is updated when going home
mInitTracker.disableLog();
- mLauncher.pressHome();
+ mLauncher.goHome();
verifyWidget(finalWidgetText);
assertNotEquals(1, mInitTracker.viewInitCount);
} finally {
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 6dc9f8d..c6cdafc 100644
--- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -15,16 +15,15 @@
*/
package com.android.quickstep.util;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.util.ArrayMap;
+import android.util.Pair;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -38,6 +37,10 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.ReflectionHelpers;
+import com.android.launcher3.util.RotationUtils;
+import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -142,29 +145,34 @@
LauncherModelHelper helper = new LauncherModelHelper();
try {
helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
+ int rotation = mDisplaySize.x > mDisplaySize.y
+ ? Surface.ROTATION_90 : Surface.ROTATION_0;
+ CachedDisplayInfo cdi =
+ new CachedDisplayInfo("test-display", mDisplaySize, rotation , new Rect());
+ WindowBounds wm = new WindowBounds(
+ new Rect(0, 0, mDisplaySize.x, mDisplaySize.y),
+ mDisplayInsets);
+ WindowBounds[] allBounds = new WindowBounds[4];
+ for (int i = 0; i < 4; i++) {
+ Rect boundsR = new Rect(wm.bounds);
+ Rect insetsR = new Rect(wm.insets);
- Display display = mock(Display.class);
- doReturn(DEFAULT_DISPLAY).when(display).getDisplayId();
- doReturn(mDisplaySize.x > mDisplaySize.y ? Surface.ROTATION_90 : Surface.ROTATION_0)
- .when(display).getRotation();
- doAnswer(i -> {
- ((Point) i.getArgument(0)).set(mDisplaySize.x, mDisplaySize.y);
- return null;
- }).when(display).getRealSize(any());
- doAnswer(i -> {
- Point smallestSize = i.getArgument(0);
- Point largestSize = i.getArgument(1);
- smallestSize.x = smallestSize.y = Math.min(mDisplaySize.x, mDisplaySize.y);
- largestSize.x = largestSize.y = Math.max(mDisplaySize.x, mDisplaySize.y);
+ RotationUtils.rotateRect(insetsR, RotationUtils.deltaRotation(rotation, i));
+ RotationUtils.rotateRect(boundsR, RotationUtils.deltaRotation(rotation, i));
+ boundsR.set(0, 0, Math.abs(boundsR.width()), Math.abs(boundsR.height()));
+ allBounds[i] = new WindowBounds(boundsR, insetsR);
+ }
- smallestSize.x -= mDisplayInsets.left + mDisplayInsets.right;
- largestSize.x -= mDisplayInsets.left + mDisplayInsets.right;
+ WindowManagerProxy wmProxy = mock(WindowManagerProxy.class);
+ doReturn(cdi).when(wmProxy).getDisplayInfo(any());
+ doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any());
- smallestSize.y -= mDisplayInsets.top + mDisplayInsets.bottom;
- largestSize.y -= mDisplayInsets.top + mDisplayInsets.bottom;
- return null;
- }).when(display).getCurrentSizeRange(any(), any());
- DisplayController.Info mockInfo = new Info(helper.sandboxContext, display);
+ ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache =
+ new ArrayMap<>();
+ perDisplayBoundsCache.put(cdi.id, Pair.create(cdi.normalize(), allBounds));
+
+ DisplayController.Info mockInfo = new Info(
+ helper.sandboxContext, mock(Display.class), wmProxy, perDisplayBoundsCache);
DisplayController controller =
DisplayController.INSTANCE.get(helper.sandboxContext);
@@ -172,7 +180,7 @@
ReflectionHelpers.setField(controller, "mInfo", mockInfo);
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(helper.sandboxContext)
- .getBestMatch(mAppBounds.width(), mAppBounds.height());
+ .getBestMatch(mAppBounds.width(), mAppBounds.height(), rotation);
mDeviceProfile.updateInsets(mLauncherInsets);
TaskViewSimulator tvs = new TaskViewSimulator(helper.sandboxContext,
diff --git a/res/values-v31/styles.xml b/res/values-v31/styles.xml
index e42d0a3..008a77c 100644
--- a/res/values-v31/styles.xml
+++ b/res/values-v31/styles.xml
@@ -38,6 +38,7 @@
<item name="preferenceScreenStyle">@style/HomeSettings.PreferenceScreenStyle</item>
<item name="preferenceStyle">@style/HomeSettings.PreferenceStyle</item>
<item name="switchPreferenceStyle">@style/HomeSettings.SwitchPreferenceStyle</item>
+ <item name="android:fontFamily">google-sans-text</item>
</style>
<style name="HomeSettings.CategoryStyle" parent="@style/Preference.Category.Material">
diff --git a/res/values/config.xml b/res/values/config.xml
index 1c996eb..e2fd0e3 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -69,6 +69,7 @@
<string name="test_information_handler_class" translatable="false"></string>
<string name="launcher_activity_logic_class" translatable="false"></string>
<string name="model_delegate_class" translatable="false"></string>
+ <string name="window_manager_proxy_class" translatable="false"></string>
<!-- View ID to use for QSB widget -->
<item type="id" name="qsb_widget" />
@@ -165,4 +166,8 @@
<!-- Name of the class used to generate colors from the wallpaper colors. Must be implementing the LauncherAppWidgetHostView.ColorGenerator interface. -->
<string name="color_generator_class" translatable="false"/>
+ <!-- Swipe back to home related -->
+ <dimen name="swipe_back_window_scale_x_margin">10dp</dimen>
+ <dimen name="swipe_back_window_scale_y_margin">80dp</dimen>
+ <dimen name="swipe_back_window_corner_radius">40dp</dimen>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3e666fc..2b599bc 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -345,6 +345,7 @@
<dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
<dimen name="overview_task_margin">0dp</dimen>
<dimen name="overview_task_margin_grid">0dp</dimen>
+ <dimen name="overview_actions_height">0dp</dimen>
<dimen name="overview_actions_button_spacing">0dp</dimen>
<dimen name="overview_actions_margin_gesture">0dp</dimen>
<dimen name="overview_actions_top_margin_gesture">0dp</dimen>
diff --git a/res/xml/default_test_workspace.xml b/res/xml/default_test_workspace.xml
new file mode 100644
index 0000000..bd718b3
--- /dev/null
+++ b/res/xml/default_test_workspace.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Split display specific version of Launcher3/res/xml/default_workspace_4x4.xml -->
+<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <!-- Launcher Test Activity -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="0"
+ launcher:x="0"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.CATEGORY_TEST;component=com.google.android.apps.nexuslauncher.tests/com.android.launcher3.testcomponent.BaseTestingActivity;end" />
+ </resolve>
+
+</favorites>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index b47554f..f53d01e 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -29,7 +29,6 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
-import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -41,8 +40,6 @@
import android.view.ActionMode;
import android.view.Display;
import android.view.View;
-import android.view.WindowInsets.Type;
-import android.view.WindowMetrics;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -322,11 +319,7 @@
protected WindowBounds getMultiWindowDisplaySize() {
if (Utilities.ATLEAST_R) {
- WindowMetrics wm = getWindowManager().getCurrentWindowMetrics();
-
- Insets insets = wm.getWindowInsets().getInsets(Type.systemBars());
- return new WindowBounds(wm.getBounds(),
- new Rect(insets.left, insets.top, insets.right, insets.bottom));
+ return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
}
// Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
// the app window size
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index cd9bbf7..39020bd 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -75,6 +75,7 @@
public final int heightPx;
public final int availableWidthPx;
public final int availableHeightPx;
+ public final int rotationHint;
public final float aspectRatio;
@@ -190,6 +191,7 @@
public int overviewTaskIconDrawableSizePx;
public int overviewTaskIconDrawableSizeGridPx;
public int overviewTaskThumbnailTopMarginPx;
+ public final int overviewActionsHeight;
public final int overviewActionsMarginThreeButtonPx;
public final int overviewActionsTopMarginGesturePx;
public final int overviewActionsBottomMarginGesturePx;
@@ -239,6 +241,7 @@
this.isGestureMode = isGestureMode;
windowX = windowBounds.bounds.left;
windowY = windowBounds.bounds.top;
+ this.rotationHint = windowBounds.rotationHint;
isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
@@ -346,9 +349,14 @@
workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
- isQsbInline = isLargeTablet && isLandscape && hotseatQsbHeight > 0;
+ // Whether QSB might be inline in appropriate orientation (landscape).
+ boolean canQsbInline = isLargeTablet && hotseatQsbHeight > 0;
+ isQsbInline = canQsbInline && isLandscape;
- if (isTaskbarPresent && !isGestureMode && isQsbInline) {
+ // We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB
+ // might be inline in either orientations, to keep hotseat size consistent across rotation.
+ boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode;
+ if (areNavButtonsInline && canQsbInline) {
numShownHotseatIcons = inv.numShrunkenHotseatIcons;
} else {
numShownHotseatIcons =
@@ -400,6 +408,7 @@
overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
overviewActionsButtonSpacing = res.getDimensionPixelSize(
R.dimen.overview_actions_button_spacing);
+ overviewActionsHeight = res.getDimensionPixelSize(R.dimen.overview_actions_height);
overviewActionsMarginThreeButtonPx = res.getDimensionPixelSize(
R.dimen.overview_actions_margin_three_button);
// Grid task's top margin is only overviewTaskIconSizePx + overviewTaskMarginGridPx, but
@@ -543,8 +552,8 @@
}
public Builder toBuilder(Context context) {
- WindowBounds bounds =
- new WindowBounds(widthPx, heightPx, availableWidthPx, availableHeightPx);
+ WindowBounds bounds = new WindowBounds(
+ widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
bounds.bounds.offsetTo(windowX, windowY);
return new Builder(context, inv, mInfo)
.setWindowBounds(bounds)
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 886c657..25fd643 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -55,6 +55,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.WindowManagerProxy;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -180,8 +181,7 @@
private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
@VisibleForTesting
- public InvariantDeviceProfile() {
- }
+ public InvariantDeviceProfile() { }
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
@@ -278,11 +278,16 @@
}
private static @DeviceType int getDeviceType(Info displayInfo) {
- // Each screen has two profiles (portrait/landscape), so devices with four or more
- // supported profiles implies two or more internal displays.
- if (displayInfo.supportedBounds.size() >= 4 && ENABLE_TWO_PANEL_HOME.get()) {
+ int flagPhone = 1 << 0;
+ int flagTablet = 1 << 1;
+
+ int type = displayInfo.supportedBounds.stream()
+ .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
+ .reduce(0, (a, b) -> a | b);
+ if ((type == (flagPhone | flagTablet)) && ENABLE_TWO_PANEL_HOME.get()) {
+ // device has profiles supporting both phone and table modes
return TYPE_MULTI_DISPLAY;
- } else if (displayInfo.supportedBounds.stream().allMatch(displayInfo::isTablet)) {
+ } else if (type == flagTablet) {
return TYPE_TABLET;
} else {
return TYPE_PHONE;
@@ -613,10 +618,14 @@
float screenWidth = config.screenWidthDp * res.getDisplayMetrics().density;
float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
- return getBestMatch(screenWidth, screenHeight);
+ return getBestMatch(screenWidth, screenHeight,
+ WindowManagerProxy.INSTANCE.get(context).getRotation(context));
}
- public DeviceProfile getBestMatch(float screenWidth, float screenHeight) {
+ /**
+ * Returns the device profile matching the provided screen configuration
+ */
+ public DeviceProfile getBestMatch(float screenWidth, float screenHeight, int rotation) {
DeviceProfile bestMatch = supportedProfiles.get(0);
float minDiff = Float.MAX_VALUE;
@@ -626,6 +635,8 @@
if (diff < minDiff) {
minDiff = diff;
bestMatch = profile;
+ } else if (diff == minDiff && profile.rotationHint == rotation) {
+ bestMatch = profile;
}
}
return bestMatch;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5c5aee5..5c406bd 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -57,6 +57,7 @@
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
import android.animation.Animator;
@@ -228,6 +229,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -500,6 +502,8 @@
if (!mModel.addCallbacksAndLoad(this)) {
if (!internalStateHandled) {
+ Log.d(BAD_STATE, "Launcher onCreate not binding sync, setting DragLayer alpha "
+ + "ALPHA_INDEX_LAUNCHER_LOAD to 0");
// If we are not binding synchronously, show a fade in animation when
// the first page bind completes.
mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
@@ -518,6 +522,8 @@
final AlphaProperty property =
mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
if (property.getValue() == 0) {
+ Log.d(BAD_STATE, "Launcher onPreDraw ALPHA_INDEX_LAUNCHER_LOAD not"
+ + " started yet, cancelling draw.");
// Animation haven't started yet; suspend.
return false;
} else {
@@ -1108,21 +1114,23 @@
&& mAllAppsSessionLogId == null) {
// creates new instance ID since new all apps session is started.
mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
- getStatsLogManager().logger().withContainerInfo(
- ContainerInfo.newBuilder().setWorkspace(
- WorkspaceContainer.newBuilder().setPageIndex(
- getWorkspace().getCurrentPage())).build())
- .log(getAllAppsEntryEvent());
+ if (getAllAppsEntryEvent().isPresent()) {
+ getStatsLogManager().logger()
+ .withContainerInfo(ContainerInfo.newBuilder()
+ .setWorkspace(WorkspaceContainer.newBuilder()
+ .setPageIndex(getWorkspace().getCurrentPage())).build())
+ .log(getAllAppsEntryEvent().get());
+ }
}
}
/**
* Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
*/
- protected EventEnum getAllAppsEntryEvent() {
- return FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+ protected Optional<EventEnum> getAllAppsEntryEvent() {
+ return Optional.of(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
- : LAUNCHER_ALLAPPS_ENTRY;
+ : LAUNCHER_ALLAPPS_ENTRY);
}
@Override
@@ -1151,17 +1159,18 @@
// Making sure mAllAppsSessionLogId is not null to avoid double logging.
&& mAllAppsSessionLogId != null) {
getAppsView().reset(false);
- getStatsLogManager().logger()
- .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
- .setWorkspace(
- LauncherAtom.WorkspaceContainer.newBuilder()
- .setPageIndex(getWorkspace().getCurrentPage()))
- .build())
- .log(LAUNCHER_ALLAPPS_EXIT);
+ getAllAppsExitEvent().ifPresent(getStatsLogManager().logger()::log);
mAllAppsSessionLogId = null;
}
}
+ /**
+ * Returns {@link EventEnum} that should be logged when Launcher exists from AllApps state.
+ */
+ protected Optional<EventEnum> getAllAppsExitEvent() {
+ return Optional.of(LAUNCHER_ALLAPPS_EXIT);
+ }
+
@Override
protected void onResume() {
Object traceToken = TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT,
@@ -2681,6 +2690,28 @@
AlphaProperty property = mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
if (property.getValue() < 1) {
ObjectAnimator anim = ObjectAnimator.ofFloat(property, MultiValueAlpha.VALUE, 1);
+
+ Log.d(BAD_STATE, "Launcher onInitialBindComplete toAlpha=" + 1);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.d(BAD_STATE, "Launcher onInitialBindComplete onStart");
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ float alpha = mDragLayer == null
+ ? -1
+ : mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).getValue();
+ Log.d(BAD_STATE, "Launcher onInitialBindComplete onCancel, alpha=" + alpha);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.d(BAD_STATE, "Launcher onInitialBindComplete onEnd");
+ }
+ });
+
anim.addListener(AnimatorListeners.forEndCallback(executor::onLoadAnimationCompleted));
anim.start();
} else {
@@ -2743,8 +2774,11 @@
* @param preferredItemId The id of the preferred item to match to if it exists.
* @param packageName The package name of the app to match.
* @param user The user of the app to match.
+ * @param supportsAllAppsState If true and we are in All Apps state, looks for view in All Apps.
+ * Else we only looks on the workspace.
*/
- public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
+ public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user,
+ boolean supportsAllAppsState) {
final ItemInfoMatcher preferredItem = (info, cn) ->
info != null && info.id == preferredItemId;
final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
@@ -2755,7 +2789,7 @@
&& TextUtils.equals(info.getTargetComponent().getPackageName(),
packageName);
- if (isInState(LauncherState.ALL_APPS)) {
+ if (supportsAllAppsState && isInState(LauncherState.ALL_APPS)) {
return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
preferredItem, packageAndUserAndApp);
} else {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 9891a60..5aa8a46 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -102,6 +102,8 @@
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".settings";
public static final String KEY_LAYOUT_PROVIDER_AUTHORITY = "KEY_LAYOUT_PROVIDER_AUTHORITY";
+ private static final int TEST_WORKSPACE_LAYOUT_RES_XML = R.xml.default_test_workspace;
+
static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
protected DatabaseHelper mOpenHelper;
@@ -109,6 +111,8 @@
private long mLastRestoreTimestamp = 0L;
+ private boolean mUseTestWorkspaceLayout;
+
/**
* $ adb shell dumpsys activity provider com.android.launcher3
*/
@@ -391,6 +395,14 @@
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
return null;
}
+ case LauncherSettings.Settings.METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG: {
+ mUseTestWorkspaceLayout = true;
+ return null;
+ }
+ case LauncherSettings.Settings.METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG: {
+ mUseTestWorkspaceLayout = false;
+ return null;
+ }
case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: {
loadDefaultFavoritesIfNecessary();
return null;
@@ -610,7 +622,8 @@
private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
- int defaultLayout = idp.defaultLayoutId;
+ int defaultLayout = mUseTestWorkspaceLayout
+ ? TEST_WORKSPACE_LAYOUT_RES_XML : idp.defaultLayoutId;
if (getContext().getSystemService(UserManager.class).isDemoUser()
&& idp.demoModeLayoutId != 0) {
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index e3aa758..a5c5c02 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -1,24 +1,19 @@
package com.android.launcher3;
-import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import android.annotation.TargetApi;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewDebug;
import android.view.WindowInsets;
-import androidx.annotation.RequiresApi;
-
import com.android.launcher3.graphics.SysUiScrim;
import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.window.WindowManagerProxy;
import java.util.Collections;
import java.util.List;
@@ -60,76 +55,12 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (Utilities.ATLEAST_R) {
- insets = updateInsetsDueToTaskbar(insets);
- Insets systemWindowInsets = insets.getInsetsIgnoringVisibility(
- WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
- mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
- systemWindowInsets.bottom);
- } else {
- mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
- insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
- }
+ insets = WindowManagerProxy.INSTANCE.get(getContext())
+ .normalizeWindowInsets(getContext(), insets, mTempRect);
handleSystemWindowInsets(mTempRect);
return insets;
}
- /**
- * Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately,
- * and can be destroyed and recreated. Thus, instead of relying on taskbar being present to
- * get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
- * is currently attached.
- *
- * @param oldInsets The system-provided insets, which we are modifying.
- * @return The updated insets.
- */
- @RequiresApi(api = Build.VERSION_CODES.R)
- private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) {
- if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) {
- // 3P launchers based on Launcher3 should still be inset like normal.
- return oldInsets;
- }
-
- WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
-
- DeviceProfile dp = mActivity.getDeviceProfile();
- Resources resources = getResources();
-
- Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
- Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
- oldNavInsets.bottom);
-
- if (dp.isLandscape) {
- boolean isGesturalMode = ResourceUtils.getIntegerByName(
- "config_navBarInteractionMode",
- resources,
- INVALID_RESOURCE_HANDLE) == 2;
- if (dp.isTablet || isGesturalMode) {
- newNavInsets.bottom = dp.isTaskbarPresent
- ? 0
- : ResourceUtils.getNavbarSize("navigation_bar_height_landscape", resources);
- } else {
- int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
- if (dp.isSeascape()) {
- newNavInsets.left = navWidth;
- } else {
- newNavInsets.right = navWidth;
- }
- }
- } else {
- newNavInsets.bottom = dp.isTaskbarPresent
- ? 0
- : ResourceUtils.getNavbarSize("navigation_bar_height", resources);
- }
- updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
- updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
- Insets.of(newNavInsets));
-
- mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets);
-
- return updatedInsetsBuilder.build();
- }
-
@Override
public void setInsets(Rect insets) {
// If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 048aaaa..66195f3 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -374,6 +374,12 @@
public static final String METHOD_CREATE_EMPTY_DB = "create_empty_db";
+ public static final String METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG =
+ "set_use_test_workspace_layout_flag";
+
+ public static final String METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG =
+ "clear_use_test_workspace_layout_flag";
+
public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites";
public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets";
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index ece123d..1c36db1 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -28,6 +28,9 @@
public static final String NAVBAR_BOTTOM_GESTURE_LARGER_SIZE =
"navigation_bar_gesture_larger_height";
+ public static final String NAVBAR_HEIGHT = "navigation_bar_height";
+ public static final String NAVBAR_HEIGHT_LANDSCAPE = "navigation_bar_height_landscape";
+
public static int getNavbarSize(String resName, Resources res) {
return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index df97d2f..8b19a19 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
+import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1266,6 +1267,7 @@
// different effects based on device performance. On at least one relatively high-end
// device I've tried, translating the launcher causes things to get quite laggy.
mLauncher.getDragLayer().setTranslationX(transX);
+ Log.d(BAD_STATE, "Workspace onOverlayScrollChanged DragLayer ALPHA_INDEX_OVERLAY=" + alpha);
mLauncher.getDragLayer().getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha);
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 114f813..b94a612 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -256,4 +256,11 @@
layoutParams.removeRule(RelativeLayout.BELOW);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
}
+
+ @Override
+ protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
+ BaseAdapterProvider[] adapterProviders) {
+ return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
+ adapterProviders);
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index f1ca9c0..58df50c 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -15,36 +15,20 @@
*/
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.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.widget.TextView;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityEventCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.views.ActivityContext;
-import java.util.Arrays;
import java.util.List;
/**
@@ -53,111 +37,26 @@
* @param <T> Type of context inflating all apps.
*/
public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
- RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
+ BaseAllAppsAdapter<T> {
public static final String TAG = "AppsGridAdapter";
+ private final GridLayoutManager mGridLayoutMgr;
+ private final GridSpanSizer mGridSizer;
- // A normal icon
- public static final int VIEW_TYPE_ICON = 1 << 1;
- // The message shown when there are no filtered results
- public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 2;
- // The message to continue to a market search when there are no filtered results
- public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 3;
-
- // We use various dividers for various purposes. They share enough attributes to reuse layouts,
- // but differ in enough attributes to require different view types
-
- // A divider that separates the apps list and the search market button
- public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
-
- // Common view type masks
- public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
- public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
-
-
- private final BaseAdapterProvider[] mAdapterProviders;
-
- /**
- * ViewHolder for each icon.
- */
- public static class ViewHolder extends RecyclerView.ViewHolder {
-
- public ViewHolder(View v) {
- super(v);
- }
+ public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
+ AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
+ super(activityContext, inflater, apps, adapterProviders);
+ mGridSizer = new GridSpanSizer();
+ mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
+ mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
+ setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
}
/**
- * Info about a particular adapter item (can be either section or app)
+ * Returns the grid layout manager.
*/
- public static class AdapterItem {
- /** Common properties */
- // The index of this adapter item in the list
- public int position;
- // The type of this item
- public int viewType;
-
- // The section name of this item. Note that there can be multiple items with different
- // sectionNames in the same section
- public String sectionName = null;
- // The row that this item shows up on
- public int rowIndex;
- // The index of this app in the row
- public int rowAppIndex;
- // The associated ItemInfoWithIcon for the item
- public ItemInfoWithIcon itemInfo = null;
- // The index of this app not including sections
- public int appIndex = -1;
- // Search section associated to result
- public DecorationInfo decorationInfo = null;
-
- /**
- * Factory method for AppIcon AdapterItem
- */
- public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
- int appIndex) {
- AdapterItem item = new AdapterItem();
- item.viewType = VIEW_TYPE_ICON;
- item.position = pos;
- item.sectionName = sectionName;
- item.itemInfo = appInfo;
- item.appIndex = appIndex;
- return item;
- }
-
- /**
- * Factory method for empty search results view
- */
- public static AdapterItem asEmptySearch(int pos) {
- AdapterItem item = new AdapterItem();
- item.viewType = VIEW_TYPE_EMPTY_SEARCH;
- item.position = pos;
- return item;
- }
-
- /**
- * Factory method for a dividerView in AllAppsSearch
- */
- public static AdapterItem asAllAppsDivider(int pos) {
- AdapterItem item = new AdapterItem();
- item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
- item.position = pos;
- return item;
- }
-
- /**
- * Factory method for a market search button
- */
- public static AdapterItem asMarketSearch(int pos) {
- AdapterItem item = new AdapterItem();
- item.viewType = VIEW_TYPE_SEARCH_MARKET;
- item.position = pos;
- return item;
- }
-
- protected boolean isCountedForAccessibility() {
- return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
- }
+ public RecyclerView.LayoutManager getLayoutManager() {
+ return mGridLayoutMgr;
}
/**
@@ -217,7 +116,7 @@
*/
private int getRowsNotForAccessibility(int adapterPosition) {
List<AdapterItem> items = mApps.getAdapterItems();
- adapterPosition = Math.max(adapterPosition, mApps.getAdapterItems().size() - 1);
+ adapterPosition = Math.max(adapterPosition, items.size() - 1);
int extraRows = 0;
for (int i = 0; i <= adapterPosition; i++) {
if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
@@ -228,6 +127,20 @@
}
}
+ @Override
+ public void setAppsPerRow(int appsPerRow) {
+ mAppsPerRow = appsPerRow;
+ int totalSpans = mAppsPerRow;
+ for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
+ for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
+ if (totalSpans % itemPerRow != 0) {
+ totalSpans *= itemPerRow;
+ }
+ }
+ }
+ mGridLayoutMgr.setSpanCount(totalSpans);
+ }
+
/**
* Helper class to size the grid items.
*/
@@ -255,202 +168,4 @@
}
}
}
-
- private final T mActivityContext;
- private final LayoutInflater mLayoutInflater;
- private final AlphabeticalAppsList<T> mApps;
- private final GridLayoutManager mGridLayoutMgr;
- private final GridSpanSizer mGridSizer;
-
- private final OnClickListener mOnIconClickListener;
- private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
-
- private int mAppsPerRow;
-
- private OnFocusChangeListener mIconFocusListener;
-
- // The text to show when there are no search results and no market search handler.
- protected String mEmptySearchMessage;
- // The click listener to send off to the market app, updated each time the search query changes.
- private OnClickListener mMarketSearchClickListener;
-
- private final int mExtraHeight;
-
- public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
- AlphabeticalAppsList<T> apps, BaseAdapterProvider[] adapterProviders) {
- Resources res = activityContext.getResources();
- mActivityContext = activityContext;
- mApps = apps;
- mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
- mGridSizer = new GridSpanSizer();
- mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
- mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
- mLayoutInflater = inflater;
-
- mOnIconClickListener = mActivityContext.getItemOnClickListener();
-
- mAdapterProviders = adapterProviders;
- setAppsPerRow(mActivityContext.getDeviceProfile().numShownAllAppsColumns);
- mExtraHeight = mActivityContext.getResources().getDimensionPixelSize(
- R.dimen.all_apps_height_extra);
- }
-
- public void setAppsPerRow(int appsPerRow) {
- mAppsPerRow = appsPerRow;
- int totalSpans = mAppsPerRow;
- for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
- for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
- if (totalSpans % itemPerRow != 0) {
- totalSpans *= itemPerRow;
- }
- }
- }
- mGridLayoutMgr.setSpanCount(totalSpans);
- }
-
- /**
- * Sets the long click listener for icons
- */
- public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
- mOnIconLongClickListener = listener;
- }
-
- public static boolean isDividerViewType(int viewType) {
- return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
- }
-
- public static boolean isIconViewType(int viewType) {
- return isViewType(viewType, VIEW_TYPE_MASK_ICON);
- }
-
- public static boolean isViewType(int viewType, int viewTypeMask) {
- return (viewType & viewTypeMask) != 0;
- }
-
- public void setIconFocusListener(OnFocusChangeListener focusListener) {
- mIconFocusListener = focusListener;
- }
-
- /**
- * Sets the last search query that was made, used to show when there are no results and to also
- * seed the intent for searching the market.
- */
- public void setLastSearchQuery(String query, OnClickListener marketSearchClickListener) {
- Resources res = mActivityContext.getResources();
- mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
- mMarketSearchClickListener = marketSearchClickListener;
- }
-
- /**
- * Returns the grid layout manager.
- */
- public GridLayoutManager getLayoutManager() {
- return mGridLayoutMgr;
- }
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- switch (viewType) {
- case VIEW_TYPE_ICON:
- int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
- : R.layout.all_apps_icon_twoline;
- BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
- layout, parent, false);
- icon.setLongPressTimeoutFactor(1f);
- icon.setOnFocusChangeListener(mIconFocusListener);
- icon.setOnClickListener(mOnIconClickListener);
- icon.setOnLongClickListener(mOnIconLongClickListener);
- // Ensure the all apps icon height matches the workspace icons in portrait mode.
- icon.getLayoutParams().height =
- mActivityContext.getDeviceProfile().allAppsCellHeightPx;
- if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
- icon.getLayoutParams().height += mExtraHeight;
- }
- return new ViewHolder(icon);
- case VIEW_TYPE_EMPTY_SEARCH:
- return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
- parent, false));
- case VIEW_TYPE_SEARCH_MARKET:
- View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
- parent, false);
- searchMarketView.setOnClickListener(mMarketSearchClickListener);
- return new ViewHolder(searchMarketView);
- case VIEW_TYPE_ALL_APPS_DIVIDER:
- return new ViewHolder(mLayoutInflater.inflate(
- R.layout.all_apps_divider, parent, false));
- default:
- BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
- if (adapterProvider != null) {
- return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
- }
- throw new RuntimeException("Unexpected view type" + viewType);
- }
- }
-
- @Override
- public void onBindViewHolder(ViewHolder holder, int position) {
- switch (holder.getItemViewType()) {
- case VIEW_TYPE_ICON:
- AdapterItem adapterItem = mApps.getAdapterItems().get(position);
- BubbleTextView icon = (BubbleTextView) holder.itemView;
- icon.reset();
- if (adapterItem.itemInfo instanceof AppInfo) {
- icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
- } else {
- icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
- }
- break;
- case VIEW_TYPE_EMPTY_SEARCH:
- TextView emptyViewText = (TextView) holder.itemView;
- emptyViewText.setText(mEmptySearchMessage);
- emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
- Gravity.START | Gravity.CENTER_VERTICAL);
- break;
- case VIEW_TYPE_SEARCH_MARKET:
- TextView searchView = (TextView) holder.itemView;
- if (mMarketSearchClickListener != null) {
- searchView.setVisibility(View.VISIBLE);
- } else {
- searchView.setVisibility(View.GONE);
- }
- break;
- case VIEW_TYPE_ALL_APPS_DIVIDER:
- // nothing to do
- break;
- default:
- BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
- if (adapterProvider != null) {
- adapterProvider.onBindView(holder, position);
- }
- }
- }
-
- @Override
- public void onViewRecycled(@NonNull ViewHolder holder) {
- super.onViewRecycled(holder);
- }
-
- @Override
- public boolean onFailedToRecycleView(ViewHolder holder) {
- // Always recycle and we will reset the view when it is bound
- return true;
- }
-
- @Override
- public int getItemCount() {
- return mApps.getAdapterItems().size();
- }
-
- @Override
- public int getItemViewType(int position) {
- AdapterItem item = mApps.getAdapterItems().get(position);
- return item.viewType;
- }
-
- @Nullable
- private BaseAdapterProvider getAdapterProvider(int viewType) {
- return Arrays.stream(mAdapterProviders).filter(
- adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
- null);
- }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index c2cb845..7dbe711 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -19,6 +19,7 @@
import static android.view.View.MeasureSpec.UNSPECIFIED;
import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
import static com.android.launcher3.util.LogConfig.SEARCH_LOGGING;
@@ -203,6 +204,7 @@
StatsLogManager mgr = ActivityContext.lookupContext(getContext()).getStatsLogManager();
switch (state) {
case SCROLL_STATE_DRAGGING:
+ mgr.logger().log(LAUNCHER_ALLAPPS_SCROLLED);
requestFocus();
mgr.logger().sendToInteractionJankMonitor(
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 1a1d521..16264da 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -18,7 +18,7 @@
import android.content.Context;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -81,8 +81,8 @@
private final List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
// The of ordered component names as a result of a search query
- private ArrayList<AdapterItem> mSearchResults;
- private AllAppsGridAdapter<T> mAdapter;
+ private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
+ private BaseAllAppsAdapter<T> mAdapter;
private AppInfoComparator mAppNameComparator;
private final int mNumAppsPerRow;
private int mNumAppRowsInAdapter;
@@ -106,7 +106,7 @@
/**
* Sets the adapter to notify when this dataset changes.
*/
- public void setAdapter(AllAppsGridAdapter<T> adapter) {
+ public void setAdapter(BaseAllAppsAdapter<T> adapter) {
mAdapter = adapter;
}
@@ -171,30 +171,33 @@
* Returns whether there are is a filter set.
*/
public boolean hasFilter() {
- return (mSearchResults != null);
+ return !mSearchResults.isEmpty();
}
/**
* Returns whether there are no filtered results.
*/
public boolean hasNoFilteredResults() {
- return (mSearchResults != null) && mAccessibilityResultsCount == 0;
+ return hasFilter() && mAccessibilityResultsCount == 0;
}
/**
* Sets results list for search
*/
public boolean setSearchResults(ArrayList<AdapterItem> results) {
- if (!Objects.equals(results, mSearchResults)) {
- mSearchResults = results;
- updateAdapterItems();
- return true;
+ if (Objects.equals(results, mSearchResults)) {
+ return false;
}
- return false;
+ mSearchResults.clear();
+ if (results != null) {
+ mSearchResults.addAll(results);
+ }
+ updateAdapterItems();
+ return true;
}
public boolean appendSearchResults(ArrayList<AdapterItem> results) {
- if (mSearchResults != null && results != null && results.size() > 0) {
+ if (hasFilter() && results != null && results.size() > 0) {
updateSearchAdapterItems(results, mSearchResults.size());
refreshRecyclerView();
return true;
@@ -259,7 +262,7 @@
}
// Recompose the set of adapter items from the current set of apps
- if (mSearchResults == null) {
+ if (mSearchResults.isEmpty()) {
updateAdapterItems();
}
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
new file mode 100644
index 0000000..1d1960d
--- /dev/null
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.Arrays;
+
+/**
+ * Adapter for all the apps.
+ *
+ * @param <T> Type of context inflating all apps.
+ */
+public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> extends
+ RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> {
+
+ public static final String TAG = "BaseAllAppsAdapter";
+
+ // A normal icon
+ public static final int VIEW_TYPE_ICON = 1 << 1;
+ // The message shown when there are no filtered results
+ public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 2;
+ // The message to continue to a market search when there are no filtered results
+ public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 3;
+
+ // We use various dividers for various purposes. They share enough attributes to reuse layouts,
+ // but differ in enough attributes to require different view types
+
+ // A divider that separates the apps list and the search market button
+ public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
+
+ // Common view type masks
+ public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
+ public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
+
+
+ protected final BaseAdapterProvider[] mAdapterProviders;
+
+ /**
+ * ViewHolder for each icon.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+
+ public ViewHolder(View v) {
+ super(v);
+ }
+ }
+
+ /** Sets the number of apps to be displayed in one row of the all apps screen. */
+ public abstract void setAppsPerRow(int appsPerRow);
+
+ /**
+ * Info about a particular adapter item (can be either section or app)
+ */
+ public static class AdapterItem {
+ /** Common properties */
+ // The index of this adapter item in the list
+ public int position;
+ // The type of this item
+ public int viewType;
+
+ // The section name of this item. Note that there can be multiple items with different
+ // sectionNames in the same section
+ public String sectionName = null;
+ // The row that this item shows up on
+ public int rowIndex;
+ // The index of this app in the row
+ public int rowAppIndex;
+ // The associated ItemInfoWithIcon for the item
+ public ItemInfoWithIcon itemInfo = null;
+ // The index of this app not including sections
+ public int appIndex = -1;
+ // Search section associated to result
+ public DecorationInfo decorationInfo = null;
+
+ /**
+ * Factory method for AppIcon AdapterItem
+ */
+ public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
+ int appIndex) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = VIEW_TYPE_ICON;
+ item.position = pos;
+ item.sectionName = sectionName;
+ item.itemInfo = appInfo;
+ item.appIndex = appIndex;
+ return item;
+ }
+
+ /**
+ * Factory method for empty search results view
+ */
+ public static AdapterItem asEmptySearch(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = VIEW_TYPE_EMPTY_SEARCH;
+ item.position = pos;
+ return item;
+ }
+
+ /**
+ * Factory method for a dividerView in AllAppsSearch
+ */
+ public static AdapterItem asAllAppsDivider(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
+ item.position = pos;
+ return item;
+ }
+
+ /**
+ * Factory method for a market search button
+ */
+ public static AdapterItem asMarketSearch(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = VIEW_TYPE_SEARCH_MARKET;
+ item.position = pos;
+ return item;
+ }
+
+ protected boolean isCountedForAccessibility() {
+ return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
+ }
+ }
+
+ protected final T mActivityContext;
+ protected final AlphabeticalAppsList<T> mApps;
+ // The text to show when there are no search results and no market search handler.
+ protected String mEmptySearchMessage;
+ protected int mAppsPerRow;
+
+ private final LayoutInflater mLayoutInflater;
+ private final OnClickListener mOnIconClickListener;
+ private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
+ private OnFocusChangeListener mIconFocusListener;
+ // The click listener to send off to the market app, updated each time the search query changes.
+ private OnClickListener mMarketSearchClickListener;
+ private final int mExtraHeight;
+
+ public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
+ AlphabeticalAppsList<T> apps, BaseAdapterProvider[] adapterProviders) {
+ Resources res = activityContext.getResources();
+ mActivityContext = activityContext;
+ mApps = apps;
+ mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
+ mLayoutInflater = inflater;
+
+ mOnIconClickListener = mActivityContext.getItemOnClickListener();
+
+ mAdapterProviders = adapterProviders;
+ mExtraHeight = res.getDimensionPixelSize(R.dimen.all_apps_height_extra);
+ }
+
+ /**
+ * 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);
+ }
+
+ /** Checks if the passed viewType represents all apps icon. */
+ public static boolean isIconViewType(int viewType) {
+ return isViewType(viewType, VIEW_TYPE_MASK_ICON);
+ }
+
+ public void setIconFocusListener(OnFocusChangeListener focusListener) {
+ mIconFocusListener = focusListener;
+ }
+
+ /**
+ * Sets the last search query that was made, used to show when there are no results and to also
+ * seed the intent for searching the market.
+ */
+ public void setLastSearchQuery(String query, OnClickListener marketSearchClickListener) {
+ Resources res = mActivityContext.getResources();
+ mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
+ mMarketSearchClickListener = marketSearchClickListener;
+ }
+
+ /**
+ * Returns the layout manager.
+ */
+ public abstract RecyclerView.LayoutManager getLayoutManager();
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ switch (viewType) {
+ case VIEW_TYPE_ICON:
+ int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
+ : R.layout.all_apps_icon_twoline;
+ BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
+ layout, parent, false);
+ icon.setLongPressTimeoutFactor(1f);
+ icon.setOnFocusChangeListener(mIconFocusListener);
+ icon.setOnClickListener(mOnIconClickListener);
+ icon.setOnLongClickListener(mOnIconLongClickListener);
+ // Ensure the all apps icon height matches the workspace icons in portrait mode.
+ icon.getLayoutParams().height =
+ mActivityContext.getDeviceProfile().allAppsCellHeightPx;
+ if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
+ icon.getLayoutParams().height += mExtraHeight;
+ }
+ return new ViewHolder(icon);
+ case VIEW_TYPE_EMPTY_SEARCH:
+ return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
+ parent, false));
+ case VIEW_TYPE_SEARCH_MARKET:
+ View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
+ parent, false);
+ searchMarketView.setOnClickListener(mMarketSearchClickListener);
+ return new ViewHolder(searchMarketView);
+ case VIEW_TYPE_ALL_APPS_DIVIDER:
+ return new ViewHolder(mLayoutInflater.inflate(
+ R.layout.all_apps_divider, parent, false));
+ default:
+ BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
+ if (adapterProvider != null) {
+ return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
+ }
+ throw new RuntimeException("Unexpected view type" + viewType);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ switch (holder.getItemViewType()) {
+ case VIEW_TYPE_ICON:
+ AdapterItem adapterItem = mApps.getAdapterItems().get(position);
+ BubbleTextView icon = (BubbleTextView) holder.itemView;
+ icon.reset();
+ if (adapterItem.itemInfo instanceof AppInfo) {
+ icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
+ } else {
+ icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
+ }
+ break;
+ case VIEW_TYPE_EMPTY_SEARCH:
+ TextView emptyViewText = (TextView) holder.itemView;
+ emptyViewText.setText(mEmptySearchMessage);
+ emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
+ Gravity.START | Gravity.CENTER_VERTICAL);
+ break;
+ case VIEW_TYPE_SEARCH_MARKET:
+ TextView searchView = (TextView) holder.itemView;
+ if (mMarketSearchClickListener != null) {
+ searchView.setVisibility(View.VISIBLE);
+ } else {
+ searchView.setVisibility(View.GONE);
+ }
+ break;
+ case VIEW_TYPE_ALL_APPS_DIVIDER:
+ // nothing to do
+ break;
+ default:
+ BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
+ if (adapterProvider != null) {
+ adapterProvider.onBindView(holder, position);
+ }
+ }
+ }
+
+ @Override
+ public void onViewRecycled(@NonNull ViewHolder holder) {
+ super.onViewRecycled(holder);
+ }
+
+ @Override
+ public boolean onFailedToRecycleView(ViewHolder holder) {
+ // Always recycle and we will reset the view when it is bound
+ return true;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mApps.getAdapterItems().size();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ AdapterItem item = mApps.getAdapterItems().get(position);
+ return item.viewType;
+ }
+
+ protected static boolean isViewType(int viewType, int viewTypeMask) {
+ return (viewType & viewTypeMask) != 0;
+ }
+
+ @Nullable
+ protected BaseAdapterProvider getAdapterProvider(int viewType) {
+ return Arrays.stream(mAdapterProviders).filter(
+ adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
+ null);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index bfc7515..f913aa9 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -44,7 +44,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.ColorUtils;
-import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
@@ -443,8 +442,8 @@
if (showTabs == mUsingTabs && !force) {
return;
}
- replaceRVContainer(showTabs);
mUsingTabs = showTabs;
+ replaceRVContainer(mUsingTabs);
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
@@ -697,18 +696,21 @@
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
}
+ protected abstract BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
+ BaseAdapterProvider[] adapterProviders);
+
protected int getHeaderBottom() {
return (int) getTranslationY();
}
- /** Holds a {@link AllAppsGridAdapter} and related fields. */
+ /** Holds a {@link BaseAllAppsAdapter} and related fields. */
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
private final boolean mIsWork;
- public final AllAppsGridAdapter<T> adapter;
- final LinearLayoutManager mLayoutManager;
+ public final BaseAllAppsAdapter<T> adapter;
+ final RecyclerView.LayoutManager mLayoutManager;
final AlphabeticalAppsList<T> mAppsList;
final Rect mPadding = new Rect();
AllAppsRecyclerView mRecyclerView;
@@ -724,8 +726,7 @@
mWorkManager.getAdapterProvider()}
: new BaseAdapterProvider[]{mMainAdapterProvider};
- adapter = new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
- adapterProviders);
+ adapter = getAdapter(mAppsList, adapterProviders);
mAppsList.setAdapter(adapter);
mLayoutManager = adapter.getLayoutManager();
}
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index f9055ee..6299657 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -65,4 +65,7 @@
* sets highlight result's title
*/
default void setFocusedResultTitle(@Nullable CharSequence title) { }
+
+ /** Refresh the currently displayed list of results. */
+ default void refreshResults() {}
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 0137e2a..fd8945a 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -33,7 +33,7 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 4a886a4..cb459ea 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -38,9 +38,9 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.search.SearchCallback;
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 1f854c6..222c8fe 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -23,7 +23,7 @@
import androidx.annotation.AnyThread;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 278bcf2..3e0c9fc 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -52,7 +52,7 @@
* Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
* and should be modified at a project level.
*/
- public static final boolean QSB_ON_FIRST_SCREEN = true;
+ public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN;
/**
* Feature flag to handle define config changes dynamically instead of killing the process.
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index b914ae2..a3945fd 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -98,6 +98,7 @@
final ValueAnimator mAnim;
// Whether mAnim has started. Unlike mAnim.isStarted(), this is true even after mAnim ends.
private boolean mAnimStarted;
+ private Runnable mOnAnimEndCallback = null;
private int mLastTouchX;
private int mLastTouchY;
@@ -180,6 +181,14 @@
public void onAnimationStart(Animator animation) {
mAnimStarted = true;
}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (mOnAnimEndCallback != null) {
+ mOnAnimEndCallback.run();
+ }
+ }
});
setDragRegion(new Rect(0, 0, width, height));
@@ -199,6 +208,10 @@
setWillNotDraw(false);
}
+ public void setOnAnimationEndCallback(Runnable callback) {
+ mOnAnimEndCallback = callback;
+ }
+
/**
* Initialize {@code #mIconDrawable} if the item can be represented using
* an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 2459e09..cc17064 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -87,6 +87,7 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
@@ -128,7 +129,8 @@
public PreviewContext(Context base, InvariantDeviceProfile idp) {
super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
- CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE);
+ CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
+ WindowManagerProxy.INSTANCE);
mIdp = idp;
mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
mObjectMap.put(LauncherAppState.INSTANCE,
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 308a8f2..5ece4a6 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -440,7 +440,7 @@
cn,
sectionKey.first);
}
- if (loadFallbackTitle && TextUtils.isEmpty(entry.title)) {
+ if (loadFallbackTitle && TextUtils.isEmpty(entry.title) && lai != null) {
loadFallbackTitle(
lai,
entry,
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 0c1ba8b..f392e95 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -527,7 +527,11 @@
LAUNCHER_TASKBAR_LONGPRESS_SHOW(897),
@UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
- LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913);
+ LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913),
+
+ @UiEvent(doc = "User scrolled on one of the all apps surfaces such as A-Z list, search "
+ + "result page etc.")
+ LAUNCHER_ALLAPPS_SCROLLED(985);
// ADD MORE
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index b45c97b..c554d06 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -17,15 +17,11 @@
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
-import android.graphics.Insets;
-import android.os.Build;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowInsets;
import androidx.annotation.CallSuper;
-import androidx.annotation.RequiresApi;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherRootView;
@@ -179,14 +175,6 @@
}
/**
- * Gives subclasses a chance to override some window insets (via
- * {@link android.view.WindowInsets.Builder#setInsets(int, Insets)}).
- */
- @RequiresApi(api = Build.VERSION_CODES.R)
- public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
- WindowInsets oldInsets) { }
-
- /**
* Runs the given {@param r} runnable when this activity binds to the touch interaction service.
*/
public void runOnBindToTouchInteractionService(Runnable r) {
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 867fd99..8b425da 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -21,7 +21,7 @@
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
+import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 2bf3b14..faf5817 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -82,6 +82,10 @@
public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized";
public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list";
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
+ public static final String REQUEST_ENABLE_MANUAL_TASKBAR_STASHING = "enable-taskbar-stashing";
+ public static final String REQUEST_DISABLE_MANUAL_TASKBAR_STASHING = "disable-taskbar-stashing";
+ public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
+ public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
@@ -96,6 +100,10 @@
public static final String REQUEST_GET_HAD_NONTEST_EVENTS = "get-had-nontest-events";
public static final String REQUEST_STOP_EVENT_LOGGING = "stop-event-logging";
public static final String REQUEST_CLEAR_DATA = "clear-data";
+ public static final String REQUEST_USE_TEST_WORKSPACE_LAYOUT = "use-test-workspace-layout";
+ public static final String REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT =
+ "use-default-workspace-layout";
+ public static final String REQUEST_HOTSEAT_ICON_NAMES = "get-hotseat-icon-names";
public static final String REQUEST_IS_TABLET = "is-tablet";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
public static final String REQUEST_START_DRAG_THRESHOLD = "start-drag-threshold";
@@ -125,8 +133,9 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
- public static final String TASK_VIEW_ID_CRASH = "b/195430732";
public static final String NO_DROP_TARGET = "b/195031154";
public static final String NULL_INT_SET = "b/200572078";
public static final String MISSING_PROMISE_ICON = "b/202985412";
+
+ public static final String BAD_STATE = "b/223498680";
}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index f944d3c..22e3de8 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -26,10 +26,8 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
-import static com.android.launcher3.util.WindowManagerCompat.MIN_LARGE_TABLET_WIDTH;
-import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
-
-import static java.util.Collections.emptyMap;
+import static com.android.launcher3.util.window.WindowManagerProxy.MIN_LARGE_TABLET_WIDTH;
+import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
@@ -38,12 +36,13 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.view.Display;
import androidx.annotation.AnyThread;
@@ -52,11 +51,12 @@
import com.android.launcher3.ResourceUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.launcher3.util.window.WindowManagerProxy;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Map;
+import java.util.Collections;
import java.util.Objects;
import java.util.Set;
@@ -89,6 +89,7 @@
// Null for SDK < S
private final Context mWindowContext;
+
// The callback in this listener updates DeviceProfile, which other listeners might depend on
private DisplayInfoChangeListener mPriorityListener;
private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
@@ -115,23 +116,9 @@
mContext.registerReceiver(mReceiver,
getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
+ WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
mInfo = new Info(getDisplayInfoContext(display), display,
- getInternalDisplays(mDM), emptyMap());
- }
-
- private static ArrayMap<String, PortraitSize> getInternalDisplays(
- DisplayManager displayManager) {
- Display[] displays = displayManager.getDisplays();
- ArrayMap<String, PortraitSize> internalDisplays = new ArrayMap<>();
- for (Display display : displays) {
- if (ApiWrapper.isInternalDisplay(display)) {
- Point size = new Point();
- display.getRealSize(size);
- internalDisplays.put(ApiWrapper.getUniqueId(display),
- new PortraitSize(size.x, size.y));
- }
- }
- return internalDisplays;
+ wmProxy, wmProxy.estimateInternalDisplayBounds(context));
}
/**
@@ -226,16 +213,17 @@
@AnyThread
private void handleInfoChange(Display display) {
+ WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
Context displayContext = getDisplayInfoContext(display);
- Info newInfo = new Info(displayContext, display,
- oldInfo.mInternalDisplays, oldInfo.mPerDisplayBounds);
+ Info newInfo = new Info(displayContext, display, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
|| newInfo.navigationMode != oldInfo.navigationMode) {
// Cache may not be valid anymore, recreate without cache
- newInfo = new Info(displayContext, display, getInternalDisplays(mDM), emptyMap());
+ newInfo = new Info(displayContext, display, wmProxy,
+ wmProxy.estimateInternalDisplayBounds(displayContext));
}
int change = 0;
@@ -254,9 +242,8 @@
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)) {
change |= CHANGE_SUPPORTED_BOUNDS;
- PortraitSize realSize = new PortraitSize(newInfo.currentSize.x, newInfo.currentSize.y);
- PortraitSize expectedSize = oldInfo.mInternalDisplays.get(
- ApiWrapper.getUniqueId(display));
+ Point currentS = newInfo.currentSize;
+ Point expectedS = oldInfo.mPerDisplayBounds.get(newInfo.displayId).first.size;
if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) {
Log.e("b/198965093",
"Inconsistent number of displays"
@@ -264,7 +251,9 @@
+ "\noldInfo.supportedBounds: " + oldInfo.supportedBounds
+ "\nnewInfo.supportedBounds: " + newInfo.supportedBounds);
}
- if (!realSize.equals(expectedSize) && display.getState() == Display.STATE_OFF) {
+ if ((Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y)
+ || Math.max(currentS.x, currentS.y) != Math.max(expectedS.x, expectedS.y))
+ && display.getState() == Display.STATE_OFF) {
Log.e("b/198965093", "Display size changed while display is off, ignoring change");
return;
}
@@ -290,30 +279,38 @@
public static class Info {
- // Configuration properties
+ // Cached property
public final int rotation;
+ public final String displayId;
+ public final Point currentSize;
+ public final Rect cutout;
+
+ // Configuration property
public final float fontScale;
public final int densityDpi;
public final NavigationMode navigationMode;
private final PortraitSize mScreenSizeDp;
- public final Point currentSize;
-
- public String displayId;
public final Set<WindowBounds> supportedBounds = new ArraySet<>();
- private final Map<String, Set<WindowBounds>> mPerDisplayBounds = new ArrayMap<>();
- private final ArrayMap<String, PortraitSize> mInternalDisplays;
+
+ private final ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> mPerDisplayBounds =
+ new ArrayMap<>();
public Info(Context context, Display display) {
- this(context, display, new ArrayMap<>(), emptyMap());
+ /* don't need system overrides for external displays */
+ this(context, display, new WindowManagerProxy(), new ArrayMap<>());
}
- private Info(Context context, Display display,
- ArrayMap<String, PortraitSize> internalDisplays,
- Map<String, Set<WindowBounds>> perDisplayBoundsCache) {
- mInternalDisplays = internalDisplays;
- rotation = display.getRotation();
+ // Used for testing
+ public Info(Context context, Display display,
+ WindowManagerProxy wmProxy,
+ ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache) {
+ CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(display);
+ rotation = displayInfo.rotation;
+ currentSize = displayInfo.size;
+ displayId = displayInfo.id;
+ cutout = displayInfo.cutout;
Configuration config = context.getResources().getConfiguration();
fontScale = config.fontScale;
@@ -321,54 +318,29 @@
mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp);
navigationMode = parseNavigationMode(context);
- currentSize = new Point();
- display.getRealSize(currentSize);
+ mPerDisplayBounds.putAll(perDisplayBoundsCache);
+ Pair<CachedDisplayInfo, WindowBounds[]> cachedValue = mPerDisplayBounds.get(displayId);
- displayId = ApiWrapper.getUniqueId(display);
- Set<WindowBounds> currentSupportedBounds =
- getSupportedBoundsForDisplay(display, currentSize);
- mPerDisplayBounds.put(displayId, currentSupportedBounds);
- supportedBounds.addAll(currentSupportedBounds);
-
- if (ApiWrapper.isInternalDisplay(display) && internalDisplays.size() > 1) {
- int displayCount = internalDisplays.size();
- for (int i = 0; i < displayCount; i++) {
- String displayKey = internalDisplays.keyAt(i);
- if (TextUtils.equals(displayId, displayKey)) {
- continue;
- }
-
- Set<WindowBounds> displayBounds = perDisplayBoundsCache.get(displayKey);
- if (displayBounds == null) {
- // We assume densityDpi is the same across all internal displays
- displayBounds = WindowManagerCompat.estimateDisplayProfiles(
- context, internalDisplays.valueAt(i), densityDpi,
- ApiWrapper.TASKBAR_DRAWN_IN_PROCESS);
- }
-
- supportedBounds.addAll(displayBounds);
- mPerDisplayBounds.put(displayKey, displayBounds);
+ WindowBounds realBounds = wmProxy.getRealBounds(context, display, displayInfo);
+ if (cachedValue == null) {
+ supportedBounds.add(realBounds);
+ } else {
+ // Verify that the real bounds are a match
+ WindowBounds expectedBounds = cachedValue.second[displayInfo.rotation];
+ if (!realBounds.equals(expectedBounds)) {
+ WindowBounds[] clone = new WindowBounds[4];
+ System.arraycopy(cachedValue.second, 0, clone, 0, 4);
+ clone[displayInfo.rotation] = realBounds;
+ cachedValue = Pair.create(displayInfo.normalize(), clone);
+ mPerDisplayBounds.put(displayId, cachedValue);
}
}
+ mPerDisplayBounds.values().forEach(
+ pair -> Collections.addAll(supportedBounds, pair.second));
Log.d("b/211775278", "displayId: " + displayId + ", currentSize: " + currentSize);
Log.d("b/211775278", "perDisplayBounds: " + mPerDisplayBounds);
}
- private static Set<WindowBounds> getSupportedBoundsForDisplay(Display display, Point size) {
- Point smallestSize = new Point();
- Point largestSize = new Point();
- display.getCurrentSizeRange(smallestSize, largestSize);
-
- int portraitWidth = Math.min(size.x, size.y);
- int portraitHeight = Math.max(size.x, size.y);
- Set<WindowBounds> result = new ArraySet<>();
- result.add(new WindowBounds(portraitWidth, portraitHeight,
- smallestSize.x, largestSize.y));
- result.add(new WindowBounds(portraitHeight, portraitWidth,
- largestSize.x, smallestSize.y));
- return result;
- }
-
/**
* Returns {@code true} if the bounds represent a tablet.
*/
diff --git a/src/com/android/launcher3/util/Executors.java b/src/com/android/launcher3/util/Executors.java
index 6329540..8485371 100644
--- a/src/com/android/launcher3/util/Executors.java
+++ b/src/com/android/launcher3/util/Executors.java
@@ -15,10 +15,17 @@
*/
package com.android.launcher3.util;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
+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;
@@ -34,6 +41,9 @@
Math.max(Runtime.getRuntime().availableProcessors(), 2);
private static final int KEEP_ALIVE = 1;
+ /** Dedicated executor instances for work depending on other packages. */
+ private static final Map<String, ExecutorService> PACKAGE_EXECUTORS = new ConcurrentHashMap<>();
+
/**
* An {@link ThreadPoolExecutor} to be used with async task with no limit on the queue size.
*/
@@ -76,6 +86,18 @@
new LooperExecutor(createAndStartNewLooper("launcher-loader"));
/**
+ * Returns and caches a single thread executor for a given package.
+ *
+ * @param packageName Package associated with the executor.
+ */
+ public static ExecutorService getPackageExecutor(String packageName) {
+ return PACKAGE_EXECUTORS.computeIfAbsent(
+ packageName,
+ p -> newSingleThreadExecutor(
+ new SimpleThreadFactory(p, THREAD_PRIORITY_BACKGROUND)));
+ }
+
+ /**
* A simple ThreadFactory to set the thread name and priority when used with executors.
*/
public static class SimpleThreadFactory implements ThreadFactory {
diff --git a/src/com/android/launcher3/util/RotationUtils.java b/src/com/android/launcher3/util/RotationUtils.java
new file mode 100644
index 0000000..3414a3d
--- /dev/null
+++ b/src/com/android/launcher3/util/RotationUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Utility methods based on {@code frameworks/base/core/java/android/util/RotationUtils.java}
+ */
+public class RotationUtils {
+
+ /**
+ * Rotates an Rect according to the given rotation.
+ */
+ public static void rotateRect(Rect rect, int rotation) {
+ switch (rotation) {
+ case ROTATION_0:
+ return;
+ case ROTATION_90:
+ rect.set(rect.top, rect.right, rect.bottom, rect.left);
+ return;
+ case ROTATION_180:
+ rect.set(rect.right, rect.bottom, rect.left, rect.top);
+ return;
+ case ROTATION_270:
+ rect.set(rect.bottom, rect.left, rect.top, rect.right);
+ return;
+ default:
+ throw new IllegalArgumentException("unknown rotation: " + rotation);
+ }
+ }
+
+ /**
+ * Rotates an size according to the given rotation.
+ */
+ public static void rotateSize(Point size, int rotation) {
+ switch (rotation) {
+ case ROTATION_0:
+ case ROTATION_180:
+ return;
+ case ROTATION_90:
+ case ROTATION_270:
+ size.set(size.y, size.x);
+ return;
+ default:
+ throw new IllegalArgumentException("unknown rotation: " + rotation);
+ }
+ }
+
+ /** @return the rotation needed to rotate from oldRotation to newRotation. */
+ public static int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+}
diff --git a/src/com/android/launcher3/util/WindowBounds.java b/src/com/android/launcher3/util/WindowBounds.java
index c92770e..a15679a 100644
--- a/src/com/android/launcher3/util/WindowBounds.java
+++ b/src/com/android/launcher3/util/WindowBounds.java
@@ -33,19 +33,27 @@
public final Rect bounds;
public final Rect insets;
public final Point availableSize;
+ public final int rotationHint;
public WindowBounds(Rect bounds, Rect insets) {
+ this(bounds, insets, -1);
+ }
+
+ public WindowBounds(Rect bounds, Rect insets, int rotationHint) {
this.bounds = bounds;
this.insets = insets;
+ this.rotationHint = rotationHint;
availableSize = new Point(bounds.width() - insets.left - insets.right,
bounds.height() - insets.top - insets.bottom);
}
- public WindowBounds(int width, int height, int availableWidth, int availableHeight) {
+ public WindowBounds(int width, int height, int availableWidth, int availableHeight,
+ int rotationHint) {
this.bounds = new Rect(0, 0, width, height);
this.availableSize = new Point(availableWidth, availableHeight);
// We don't care about insets in this case
this.insets = new Rect(0, 0, width - availableWidth, height - availableHeight);
+ this.rotationHint = rotationHint;
}
@Override
diff --git a/src/com/android/launcher3/util/WindowManagerCompat.java b/src/com/android/launcher3/util/WindowManagerCompat.java
deleted file mode 100644
index 873a518..0000000
--- a/src/com/android/launcher3/util/WindowManagerCompat.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
-import static com.android.launcher3.Utilities.dpiFromPx;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.graphics.Rect;
-import android.os.Build;
-import android.util.ArraySet;
-import android.view.WindowInsets;
-import android.view.WindowInsets.Type;
-import android.view.WindowManager;
-import android.view.WindowMetrics;
-
-import com.android.launcher3.R;
-import com.android.launcher3.ResourceUtils;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DisplayController.PortraitSize;
-
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Utility class to estimate window manager values
- */
-@TargetApi(Build.VERSION_CODES.S)
-public class WindowManagerCompat {
-
- public static final int MIN_TABLET_WIDTH = 600;
- public static final int MIN_LARGE_TABLET_WIDTH = 720;
-
- /**
- * Returns a set of supported render sizes for a internal display.
- * This is a temporary workaround which assumes only nav-bar insets change across displays, and
- * is only used until we eventually get the real values
- * @param consumeTaskBar if true, it assumes that task bar is part of the app window
- * and ignores any insets because of task bar.
- */
- public static Set<WindowBounds> estimateDisplayProfiles(
- Context windowContext, PortraitSize size, int densityDpi, boolean consumeTaskBar) {
- if (!Utilities.ATLEAST_S) {
- return Collections.emptySet();
- }
- WindowInsets defaultInsets = windowContext.getSystemService(WindowManager.class)
- .getMaximumWindowMetrics().getWindowInsets();
- boolean isGesturalMode = ResourceUtils.getIntegerByName(
- "config_navBarInteractionMode",
- windowContext.getResources(),
- INVALID_RESOURCE_HANDLE) == 2;
-
- WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(defaultInsets);
- Set<WindowBounds> result = new ArraySet<>();
- int swDP = (int) dpiFromPx(size.width, densityDpi);
- boolean isTablet = swDP >= MIN_TABLET_WIDTH;
-
- final Insets portraitNav, landscapeNav;
- if (isTablet && !consumeTaskBar) {
- portraitNav = landscapeNav = Insets.of(0, 0, 0, windowContext.getResources()
- .getDimensionPixelSize(R.dimen.taskbar_size));
- } else if (!isGesturalMode) {
- portraitNav = Insets.of(0, 0, 0,
- getSystemResource(windowContext, "navigation_bar_height", swDP));
- landscapeNav = isTablet
- ? Insets.of(0, 0, 0, getSystemResource(windowContext,
- "navigation_bar_height_landscape", swDP))
- : Insets.of(0, 0, getSystemResource(windowContext,
- "navigation_bar_width", swDP), 0);
- } else {
- portraitNav = landscapeNav = Insets.of(0, 0, 0, 0);
- }
-
- result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
- new Rect(0, 0, size.width, size.height),
- insetsBuilder.setInsets(Type.navigationBars(), portraitNav).build())));
- result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
- new Rect(0, 0, size.height, size.width),
- insetsBuilder.setInsets(Type.navigationBars(), landscapeNav).build())));
- return result;
- }
-
- private static int getSystemResource(Context context, String key, int swDp) {
- int resourceId = context.getResources().getIdentifier(key, "dimen", "android");
- if (resourceId > 0) {
- Configuration conf = new Configuration();
- conf.smallestScreenWidthDp = swDp;
- return context.createConfigurationContext(conf)
- .getResources().getDimensionPixelSize(resourceId);
- }
- return 0;
- }
-}
diff --git a/src/com/android/launcher3/util/window/CachedDisplayInfo.java b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
new file mode 100644
index 0000000..06b9829
--- /dev/null
+++ b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util.window;
+
+import static com.android.launcher3.util.RotationUtils.deltaRotation;
+import static com.android.launcher3.util.RotationUtils.rotateRect;
+import static com.android.launcher3.util.RotationUtils.rotateSize;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Surface;
+
+import java.util.Objects;
+
+/**
+ * Properties on a display
+ */
+public class CachedDisplayInfo {
+
+ public final String id;
+ public final Point size;
+ public final int rotation;
+ public final Rect cutout;
+
+ public CachedDisplayInfo() {
+ this(new Point(0, 0), 0);
+ }
+
+ public CachedDisplayInfo(Point size, int rotation) {
+ this("", size, rotation, new Rect());
+ }
+
+ public CachedDisplayInfo(String id, Point size, int rotation, Rect cutout) {
+ this.id = id;
+ this.size = size;
+ this.rotation = rotation;
+ this.cutout = cutout;
+ }
+
+ /**
+ * Returns a CachedDisplayInfo where the properties are normalized to {@link Surface#ROTATION_0}
+ */
+ public CachedDisplayInfo normalize() {
+ if (rotation == Surface.ROTATION_0) {
+ return this;
+ }
+ Point newSize = new Point(size);
+ rotateSize(newSize, deltaRotation(rotation, Surface.ROTATION_0));
+
+ Rect newCutout = new Rect(cutout);
+ rotateRect(newCutout, deltaRotation(rotation, Surface.ROTATION_0));
+ return new CachedDisplayInfo(id, newSize, Surface.ROTATION_0, newCutout);
+ }
+
+ @Override
+ public String toString() {
+ return "CachedDisplayInfo{"
+ + "id='" + id + '\''
+ + ", size=" + size
+ + ", rotation=" + rotation
+ + ", cutout=" + cutout
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CachedDisplayInfo)) return false;
+ CachedDisplayInfo that = (CachedDisplayInfo) o;
+ return rotation == that.rotation && Objects.equals(id, that.id)
+ && Objects.equals(size, that.size) && Objects.equals(cutout,
+ that.cutout);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, size, rotation, cutout);
+ }
+}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
new file mode 100644
index 0000000..ba3d981
--- /dev/null
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util.window;
+
+import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
+import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
+import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
+import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
+import static com.android.launcher3.ResourceUtils.getDimenByName;
+import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+import static com.android.launcher3.util.RotationUtils.deltaRotation;
+import static com.android.launcher3.util.RotationUtils.rotateRect;
+import static com.android.launcher3.util.RotationUtils.rotateSize;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Build;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.Surface;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import com.android.launcher3.R;
+import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.WindowBounds;
+
+/**
+ * Utility class for mocking some window manager behaviours
+ */
+public class WindowManagerProxy implements ResourceBasedOverride {
+
+ public static final int MIN_TABLET_WIDTH = 600;
+ public static final int MIN_LARGE_TABLET_WIDTH = 720;
+
+ public static final MainThreadInitializedObject<WindowManagerProxy> INSTANCE =
+ forOverride(WindowManagerProxy.class, R.string.window_manager_proxy_class);
+
+ protected final boolean mTaskbarDrawnInProcess;
+
+ /**
+ * Creates a new instance of proxy, applying any overrides
+ */
+ public static WindowManagerProxy newInstance(Context context) {
+ return Overrides.getObject(WindowManagerProxy.class, context,
+ R.string.window_manager_proxy_class);
+ }
+
+ public WindowManagerProxy() {
+ this(false);
+ }
+
+ protected WindowManagerProxy(boolean taskbarDrawnInProcess) {
+ mTaskbarDrawnInProcess = taskbarDrawnInProcess;
+ }
+
+ /**
+ * Returns a map of normalized info of internal displays to estimated window bounds
+ * for that display
+ */
+ public ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> estimateInternalDisplayBounds(
+ Context context) {
+ Display[] displays = context.getSystemService(DisplayManager.class).getDisplays();
+ ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> result = new ArrayMap<>();
+ for (Display display : displays) {
+ if (isInternalDisplay(display)) {
+ CachedDisplayInfo info = getDisplayInfo(display).normalize();
+ WindowBounds[] bounds = estimateWindowBounds(context, info);
+ result.put(info.id, Pair.create(info, bounds));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the real bounds for the provided display after applying any insets normalization
+ */
+ @TargetApi(Build.VERSION_CODES.R)
+ public WindowBounds getRealBounds(Context windowContext,
+ Display display, CachedDisplayInfo info) {
+ if (!Utilities.ATLEAST_R) {
+ Point smallestSize = new Point();
+ Point largestSize = new Point();
+ display.getCurrentSizeRange(smallestSize, largestSize);
+
+ if (info.size.y > info.size.x) {
+ // Portrait
+ return new WindowBounds(info.size.x, info.size.y, smallestSize.x, largestSize.y,
+ info.rotation);
+ } else {
+ // Landscape
+ new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
+ info.rotation);
+ }
+ }
+
+ WindowMetrics wm = windowContext.getSystemService(WindowManager.class)
+ .getCurrentWindowMetrics();
+
+ Rect insets = new Rect();
+ normalizeWindowInsets(windowContext, wm.getWindowInsets(), insets);
+ return new WindowBounds(wm.getBounds(), insets, info.rotation);
+ }
+
+ /**
+ * Returns an updated insets, accounting for various Launcher UI specific overrides like taskbar
+ */
+ @TargetApi(Build.VERSION_CODES.R)
+ public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
+ Rect outInsets) {
+ if (!Utilities.ATLEAST_R || !mTaskbarDrawnInProcess) {
+ outInsets.set(oldInsets.getSystemWindowInsetLeft(), oldInsets.getSystemWindowInsetTop(),
+ oldInsets.getSystemWindowInsetRight(), oldInsets.getSystemWindowInsetBottom());
+ return oldInsets;
+ }
+
+ WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(oldInsets);
+ Insets navInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
+
+ Resources systemRes = context.getResources();
+ Configuration config = systemRes.getConfiguration();
+
+ boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
+ boolean isGesture = isGestureNav(context);
+
+ int bottomNav = isTablet
+ ? 0
+ : (config.screenHeightDp > config.screenWidthDp
+ ? getDimenByName(NAVBAR_HEIGHT, systemRes, 0)
+ : (isGesture
+ ? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0)
+ : 0));
+ Insets newNavInsets = Insets.of(navInsets.left, navInsets.top, navInsets.right, bottomNav);
+ insetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
+ insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
+
+ // Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
+ // would count towards it). This is used for the bottom protection in All Apps for example.
+ if (isGesture) {
+ Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
+ Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
+ oldTappableInsets.right, 0);
+ insetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
+ }
+
+ WindowInsets result = insetsBuilder.build();
+ Insets systemWindowInsets = result.getInsetsIgnoringVisibility(
+ WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
+ outInsets.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
+ systemWindowInsets.bottom);
+ return result;
+ }
+
+ /**
+ * Returns true if the display is an internal displays
+ */
+ protected boolean isInternalDisplay(Display display) {
+ return display.getDisplayId() == Display.DEFAULT_DISPLAY;
+ }
+
+ /**
+ * Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations
+ */
+ public WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo display) {
+ int densityDpi = context.getResources().getConfiguration().densityDpi;
+ int rotation = display.rotation;
+ Rect safeCutout = display.cutout;
+
+ int minSize = Math.min(display.size.x, display.size.y);
+ int swDp = (int) dpiFromPx(minSize, densityDpi);
+
+ Resources systemRes;
+ {
+ Configuration conf = new Configuration();
+ conf.smallestScreenWidthDp = swDp;
+ systemRes = context.createConfigurationContext(conf).getResources();
+ }
+
+ boolean isTablet = swDp >= MIN_TABLET_WIDTH;
+ boolean isTabletOrGesture = isTablet
+ || (Utilities.ATLEAST_R && isGestureNav(context));
+
+ int statusBarHeight = getDimenByName("status_bar_height", systemRes, 0);
+
+ int navBarHeightPortrait, navBarHeightLandscape, navbarWidthLandscape;
+
+ navBarHeightPortrait = isTablet
+ ? (mTaskbarDrawnInProcess
+ ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ : getDimenByName(NAVBAR_HEIGHT, systemRes, 0);
+
+ navBarHeightLandscape = isTablet
+ ? (mTaskbarDrawnInProcess
+ ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ : (isTabletOrGesture
+ ? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0) : 0);
+ navbarWidthLandscape = isTabletOrGesture
+ ? 0
+ : getDimenByName(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, systemRes, 0);
+
+ WindowBounds[] result = new WindowBounds[4];
+ Point tempSize = new Point();
+ for (int i = 0; i < 4; i++) {
+ int rotationChange = deltaRotation(rotation, i);
+ tempSize.set(display.size.x, display.size.y);
+ rotateSize(tempSize, rotationChange);
+ Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y);
+
+ int navBarHeight, navbarWidth;
+ if (tempSize.y > tempSize.x) {
+ navBarHeight = navBarHeightPortrait;
+ navbarWidth = 0;
+ } else {
+ navBarHeight = navBarHeightLandscape;
+ navbarWidth = navbarWidthLandscape;
+ }
+
+ Rect insets = new Rect(safeCutout);
+ rotateRect(insets, rotationChange);
+ insets.top = Math.max(insets.top, statusBarHeight);
+ insets.bottom = Math.max(insets.bottom, navBarHeight);
+
+ if (i == Surface.ROTATION_270 || i == Surface.ROTATION_180) {
+ // On reverse landscape (and in rare-case when the natural orientation of the
+ // device is landscape), navigation bar is on the right.
+ insets.left = Math.max(insets.left, navbarWidth);
+ } else {
+ insets.right = Math.max(insets.right, navbarWidth);
+ }
+ result[i] = new WindowBounds(bounds, insets, i);
+ }
+ return result;
+ }
+
+ protected boolean isGestureNav(Context context) {
+ return ResourceUtils.getIntegerByName("config_navBarInteractionMode",
+ context.getResources(), INVALID_RESOURCE_HANDLE) == 2;
+ }
+
+ /**
+ * Returns a CachedDisplayInfo initialized for the current display
+ */
+ @TargetApi(Build.VERSION_CODES.S)
+ public CachedDisplayInfo getDisplayInfo(Display display) {
+ int rotation = display.getRotation();
+
+ Point size = new Point();
+ display.getRealSize(size);
+
+ Rect cutoutRect = new Rect();
+ if (Utilities.ATLEAST_S) {
+ DisplayCutout cutout = display.getCutout();
+ if (cutout != null) {
+ cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
+ cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
+ }
+ }
+
+ return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutoutRect);
+ }
+
+ /**
+ * Returns a unique ID representing the display
+ */
+ protected String getDisplayId(Display display) {
+ return Integer.toString(display.getDisplayId());
+ }
+
+ /**
+ * Returns rotation of the display associated with the context.
+ */
+ public int getRotation(Context context) {
+ Display d = null;
+ if (Utilities.ATLEAST_R) {
+ try {
+ d = context.getDisplay();
+ } catch (UnsupportedOperationException e) {
+ // Ignore
+ }
+ }
+ return d == null ? DisplayController.INSTANCE.get(context).getInfo().rotation
+ : d.getRotation();
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index 7f54d6d..19c28b4 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -159,7 +159,8 @@
return;
}
View icon = mLauncher.getFirstMatchForAppClose(-1,
- mContract.componentName.getPackageName(), mContract.user);
+ mContract.componentName.getPackageName(), mContract.user,
+ false /* supportsAllAppsState */);
boolean iconChanged = mIcon != icon;
if (iconChanged) {
diff --git a/src_build_config/com/android/launcher3/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java
index 49aadf6..9a81d3f 100644
--- a/src_build_config/com/android/launcher3/BuildConfig.java
+++ b/src_build_config/com/android/launcher3/BuildConfig.java
@@ -17,6 +17,11 @@
package com.android.launcher3;
public final class BuildConfig {
- public static final String APPLICATION_ID = "com.android.launcher3";
- public static final boolean DEBUG = false;
+ public static final String APPLICATION_ID = "com.android.launcher3";
+ public static final boolean DEBUG = false;
+ /**
+ * Flag to state if the QSB is on the first screen and placed on the top,
+ * this can be overwritten in other launchers with a different value, if needed.
+ */
+ public static final boolean QSB_ON_FIRST_SCREEN = true;
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index 81e3f98..6715749 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -19,7 +19,6 @@
import android.app.Person;
import android.content.Context;
import android.content.pm.ShortcutInfo;
-import android.view.Display;
import com.android.launcher3.Utilities;
@@ -32,20 +31,6 @@
}
/**
- * Returns true if the display is an internal displays
- */
- public static boolean isInternalDisplay(Display display) {
- return display.getDisplayId() == Display.DEFAULT_DISPLAY;
- }
-
- /**
- * Returns a unique ID representing the display
- */
- public static String getUniqueId(Display display) {
- return Integer.toString(display.getDisplayId());
- }
-
- /**
* Returns the minimum space that should be left empty at the end of hotseat
*/
public static int getHotseatEndOffset(Context context) {
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index b4cd773..9cc3aed 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -94,7 +94,6 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
@@ -138,6 +137,7 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.android.launcher3.intent.action.test_shortcut"/>
diff --git a/tests/src/com/android/launcher3/DeviceProfileTest.kt b/tests/src/com/android/launcher3/DeviceProfileTest.kt
index 60046a0..75ad21d 100644
--- a/tests/src/com/android/launcher3/DeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileTest.kt
@@ -139,7 +139,7 @@
else
Pair(1440, 3120)
- windowBounds = WindowBounds(x, y, x, y - 100)
+ windowBounds = WindowBounds(x, y, x, y - 100, 0)
`when`(info.isTablet(any())).thenReturn(false)
`when`(info.isLargeTablet(any())).thenReturn(false)
@@ -153,7 +153,7 @@
else
Pair(1600, 2560)
- windowBounds = WindowBounds(x, y, x, y - 100)
+ windowBounds = WindowBounds(x, y, x, y - 100, 0)
`when`(info.isTablet(any())).thenReturn(true)
`when`(info.isLargeTablet(any())).thenReturn(false)
@@ -167,7 +167,7 @@
else
Pair(1600, 2560)
- windowBounds = WindowBounds(x, y, x, y - 100)
+ windowBounds = WindowBounds(x, y, x, y - 100, 0)
`when`(info.isTablet(any())).thenReturn(true)
`when`(info.isLargeTablet(any())).thenReturn(true)
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index c99c4f1..136f115 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -567,6 +567,7 @@
ordinal == TestProtocol.OVERVIEW_STATE_ORDINAL);
break;
}
+ case TASKBAR_ALL_APPS:
case LAUNCHED_APP: {
assertTrue("Launcher is resumed in state: " + expectedContainerType,
!isResumed);
@@ -580,9 +581,10 @@
}
} else {
assertTrue(
- "Container type is not LAUNCHED_APP or FALLBACK_OVERVIEW: "
- + expectedContainerType,
+ "Container type is not LAUNCHED_APP, TASKBAR_ALL_APPS "
+ + "or FALLBACK_OVERVIEW: " + expectedContainerType,
expectedContainerType == ContainerType.LAUNCHED_APP
+ || expectedContainerType == ContainerType.TASKBAR_ALL_APPS
|| expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
}
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 61ec8bd..73e9823 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -109,7 +109,7 @@
launcher -> assertNotNull("Launcher internal state didn't switch to Showing Menu",
launcher.getOptionsPopup()));
// Check that pressHome works when the menu is shown.
- mLauncher.pressHome();
+ mLauncher.goHome();
}
@Test
@@ -121,7 +121,7 @@
} finally {
allApps.unfreeze();
}
- mLauncher.pressHome();
+ mLauncher.goHome();
}
public static void runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
@@ -273,7 +273,7 @@
executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
getWidgetsScroll(launcher) < flingForwardY));
- mLauncher.pressHome();
+ mLauncher.goHome();
waitForLauncherCondition("Widgets were not closed",
launcher -> getWidgetsView(launcher) == null);
}
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 0c1f0cd..9fb52fc 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -169,7 +169,7 @@
}
// Go back to home
- mLauncher.pressHome();
+ mLauncher.goHome();
Wait.atMost("", new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT,
mLauncher);
}
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 59966ee..3324959 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -67,6 +67,7 @@
import com.android.launcher3.testing.TestInformationProvider;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import org.mockito.ArgumentCaptor;
@@ -501,7 +502,7 @@
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
- ItemInstallQueue.INSTANCE);
+ ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
mPm = spy(getBaseContext().getPackageManager());
mDbDir = new File(getCacheDir(), UUID.randomUUID().toString());
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 3658f41..bfb115d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -74,7 +74,7 @@
LauncherInstrumentation.log("hasClickableIcon: icon has insufficient height");
return false;
}
- if (iconCenterInSearchBox(allAppsContainer, icon)) {
+ if (hasSearchBox() && iconCenterInSearchBox(allAppsContainer, icon)) {
LauncherInstrumentation.log("hasClickableIcon: icon center is under search box");
return false;
}
@@ -107,7 +107,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
- final UiObject2 searchBox = getSearchBox(allAppsContainer);
+ final UiObject2 searchBox = hasSearchBox() ? getSearchBox(allAppsContainer) : null;
int deviceHeight = mLauncher.getRealDisplaySize().y;
int bottomGestureStartOnScreen = mLauncher.getBottomGestureStartOnScreen();
@@ -128,8 +128,10 @@
mLauncher.getVisibleBounds(icon).top
< bottomGestureStartOnScreen)
.collect(Collectors.toList()),
- mLauncher.getVisibleBounds(searchBox).bottom
- - mLauncher.getVisibleBounds(allAppsContainer).top);
+ hasSearchBox()
+ ? mLauncher.getVisibleBounds(searchBox).bottom
+ - mLauncher.getVisibleBounds(allAppsContainer).top
+ : 0);
verifyActiveContainer();
final int newScroll = getAllAppsScroll();
mLauncher.assertTrue(
@@ -173,18 +175,21 @@
return appIcon;
}
+ @NonNull
protected abstract AppIcon createAppIcon(UiObject2 icon);
+ protected abstract boolean hasSearchBox();
+
private void scrollBackToBeginning() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to scroll back in all apps")) {
LauncherInstrumentation.log("Scrolling to the beginning");
final UiObject2 allAppsContainer = verifyActiveContainer();
- final UiObject2 searchBox = getSearchBox(allAppsContainer);
+ final UiObject2 searchBox = hasSearchBox() ? getSearchBox(allAppsContainer) : null;
int attempts = 0;
- final Rect margins =
- new Rect(0, mLauncher.getVisibleBounds(searchBox).bottom + 1, 0, 5);
+ final Rect margins = new Rect(
+ 0, hasSearchBox() ? mLauncher.getVisibleBounds(searchBox).bottom + 1 : 0, 0, 5);
for (int scroll = getAllAppsScroll();
scroll != 0;
@@ -196,7 +201,11 @@
++attempts <= MAX_SCROLL_ATTEMPTS);
mLauncher.scroll(
- allAppsContainer, Direction.UP, margins, 12, false);
+ allAppsContainer,
+ Direction.UP,
+ margins,
+ /* steps= */ 12,
+ /* slowDown= */ false);
}
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
@@ -225,7 +234,11 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
mLauncher.scroll(
- allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10, false);
+ allAppsContainer,
+ Direction.DOWN,
+ new Rect(0, 0, 0, mHeight / 2),
+ /* steps= */ 10,
+ /* slowDown= */ false);
verifyActiveContainer();
}
}
@@ -240,7 +253,11 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
mLauncher.scroll(
- allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10, false);
+ allAppsContainer,
+ Direction.UP,
+ new Rect(0, mHeight / 2, 0, 0),
+ /* steps= */ 10,
+ /*slowDown= */ false);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java
new file mode 100644
index 0000000..5164025
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on AllApps opened from the Taskbar.
+ */
+public class AllAppsFromTaskbar extends AllApps {
+
+ AllAppsFromTaskbar(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.TASKBAR_ALL_APPS;
+ }
+
+ @NonNull
+ @Override
+ public TaskbarAppIcon getAppIcon(String appName) {
+ return (TaskbarAppIcon) super.getAppIcon(appName);
+ }
+
+ @NonNull
+ @Override
+ protected TaskbarAppIcon createAppIcon(UiObject2 icon) {
+ return new TaskbarAppIcon(mLauncher, icon);
+ }
+
+ @Override
+ protected boolean hasSearchBox() {
+ return false;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index bef242c..e28f0af 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -51,7 +51,7 @@
public AppIconMenu openMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
return createMenu(mLauncher.clickAndGet(
- mObject, "popup_container", getLongClickEvent()));
+ mObject, /* resName= */ "popup_container", getLongClickEvent()));
}
}
@@ -61,7 +61,7 @@
public AppIconMenu openDeepShortcutMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
return createMenu(mLauncher.clickAndGet(
- mObject, "deep_shortcuts_container", getLongClickEvent()));
+ mObject, /* resName= */ "deep_shortcuts_container", getLongClickEvent()));
}
}
@@ -73,8 +73,8 @@
}
@Override
- protected String getLongPressIndicator() {
- return "popup_container";
+ protected void waitForLongPressConfirmation() {
+ mLauncher.waitForLauncherObject("popup_container");
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index a6a1531..5cf5aba 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -41,8 +41,8 @@
}
@Override
- protected String getLongPressIndicator() {
- return "drop_target_bar";
+ protected void waitForLongPressConfirmation() {
+ mLauncher.waitForLauncherObject("drop_target_bar");
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 2e00d59..c275f3b 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -35,8 +35,14 @@
return (AllAppsAppIcon) super.getAppIcon(appName);
}
+ @NonNull
@Override
protected HomeAppIcon createAppIcon(UiObject2 icon) {
return new AllAppsAppIcon(mLauncher, icon);
}
+
+ @Override
+ protected boolean hasSearchBox() {
+ return true;
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
index baabe12..71d8ba9 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
@@ -51,8 +51,7 @@
() -> {
final Rect bounds = target.getDropLocationBounds();
return new Point(bounds.centerX(), bounds.centerY());
- },
- getLongPressIndicator());
+ });
FolderIcon result = target.getTargetFolder(dropBounds);
mLauncher.assertTrue("Can't find the target folder.", result != null);
return result;
@@ -115,8 +114,12 @@
String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))
) {
final Supplier<Point> dest = () -> Workspace.getCellCenter(mLauncher, cellX, cellY);
- Workspace.dragIconToWorkspace(mLauncher, this, dest, getLongPressIndicator(),
- () -> addExpectedEventsForLongClick(), null);
+ Workspace.dragIconToWorkspace(
+ mLauncher,
+ /* launchable= */ this,
+ dest,
+ () -> addExpectedEventsForLongClick(),
+ /*expectDropEvents= */ null);
try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
WorkspaceAppIcon appIcon =
(WorkspaceAppIcon) mLauncher.getWorkspace().getWorkspaceAppIcon(mAppName);
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index a28eac6..45a0196 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -97,8 +97,7 @@
return new LaunchedAppState(mLauncher);
}
- Point startDrag(long downTime, String longPressIndicator,
- Runnable expectLongClickEvents, boolean runToSpringLoadedState) {
+ Point startDrag(long downTime, Runnable expectLongClickEvents, boolean runToSpringLoadedState) {
final Point iconCenter = getObject().getVisibleCenter();
final Point dragStartCenter = new Point(iconCenter.x,
iconCenter.y - getStartDragThreshold());
@@ -108,7 +107,6 @@
downTime,
iconCenter,
dragStartCenter,
- longPressIndicator,
expectLongClickEvents),
SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
} else {
@@ -116,7 +114,6 @@
downTime,
iconCenter,
dragStartCenter,
- longPressIndicator,
expectLongClickEvents);
}
@@ -125,21 +122,43 @@
}
/**
+ * Waits for a confirmation that a long press has successfully been triggered.
+ *
+ * This method waits for a view to either appear or disappear to confirm that the long press
+ * has been triggered and fails if no confirmation is received before the default timeout.
+ */
+ protected abstract void waitForLongPressConfirmation();
+
+ /**
* Drags this Launchable a short distance before starting a full drag.
*
* This is necessary for shortcuts, which require being dragged beyond a threshold to close
* their container and start drag callbacks.
*/
- private void movePointerForStartDrag(long downTime, Point iconCenter, Point dragStartCenter,
- String longPressIndicator, Runnable expectLongClickEvents) {
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
- iconCenter, LauncherInstrumentation.GestureScope.INSIDE);
+ private void movePointerForStartDrag(
+ long downTime,
+ Point iconCenter,
+ Point dragStartCenter,
+ Runnable expectLongClickEvents) {
+ mLauncher.sendPointer(
+ downTime,
+ downTime,
+ MotionEvent.ACTION_DOWN,
+ iconCenter,
+ LauncherInstrumentation.GestureScope.INSIDE);
LauncherInstrumentation.log("movePointerForStartDrag: sent down");
expectLongClickEvents.run();
- mLauncher.waitForLauncherObject(longPressIndicator);
+ waitForLongPressConfirmation();
LauncherInstrumentation.log("movePointerForStartDrag: indicator");
- mLauncher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false,
- downTime, downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
+ mLauncher.movePointer(
+ iconCenter,
+ dragStartCenter,
+ DEFAULT_DRAG_STEPS,
+ /* isDecelerating= */ false,
+ downTime,
+ downTime,
+ /* slowDown= */ true,
+ LauncherInstrumentation.GestureScope.INSIDE);
}
private int getStartDragThreshold() {
@@ -148,6 +167,4 @@
}
protected abstract void addExpectedEventsForLongClick();
-
- protected abstract String getLongPressIndicator();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 3f1be80..2033a42 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -16,11 +16,27 @@
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
+import static com.android.launcher3.testing.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
+import static com.android.launcher3.testing.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+
+import androidx.test.uiautomator.By;
+
+import com.android.launcher3.testing.TestProtocol;
+
/**
* Background state operations specific to when an app has been launched.
*/
public final class LaunchedAppState extends Background {
+ // More drag steps than Launchables to give the window manager time to register the drag.
+ private static final int DEFAULT_DRAG_STEPS = 35;
+
LaunchedAppState(LauncherInstrumentation launcher) {
super(launcher);
}
@@ -29,4 +45,126 @@
protected LauncherInstrumentation.ContainerType getContainerType() {
return LauncherInstrumentation.ContainerType.LAUNCHED_APP;
}
+
+ /**
+ * Returns the taskbar.
+ *
+ * The taskbar must already be visible when calling this method.
+ */
+ public Taskbar getTaskbar() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get the taskbar")) {
+ mLauncher.waitForLauncherObject("taskbar_view");
+
+ return new Taskbar(mLauncher);
+ }
+ }
+
+ /**
+ * Returns the Taskbar in a visible state.
+ *
+ * The taskbar must already be hidden when calling this method.
+ */
+ public Taskbar showTaskbar() {
+ mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "want to show the taskbar")) {
+ mLauncher.waitUntilLauncherObjectGone("taskbar_view");
+
+ final long downTime = SystemClock.uptimeMillis();
+ final int unstashTargetY = mLauncher.getRealDisplaySize().y
+ - (mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_HEIGHT)
+ .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) / 2);
+ final Point unstashTarget = new Point(
+ mLauncher.getRealDisplaySize().x / 2, unstashTargetY);
+
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget,
+ LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
+ LauncherInstrumentation.log("showTaskbar: sent down");
+
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
+ mLauncher.waitForLauncherObject("taskbar_view");
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
+ LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
+
+ return new Taskbar(mLauncher);
+ }
+ } finally {
+ mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
+ }
+ }
+
+ static void dragToSplitscreen(
+ LauncherInstrumentation launcher, Launchable launchable, String expectedNewPackageName,
+ String expectedExistingPackageName) {
+ try (LauncherInstrumentation.Closable c1 = launcher.addContextLayer(
+ "want to drag taskbar item to splitscreen")) {
+ final Point displaySize = launcher.getRealDisplaySize();
+ final Point endPoint = new Point(displaySize.x / 4, 3 * displaySize.y / 4);
+ final long downTime = SystemClock.uptimeMillis();
+ // Use mObject before starting drag since the system drag and drop moves the original
+ // view.
+ Point itemVisibleCenter = launchable.mObject.getVisibleCenter();
+ Rect itemVisibleBounds = launcher.getVisibleBounds(launchable.mObject);
+ String itemLabel = launchable.mObject.getText();
+
+ Point dragStart = launchable.startDrag(
+ downTime,
+ launchable::addExpectedEventsForLongClick,
+ /* runToSpringLoadedState= */ false);
+
+ try (LauncherInstrumentation.Closable c2 = launcher.addContextLayer(
+ "started item drag")) {
+ launcher.movePointer(
+ dragStart,
+ endPoint,
+ DEFAULT_DRAG_STEPS,
+ /* isDecelerating= */ true,
+ downTime,
+ SystemClock.uptimeMillis(),
+ /* slowDown= */ false,
+ LauncherInstrumentation.GestureScope.INSIDE);
+
+ try (LauncherInstrumentation.Closable c3 = launcher.addContextLayer(
+ "moved pointer to drop point")) {
+ dropDraggedItem(
+ launcher,
+ launchable,
+ expectedNewPackageName,
+ endPoint, downTime,
+ itemVisibleCenter,
+ itemVisibleBounds,
+ itemLabel,
+ expectedExistingPackageName);
+ }
+ }
+ }
+ }
+
+ private static void dropDraggedItem(
+ LauncherInstrumentation launcher, Launchable launchable, String expectedNewPackageName,
+ Point endPoint, long downTime, Point itemVisibleCenter, Rect itemVisibleBounds,
+ String itemLabel, String expectedExistingPackageName) {
+ LauncherInstrumentation.log("SplitscreenDragSource.dragToSplitscreen before drop "
+ + itemVisibleCenter + " in " + itemVisibleBounds);
+
+ launchable.executeAndWaitForWindowChange(() -> {
+ launcher.sendPointer(
+ downTime,
+ SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP,
+ endPoint,
+ LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER);
+ LauncherInstrumentation.log("SplitscreenDragSource.dragToSplitscreen: after "
+ + "drop");
+ }, itemLabel, "dropping taskbar item");
+
+ try (LauncherInstrumentation.Closable c = launcher.addContextLayer("dropped item")) {
+ launchable.assertAppLaunched(itemLabel, By.pkg(expectedNewPackageName));
+ launcher.checkPackagesVisible(
+ new String[] {expectedNewPackageName, expectedExistingPackageName});
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index bbfbc55..8e0eb7b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -84,6 +84,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@@ -123,7 +124,8 @@
// Types for launcher containers that the user is interacting with. "Background" is a
// pseudo-container corresponding to inactive launcher covered by another app.
public enum ContainerType {
- WORKSPACE, HOME_ALL_APPS, OVERVIEW, WIDGETS, FALLBACK_OVERVIEW, LAUNCHED_APP
+ WORKSPACE, HOME_ALL_APPS, OVERVIEW, WIDGETS, FALLBACK_OVERVIEW, LAUNCHED_APP,
+ TASKBAR_ALL_APPS
}
public enum NavigationModel {ZERO_BUTTON, THREE_BUTTON}
@@ -167,6 +169,7 @@
private static final String OVERVIEW_RES_ID = "overview_panel";
private static final String WIDGETS_RES_ID = "primary_widgets_list_view";
private static final String CONTEXT_MENU_RES_ID = "popup_container";
+ private static final String TASKBAR_RES_ID = "taskbar_view";
public static final int WAIT_TIME_MS = 60000;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
private static final String ANDROID_PACKAGE = "android";
@@ -500,6 +503,16 @@
}
}
+ void checkPackagesVisible(String[] expectedVisiblePackages) {
+ Set<String> actualVisiblePackages =
+ getVisiblePackagesStream().collect(Collectors.toSet());
+
+ for (String expectedVisible : expectedVisiblePackages) {
+ assertTrue("Expected package not visible: " + expectedVisible,
+ actualVisiblePackages.contains(expectedVisible));
+ }
+ }
+
private String getVisiblePackages() {
final String apps = getVisiblePackagesStream().collect(Collectors.joining(", "));
return !apps.isEmpty()
@@ -722,27 +735,41 @@
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+
return waitForLauncherObject(WORKSPACE_RES_ID);
}
case WIDGETS: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+
return waitForLauncherObject(WIDGETS_RES_ID);
}
+ case TASKBAR_ALL_APPS:
case HOME_ALL_APPS: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+
return waitForLauncherObject(APPS_RES_ID);
}
case OVERVIEW: {
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+
return waitForLauncherObject(OVERVIEW_RES_ID);
}
case FALLBACK_OVERVIEW: {
+ waitUntilLauncherObjectGone(APPS_RES_ID);
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+
return waitForFallbackLauncherObject(OVERVIEW_RES_ID);
}
case LAUNCHED_APP: {
@@ -750,6 +777,12 @@
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+
+ if (isTablet() && !isFallbackOverview()) {
+ waitForLauncherObject(TASKBAR_RES_ID);
+ } else {
+ waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+ }
return null;
}
default:
@@ -844,11 +877,22 @@
}
/**
+ * @deprecated use goHome().
* Presses nav bar home button.
*
* @return the Workspace object.
*/
+ @Deprecated
public Workspace pressHome() {
+ return goHome();
+ }
+
+ /**
+ * Presses nav bar home button.
+ *
+ * @return the Workspace object.
+ */
+ public Workspace goHome() {
try (LauncherInstrumentation.Closable e = eventsCheck();
LauncherInstrumentation.Closable c = addContextLayer("want to switch to home")) {
waitForLauncherInitialized();
@@ -863,8 +907,13 @@
setForcePauseTimeout(FORCE_PAUSE_TIMEOUT_MS);
final Point displaySize = getRealDisplaySize();
+ // The swipe up to home gesture starts from inside the launcher when the user is
+ // already home. Otherwise, the gesture can start inside the launcher process if the
+ // taskbar is visible.
boolean gestureStartFromLauncher = isTablet()
- ? !isLauncher3() || hasLauncherObject(WORKSPACE_RES_ID)
+ ? !isLauncher3()
+ || hasLauncherObject(WORKSPACE_RES_ID)
+ || hasLauncherObject(TASKBAR_RES_ID)
: isLauncherVisible();
// CLose floating views before going back to home.
@@ -1301,9 +1350,7 @@
}
void scrollToLastVisibleRow(
- UiObject2 container,
- Collection<UiObject2> items,
- int topPaddingInContainer) {
+ UiObject2 container, Collection<UiObject2> items, int topPaddingInContainer) {
final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
Integer.compare(getVisibleBounds(i1).top, getVisibleBounds(i2).top));
@@ -1326,8 +1373,8 @@
containerRect.height() - distance - bottomGestureMarginInContainer,
0,
bottomGestureMarginInContainer),
- 10,
- true);
+ /* steps= */ 10,
+ /* slowDown= */ true);
}
void scrollLeftByDistance(UiObject2 container, int distance) {
@@ -1650,6 +1697,29 @@
getTestInfo(TestProtocol.REQUEST_CLEAR_DATA);
}
+ /**
+ * Reloads the workspace with a test layout that includes the Test Activity app icon on the
+ * hotseat.
+ */
+ public void useTestWorkspaceLayoutOnReload() {
+ getTestInfo(TestProtocol.REQUEST_USE_TEST_WORKSPACE_LAYOUT);
+ }
+
+ /** Reloads the workspace with the default layout defined by the user's grid size selection. */
+ public void useDefaultWorkspaceLayoutOnReload() {
+ getTestInfo(TestProtocol.REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT);
+ }
+
+ /** Shows the taskbar if it is hidden, otherwise does nothing. */
+ public void showTaskbarIfHidden() {
+ getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED);
+ }
+
+ public List<String> getHotseatIconNames() {
+ return getTestInfo(TestProtocol.REQUEST_HOTSEAT_ICON_NAMES)
+ .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
private String[] getActivities() {
return getTestInfo(TestProtocol.REQUEST_GET_ACTIVITIES)
.getStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD);
diff --git a/tests/tapl/com/android/launcher3/tapl/SplitscreenDragSource.java b/tests/tapl/com/android/launcher3/tapl/SplitscreenDragSource.java
new file mode 100644
index 0000000..ce1c3c0
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SplitscreenDragSource.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+/** Launchable that can serve as a source for dragging and dropping to splitscreen. */
+interface SplitscreenDragSource {
+
+ /**
+ * Drags this app icon to the left (landscape) or bottom (portrait) of the screen, launching it
+ * in splitscreen.
+ *
+ * @param expectedNewPackageName package name of the app being dragged
+ * @param expectedExistingPackageName package name of the already-launched app
+ */
+ default void dragToSplitscreen(
+ String expectedNewPackageName, String expectedExistingPackageName) {
+ Launchable launchable = getLaunchable();
+ LauncherInstrumentation launcher = launchable.mLauncher;
+ try (LauncherInstrumentation.Closable e = launcher.eventsCheck()) {
+ LaunchedAppState.dragToSplitscreen(
+ launcher, launchable, expectedNewPackageName, expectedExistingPackageName);
+ }
+ }
+
+ Launchable getLaunchable();
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
new file mode 100644
index 0000000..b5a08c3
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import static com.android.launcher3.testing.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
+import static com.android.launcher3.testing.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
+
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Operations on the Taskbar from LaunchedApp.
+ */
+public final class Taskbar {
+
+ private final LauncherInstrumentation mLauncher;
+
+ Taskbar(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ }
+
+ /**
+ * Returns an app icon with the given name. This fails if the icon is not found.
+ */
+ @NonNull
+ public TaskbarAppIcon getAppIcon(String appName) {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get a taskbar icon")) {
+ return new TaskbarAppIcon(mLauncher, mLauncher.waitForObjectInContainer(
+ mLauncher.waitForLauncherObject("taskbar_view"),
+ AppIcon.getAppIconSelector(appName, mLauncher)));
+ }
+ }
+
+ /**
+ * Hides this taskbar.
+ *
+ * The taskbar must already be visible when calling this method.
+ */
+ public void hide() {
+ mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to hide the taskbar");
+ LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ mLauncher.waitForLauncherObject("taskbar_view");
+
+ final long downTime = SystemClock.uptimeMillis();
+ Point stashTarget = new Point(
+ mLauncher.getRealDisplaySize().x - 1, mLauncher.getRealDisplaySize().y - 1);
+
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, stashTarget,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.log("hideTaskbar: sent down");
+
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
+ mLauncher.waitUntilLauncherObjectGone("taskbar_view");
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ }
+ } finally {
+ mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
+ }
+ }
+
+ /**
+ * Opens the Taskbar all apps page.
+ */
+ public AllAppsFromTaskbar openAllApps() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to open taskbar all apps");
+ LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+
+ mLauncher.clickLauncherObject(mLauncher.waitForObjectInContainer(
+ mLauncher.waitForLauncherObject("taskbar_view"), getAllAppsButtonSelector()));
+
+ return new AllAppsFromTaskbar(mLauncher);
+ }
+ }
+
+ /** Returns a list of app icon names on the Taskbar */
+ public List<String> getIconNames() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get all taskbar icons")) {
+ return mLauncher.waitForObjectsInContainer(
+ mLauncher.waitForLauncherObject("taskbar_view"),
+ AppIcon.getAnyAppIconSelector())
+ .stream()
+ .map(UiObject2::getText)
+ .filter(text -> !TextUtils.isEmpty(text)) // Filter out the all apps button
+ .collect(Collectors.toList());
+ }
+ }
+
+ private static BySelector getAllAppsButtonSelector() {
+ // Look for an icon with no text
+ return By.clazz(TextView.class).text("");
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
new file mode 100644
index 0000000..099acd4
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+import java.util.regex.Pattern;
+
+/**
+ * App icon specifically on the Taskbar.
+ */
+public final class TaskbarAppIcon extends AppIcon implements SplitscreenDragSource {
+
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onTaskbarItemLongClick");
+
+ TaskbarAppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+ super(launcher, icon);
+ }
+
+ @Override
+ protected Pattern getLongClickEvent() {
+ return LONG_CLICK_EVENT;
+ }
+
+ @Override
+ public TaskbarAppIconMenu openDeepShortcutMenu() {
+ return (TaskbarAppIconMenu) super.openDeepShortcutMenu();
+ }
+
+ @Override
+ protected TaskbarAppIconMenu createMenu(UiObject2 menu) {
+ return new TaskbarAppIconMenu(mLauncher, menu);
+ }
+
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenu.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenu.java
new file mode 100644
index 0000000..1f137c5
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenu.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Context menu of a Taskbar app icon.
+ */
+public final class TaskbarAppIconMenu extends AppIconMenu {
+
+ TaskbarAppIconMenu(LauncherInstrumentation launcher, UiObject2 deepShortcutsContainer) {
+ super(launcher, deepShortcutsContainer);
+ }
+
+ @Override
+ public TaskbarAppIconMenuItem getMenuItem(String shortcutText) {
+ return (TaskbarAppIconMenuItem) super.getMenuItem(shortcutText);
+ }
+
+ @Override
+ protected TaskbarAppIconMenuItem createMenuItem(UiObject2 menuItem) {
+ return new TaskbarAppIconMenuItem(mLauncher, menuItem);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenuItem.java
new file mode 100644
index 0000000..69a8a08
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIconMenuItem.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.testing.TestProtocol;
+
+import java.util.regex.Pattern;
+
+/**
+ * Menu item in a Taskbar app icon menu.
+ */
+public final class TaskbarAppIconMenuItem extends AppIconMenuItem implements SplitscreenDragSource {
+
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onTaskbarItemLongClick");
+
+ TaskbarAppIconMenuItem(
+ LauncherInstrumentation launcher, UiObject2 shortcut) {
+ super(launcher, shortcut);
+ }
+
+ @Override
+ protected void addExpectedEventsForLongClick() {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
+ }
+
+ @Override
+ protected void waitForLongPressConfirmation() {
+ // On long-press, the popup container closes and the system drag-and-drop begins. This
+ // only leaves launcher views that were previously visible.
+ mLauncher.waitUntilLauncherObjectGone("popup_container");
+ }
+
+ @Override
+ protected String launchableType() {
+ return "taskbar app icon menu item";
+ }
+
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index 73e9830..2346249 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -39,8 +39,8 @@
}
@Override
- protected String getLongPressIndicator() {
- return "drop_target_bar";
+ protected void waitForLongPressConfirmation() {
+ mLauncher.waitForLauncherObject("drop_target_bar");
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 3bc5389..fee4490 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -205,7 +205,6 @@
mLauncher,
homeAppIcon,
new Point(targetX, mLauncher.getVisibleBounds(workspace).centerY()),
- "popup_container",
false,
false,
() -> mLauncher.expectEvent(
@@ -244,11 +243,11 @@
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"removing app icon from workspace")) {
dragIconToWorkspace(
- mLauncher, homeAppIcon,
+ mLauncher,
+ homeAppIcon,
() -> getDropPointFromDropTargetBar(mLauncher, DELETE_TARGET_TEXT_ID),
- homeAppIcon.getLongPressIndicator(),
() -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
- null);
+ /* expectDropEvents= */ null);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"dragged the app to the drop bar")) {
@@ -274,11 +273,11 @@
try (LauncherInstrumentation.Closable c = launcher.addContextLayer(
"uninstalling app icon")) {
dragIconToWorkspace(
- launcher, homeAppIcon,
+ launcher,
+ homeAppIcon,
() -> getDropPointFromDropTargetBar(launcher, UNINSTALL_TARGET_TEXT_ID),
- homeAppIcon.getLongPressIndicator(),
expectLongClickEvents,
- null);
+ /* expectDropEvents= */null);
launcher.waitUntilLauncherObjectGone(DROP_BAR_RES_ID);
@@ -345,15 +344,15 @@
}
static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
- Point dest, String longPressIndicator, boolean startsActivity, boolean isWidgetShortcut,
+ Point dest, boolean startsActivity, boolean isWidgetShortcut,
Runnable expectLongClickEvents) {
Runnable expectDropEvents = null;
if (startsActivity || isWidgetShortcut) {
expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_START);
}
- dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator,
- expectLongClickEvents, expectDropEvents);
+ dragIconToWorkspace(
+ launcher, launchable, () -> dest, expectLongClickEvents, expectDropEvents);
}
/**
@@ -361,22 +360,27 @@
* (There is no slow down time before drop event)
* This function expects the launchable is inside the workspace and there is no drop event.
*/
- static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
- Supplier<Point> destSupplier, String longPressIndicator) {
- dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator,
- () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null);
+ static void dragIconToWorkspace(
+ LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> destSupplier) {
+ dragIconToWorkspace(
+ launcher,
+ launchable,
+ destSupplier,
+ () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
+ /* expectDropEvents= */ null);
}
static void dragIconToWorkspace(
- LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest,
- String longPressIndicator, Runnable expectLongClickEvents,
+ LauncherInstrumentation launcher,
+ Launchable launchable,
+ Supplier<Point> dest,
+ Runnable expectLongClickEvents,
@Nullable Runnable expectDropEvents) {
try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
"want to drag icon to workspace")) {
final long downTime = SystemClock.uptimeMillis();
Point dragStart = launchable.startDrag(
downTime,
- longPressIndicator,
expectLongClickEvents,
/* runToSpringLoadedState= */ true);
Point targetDest = dest.get();
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index 93c2213..d8d4420 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -41,7 +41,6 @@
? launchableCenter.x - width / 2
: launchableCenter.x + width / 2,
displaySize.y / 2),
- launchable.getLongPressIndicator(),
startsActivity,
isWidgetShortcut,
launchable::addExpectedEventsForLongClick);