Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/Android.bp b/Android.bp
index b205d0c..a0187e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,6 +69,15 @@
],
}
+// Source code for quickstep dagger
+filegroup {
+ name: "launcher-quickstep-dagger",
+ srcs: [
+ "quickstep/dagger/**/*.java",
+ "quickstep/dagger/**/*.kt",
+ ],
+}
+
// Source code for quickstep build with compose enabled, on top of launcher-src
filegroup {
name: "launcher-quickstep-compose-enabled-src",
@@ -221,7 +230,7 @@
android_library {
name: "launcher-aosp-tapl",
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
static_libs: [
"androidx.annotation_annotation",
@@ -388,7 +397,7 @@
"quickstep/res",
],
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
static_libs: [
"Launcher3ResLib",
@@ -411,6 +420,7 @@
srcs: [
":launcher-src",
":launcher-quickstep-src",
+ ":launcher-quickstep-dagger",
"go/quickstep/src/**/*.java",
"go/quickstep/src/**/*.kt",
],
@@ -449,11 +459,12 @@
srcs: [
":launcher-src",
":launcher-quickstep-src",
+ ":launcher-quickstep-dagger",
":launcher-build-config",
],
resource_dirs: [],
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
// Note the ordering here is important when it comes to resource
// overriding. We want the most specific resource overrides defined
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 1b9c661..4c724dc 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -52,6 +52,7 @@
"tests/src/com/android/quickstep/TaplOverviewIconTest.java",
"tests/src/com/android/quickstep/TaplTestsQuickstep.java",
"tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
+ "tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt",
"tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java",
],
}
diff --git a/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
similarity index 100%
rename from quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java
rename to quickstep/dagger/LauncherAppComponent.java
diff --git a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
similarity index 78%
rename from quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
rename to quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
index 8180293..f204920 100644
--- a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
+++ b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
@@ -15,8 +15,7 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?attr/materialColorSurfaceBright" />
- <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+ <solid android:color="@android:color/white" />
+ <corners android:radius="@dimen/keyboard_quick_switch_text_button_radius" />
</shape>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 613edac..d1e5667 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:importantForAccessibility="yes"
android:background="@drawable/keyboard_quick_switch_task_view_background"
android:clipToOutline="true"
@@ -27,8 +27,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="gone"
- android:layout_marginStart="@dimen/keyboard_quick_switch_split_view_spacing"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..0eccd8e
--- /dev/null
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/content"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:visibility="gone"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
+
+ app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <ImageView
+ android:id="@+id/icon_1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+ <ImageView
+ android:id="@+id/icon_2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 6a99a3b..3973e56 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView
+<com.android.quickstep.views.DigitalWellBeingToast
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
style="@style/TextTitle"
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
similarity index 68%
rename from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
rename to quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
index c76a2e3..c3f9e54 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
@@ -18,17 +18,20 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:clipToOutline="true"
android:importantForAccessibility="yes"
- launcher:focusBorderColor="?attr/materialColorOutline">
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+ launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/keyboard_quick_switch_overview_button_background"
+ android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:background="@drawable/keyboard_quick_switch_text_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorSurfaceContainer"
+ android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -37,10 +40,11 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_marginBottom="8dp"
- android:tint="?attr/materialColorOnSurface"
+ android:layout_width="@dimen/keyboard_quick_switch_desktop_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_desktop_icon_size"
+ android:layout_marginBottom="4dp"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:src="@drawable/ic_desktop"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
@@ -49,9 +53,9 @@
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
- style="@style/KeyboardQuickSwitchText"
+ style="@style/KeyboardQuickSwitchText.OnTaskView"
android:id="@+id/text"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
similarity index 62%
copy from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
copy to quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
index c76a2e3..0b44a2a 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
@@ -18,44 +18,47 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:clipToOutline="true"
android:importantForAccessibility="yes"
- launcher:focusBorderColor="?attr/materialColorOutline">
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+ launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/keyboard_quick_switch_overview_button_background"
+ android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:background="@drawable/keyboard_quick_switch_text_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorSurfaceBright"
+ android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
- <ImageView
- android:id="@+id/icon"
- android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_marginBottom="8dp"
- android:tint="?attr/materialColorOnSurface"
-
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
<TextView
- style="@style/KeyboardQuickSwitchText"
- android:id="@+id/text"
+ style="@style/KeyboardQuickSwitchText.LargeText"
+ android:id="@+id/large_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
- app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/small_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/KeyboardQuickSwitchText.OnTaskView"
+ android:id="@+id/small_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="center"
+
+ app:layout_constraintTop_toBottomOf="@id/large_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 8f09176..41eb623 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:importantForAccessibility="yes"
android:background="@drawable/keyboard_quick_switch_task_view_background"
android:clipToOutline="true"
@@ -27,8 +27,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
- android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..1474949
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/content"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/thumbnail_2"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <ImageView
+ android:id="@+id/icon_1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+ <ImageView
+ android:id="@+id/icon_2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 34193d3..bdfd241 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -47,4 +47,8 @@
android:inflatedId="@id/icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/digital_wellbeing_toast"
+ android:visibility="invisible"/>
</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index cb4b98f..00a990b 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -73,4 +73,12 @@
android:inflatedId="@id/bottomRight_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/digital_wellbeing_toast"
+ android:visibility="invisible"/>
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/bottomRight_digital_wellbeing_toast"
+ android:visibility="invisible"/>
</com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index e862b9e..2239f8b 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -83,7 +83,7 @@
<dimen name="taskbar_suw_frame">96dp</dimen>
<dimen name="taskbar_suw_insets">24dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+ <!-- Keyboard Quick Switch -->
+ <dimen name="keyboard_quick_switch_taskview_width">217.6dp</dimen>
</resources>
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index 2cb633a..eb88310 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -14,16 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
- <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar">
- <item name="android:navigationBarColor">@android:color/transparent</item>
- <item name="android:statusBarColor">@android:color/transparent</item>
- <item name="android:enforceNavigationBarContrast">false</item>
- <item name="android:windowLightStatusBar">false</item>
- <item name="android:windowBackground">@android:color/transparent</item>
- </style>
+<resources>
<style name="TextAppearance.GestureTutorial.MainTitle.Home"
parent="TextAppearance.GestureTutorial.MainTitle">
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index ccc7f18..7fd6b5c 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -28,6 +28,7 @@
<!-- Border color for a keyboard quick switch task views -->
<attr name="focusBorderColor" format="color" />
<attr name="hoverBorderColor" format="color" />
+ <attr name="focusBorderRadius" format="dimension" />
</declare-styleable>
<declare-styleable name="ClearAllButton">
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d981882..ce3f3ac 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -437,6 +437,7 @@
<dimen name="bubblebar_stashed_handle_width">55dp</dimen>
<dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
<dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
+ <dimen name="bubblebar_stashed_handle_spring_velocity_dp_per_s">@dimen/transient_taskbar_stash_spring_velocity_dp_per_s</dimen>
<!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
background appropriately when close to the rounded corner -->
<dimen name="bubblebar_pointer_visible_size">9dp</dimen>
@@ -487,17 +488,22 @@
<!-- Keyboard Quick Switch -->
<dimen name="keyboard_quick_switch_border_width">4dp</dimen>
<dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_height">136dp</dimen>
<dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
<dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
+ <dimen name="keyboard_quick_switch_desktop_icon_size">32dp</dimen>
<dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
<dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
<dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
- <dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
+ <dimen name="keyboard_quick_switch_view_small_spacing">4dp</dimen>
<dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
<dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_width">104dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_radius">360dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_horizontal_padding">16dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_fade_edge_length">20dp</dimen>
<!-- Digital Wellbeing -->
<dimen name="digital_wellbeing_toast_height">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index d0f474f..f72f3c5 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -327,17 +327,14 @@
<!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the Taskbar only). -->
<string name="move_drop_target_bottom_or_right">Move to bottom/right</string>
- <!-- Label for quick switch tile showing how many more apps are available [CHAR LIMIT=NONE] -->
+ <!-- Label for quick switch tile showing how many more apps are available. The number will be displayed above this text. [CHAR LIMIT=NONE] -->
<string name="quick_switch_overflow">{count, plural,
- =1{Show # more app.}
- other{Show # more apps.}
+ =1{more app}
+ other{more apps}
}</string>
- <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
- <string name="quick_switch_desktop">{count, plural,
- =1{Show # desktop app.}
- other{Show # desktop apps.}
- }</string>
+ <!-- Label for quick switch tile to launch desktop mode [CHAR LIMIT=NONE] -->
+ <string name="quick_switch_desktop">Desktop</string>
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 1f4720c..c423d09 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -205,7 +205,7 @@
<item name="android:textColor">?attr/tutorialSubtitle</item>
</style>
- <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
+ <style name="AllSetTheme" parent="@style/DynamicColorsBaseLauncherTheme.NoActionBar">
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
@@ -272,10 +272,22 @@
<item name="lineHeight">20sp</item>
</style>
+ <style name="KeyboardQuickSwitchText.LargeText" parent="KeyboardQuickSwitchText">
+ <item name="android:textSize">32sp</item>
+ </style>
+
<style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
<item name="android:textColor">?attr/materialColorOnSurface</item>
</style>
+ <style name="KeyboardQuickSwitchText.OnTaskView" parent="KeyboardQuickSwitchText">
+ <item name="android:requiresFadingEdge">horizontal</item>
+ <item name="android:fadeScrollbars">false</item>
+ <item name="android:fadingEdgeLength">20dp</item>
+ <item name="android:ellipsize">none</item>
+ <item name="android:singleLine">true</item>
+ </style>
+
<style name="GestureTutorialActivity" parent="@style/AppTheme">
<item name="background">@android:color/transparent</item>
<item name="tutorialSubtitle">@android:color/black</item>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 4a1035f..e51c956 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -65,7 +65,6 @@
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;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.util.AnimUtils.clampToDuration;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
@@ -1228,9 +1227,7 @@
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
@@ -1294,9 +1291,7 @@
}
protected void unregisterRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 46501c4..e4cc6bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -29,6 +29,7 @@
import com.android.quickstep.RecentsModel;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.LayoutUtils;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -66,6 +67,9 @@
@Nullable private KeyboardQuickSwitchViewController mQuickSwitchViewController;
+ private boolean mHasDesktopTask = false;
+ private boolean mWasDesktopTaskFilteredOut = false;
+
/** Initialize the controller. */
public void init(@NonNull TaskbarControllers controllers) {
mControllers = controllers;
@@ -126,11 +130,15 @@
/* updateTasks= */ false,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
- onDesktop);
+ onDesktop,
+ mHasDesktopTask,
+ mWasDesktopTaskFilteredOut);
return;
}
mTaskListChangeId = mModel.getTasks((tasks) -> {
+ mHasDesktopTask = false;
+ mWasDesktopTaskFilteredOut = false;
if (onDesktop) {
processLoadedTasksOnDesktop(tasks);
} else {
@@ -144,7 +152,9 @@
/* updateTasks= */ true,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
- onDesktop);
+ onDesktop,
+ mHasDesktopTask,
+ mWasDesktopTaskFilteredOut);
});
}
@@ -152,9 +162,22 @@
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
mTasks = tasks.stream()
+ .filter(task -> !(task instanceof DesktopTask))
.limit(MAX_TASKS)
.collect(Collectors.toList());
- mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
+
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i) instanceof DesktopTask) {
+ mHasDesktopTask = true;
+ if (i < mTasks.size()) {
+ mWasDesktopTaskFilteredOut = true;
+ }
+ break;
+ }
+ }
+
+ mNumHiddenTasks = Math.max(0,
+ tasks.size() - (mWasDesktopTaskFilteredOut ? 1 : 0) - MAX_TASKS);
}
private void processLoadedTasksOnDesktop(List<GroupTask> tasks) {
@@ -214,6 +237,8 @@
pw.println(prefix + "\tisOpen=" + (mQuickSwitchViewController != null));
pw.println(prefix + "\tmNumHiddenTasks=" + mNumHiddenTasks);
pw.println(prefix + "\tmTaskListChangeId=" + mTaskListChangeId);
+ pw.println(prefix + "\tmHasDesktopTask=" + mHasDesktopTask);
+ pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
pw.println(prefix + "\tmTasks=[");
for (GroupTask task : mTasks) {
Task task1 = task.task1;
@@ -235,10 +260,6 @@
class ControllerCallbacks {
- int getTaskCount() {
- return mTasks.size() + (mNumHiddenTasks == 0 ? 0 : 1);
- }
-
@Nullable
GroupTask getTaskAt(int index) {
return index < 0 || index >= mTasks.size() ? null : mTasks.get(index);
@@ -279,5 +300,10 @@
boolean isFirstTaskRunning() {
return isTaskRunning(getTaskAt(0));
}
+
+ boolean isAspectRatioSquare() {
+ return mControllers != null && LayoutUtils.isAspectRatioSquare(
+ mControllers.taskbarActivityContext.getDeviceProfile().aspectRatio);
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 39b4f77..8ceb77d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -50,8 +50,10 @@
public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
private static final float THUMBNAIL_BLUR_RADIUS = 1f;
+ private static final int INVALID_BORDER_RADIUS = -1;
@ColorInt private final int mBorderColor;
+ @ColorInt private final int mBorderRadius;
@Nullable private BorderAnimator mBorderAnimator;
@@ -87,6 +89,8 @@
mBorderColor = ta.getColor(
R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR);
+ mBorderRadius = ta.getDimensionPixelSize(
+ R.styleable.TaskView_focusBorderRadius, INVALID_BORDER_RADIUS);
ta.recycle();
}
@@ -103,8 +107,10 @@
Preconditions.assertNotNull(mContent);
mBorderAnimator = BorderAnimator.createScalingBorderAnimator(
- /* borderRadiusPx= */ resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_task_view_radius),
+ /* borderRadiusPx= */ mBorderRadius != INVALID_BORDER_RADIUS
+ ? mBorderRadius
+ : resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_task_view_radius),
/* borderWidthPx= */ resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_border_width),
/* boundsBuilder= */ bounds -> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index dbd9c73..a527c82 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,14 +36,12 @@
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.core.content.res.ResourcesCompat;
import com.android.app.animation.Interpolators;
import com.android.internal.jank.Cuj;
@@ -52,9 +50,7 @@
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.HashMap;
@@ -102,9 +98,13 @@
private int mTaskViewWidth;
private int mTaskViewHeight;
private int mSpacing;
+ private int mSmallSpacing;
private int mOutlineRadius;
private boolean mIsRtl;
+ private int mOverviewTaskIndex = -1;
+ private int mDesktopTaskIndex = -1;
+
@Nullable private AnimatorSet mOpenAnimation;
@Nullable private KeyboardQuickSwitchViewController.ViewCallbacks mViewCallbacks;
@@ -141,6 +141,8 @@
mTaskViewHeight = resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_taskview_height);
mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
+ mSmallSpacing = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_view_small_spacing);
mOutlineRadius = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_radius);
mIsRtl = Utilities.isRtl(resources);
}
@@ -148,6 +150,7 @@
private KeyboardQuickSwitchTaskView createAndAddTaskView(
int index,
boolean isFinalView,
+ boolean useSmallStartSpacing,
@LayoutRes int resId,
@NonNull LayoutInflater layoutInflater,
@Nullable View previousView) {
@@ -156,7 +159,7 @@
taskView.setId(View.generateViewId());
taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
- LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// Create a left-to-right ordering of views (or right-to-left in RTL locales)
if (previousView != null) {
lp.startToEnd = previousView.getId();
@@ -166,7 +169,7 @@
lp.topToTop = PARENT_ID;
lp.bottomToBottom = PARENT_ID;
// Add spacing between views
- lp.setMarginStart(mSpacing);
+ lp.setMarginStart(useSmallStartSpacing ? mSmallSpacing : mSpacing);
if (isFinalView) {
// Add spacing to the end of the final view so that scrolling ends with some padding.
lp.endToEnd = PARENT_ID;
@@ -185,7 +188,8 @@
int numHiddenTasks,
boolean updateTasks,
int currentFocusIndexOverride,
- @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
+ @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks,
+ boolean useDesktopTaskView) {
mViewCallbacks = viewCallbacks;
Resources resources = context.getResources();
Resources.Theme theme = context.getTheme();
@@ -197,57 +201,62 @@
GroupTask groupTask = groupTasks.get(i);
KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
i,
- /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
- groupTask instanceof DesktopTask
- ? R.layout.keyboard_quick_switch_textonly_taskview
+ /* isFinalView= */ i == tasksToDisplay - 1
+ && numHiddenTasks == 0 && !useDesktopTaskView,
+ /* useSmallStartSpacing= */ false,
+ mViewCallbacks.isAspectRatioSquare()
+ ? R.layout.keyboard_quick_switch_taskview_square
: R.layout.keyboard_quick_switch_taskview,
layoutInflater,
previousTaskView);
- if (groupTask instanceof DesktopTask desktopTask) {
- HashMap<String, Integer> args = new HashMap<>();
- args.put("count", desktopTask.tasks.size());
+ final boolean firstTaskIsLeftTopTask =
+ groupTask.mSplitBounds == null
+ || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id
+ || groupTask.task2 == null;
+ currentTaskView.setThumbnails(
+ firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2,
+ firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1,
+ updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+ updateTasks ? mViewCallbacks::updateIconInBackground : null);
- currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
- ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
- currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
- resources.getString(R.string.quick_switch_desktop),
- Locale.getDefault()).format(args));
- } else {
- final boolean firstTaskIsLeftTopTask =
- groupTask.mSplitBounds == null
- || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
- final Task leftTopTask = firstTaskIsLeftTopTask
- ? groupTask.task1 : groupTask.task2;
- final Task rightBottomTask = firstTaskIsLeftTopTask
- ? groupTask.task2 : groupTask.task1;
- currentTaskView.setThumbnails(
- leftTopTask,
- rightBottomTask,
- updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
- updateTasks ? mViewCallbacks::updateIconInBackground : null);
- }
previousTaskView = currentTaskView;
}
-
if (numHiddenTasks > 0) {
HashMap<String, Integer> args = new HashMap<>();
args.put("count", numHiddenTasks);
+ mOverviewTaskIndex = getTaskCount();
View overviewButton = createAndAddTaskView(
- MAX_TASKS,
- /* isFinalView= */ true,
- R.layout.keyboard_quick_switch_textonly_taskview,
+ mOverviewTaskIndex,
+ /* isFinalView= */ !useDesktopTaskView,
+ /* useSmallStartSpacing= */ false,
+ R.layout.keyboard_quick_switch_overview_taskview,
layoutInflater,
previousTaskView);
- overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
- ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
- overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+ overviewButton.<TextView>findViewById(R.id.large_text).setText(
+ String.format(Locale.getDefault(), "%d", numHiddenTasks));
+ overviewButton.<TextView>findViewById(R.id.small_text).setText(new MessageFormat(
resources.getString(R.string.quick_switch_overflow),
Locale.getDefault()).format(args));
+
+ previousTaskView = overviewButton;
}
- mDisplayingRecentTasks = !groupTasks.isEmpty();
+ if (useDesktopTaskView) {
+ mDesktopTaskIndex = getTaskCount();
+ View desktopButton = createAndAddTaskView(
+ mDesktopTaskIndex,
+ /* isFinalView= */ true,
+ /* useSmallStartSpacing= */ numHiddenTasks > 0,
+ R.layout.keyboard_quick_switch_desktop_taskview,
+ layoutInflater,
+ previousTaskView);
+
+ desktopButton.<TextView>findViewById(R.id.text).setText(
+ resources.getString(R.string.quick_switch_desktop));
+ }
+ mDisplayingRecentTasks = !groupTasks.isEmpty() || useDesktopTaskView;
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@@ -260,6 +269,14 @@
});
}
+ int getOverviewTaskIndex() {
+ return mOverviewTaskIndex;
+ }
+
+ int getDesktopTaskIndex() {
+ return mDesktopTaskIndex;
+ }
+
protected Animator getCloseAnimation() {
AnimatorSet closeAnimation = new AnimatorSet();
@@ -370,7 +387,7 @@
}
});
animateFocusMove(-1, Math.min(
- mContent.getChildCount() - 1,
+ getTaskCount() - 1,
currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
displayedContent.setVisibility(VISIBLE);
setVisibility(VISIBLE);
@@ -577,7 +594,11 @@
@Nullable
protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
- return !mDisplayingRecentTasks || index < 0 || index >= mContent.getChildCount()
+ return !mDisplayingRecentTasks || index < 0 || index >= getTaskCount()
? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
}
+
+ public int getTaskCount() {
+ return mContent.getChildCount();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index d411ba6..40e77e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.KeyEvent;
@@ -28,6 +30,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SlideInRemoteTransition;
import com.android.systemui.shared.recents.model.Task;
@@ -56,6 +59,7 @@
private int mCurrentFocusIndex = -1;
private boolean mOnDesktop;
+ private boolean mWasDesktopTaskFilteredOut;
protected KeyboardQuickSwitchViewController(
@NonNull TaskbarControllers controllers,
@@ -77,9 +81,12 @@
int numHiddenTasks,
boolean updateTasks,
int currentFocusIndexOverride,
- boolean onDesktop) {
+ boolean onDesktop,
+ boolean hasDesktopTask,
+ boolean wasDesktopTaskFilteredOut) {
mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
mOnDesktop = onDesktop;
+ mWasDesktopTaskFilteredOut = wasDesktopTaskFilteredOut;
mKeyboardQuickSwitchView.applyLoadPlan(
mOverlayContext,
@@ -87,7 +94,8 @@
numHiddenTasks,
updateTasks,
currentFocusIndexOverride,
- mViewCallbacks);
+ mViewCallbacks,
+ /* useDesktopTaskView= */ !onDesktop && hasDesktopTask);
}
boolean isCloseAnimationRunning() {
@@ -136,7 +144,7 @@
}
// If the user quick switches too quickly, updateCurrentFocusIndex might not have run.
return launchTaskAt(mControllerCallbacks.isFirstTaskRunning()
- && mControllerCallbacks.getTaskCount() > 1 ? 1 : 0);
+ && mKeyboardQuickSwitchView.getTaskCount() > 1 ? 1 : 0);
}
private int launchTaskAt(int index) {
@@ -144,17 +152,11 @@
// Ignore taps on task views and alt key unpresses while the close animation is running.
return -1;
}
- // Even with a valid index, this can be null if the user tries to quick switch before the
- // views have been added in the KeyboardQuickSwitchView.
- GroupTask task = mControllerCallbacks.getTaskAt(index);
- if (task == null) {
- return mOnDesktop ? 1 : Math.max(0, index);
+ if (index == mKeyboardQuickSwitchView.getOverviewTaskIndex()) {
+ // If there is a desktop task view, then we should account for it when focusing the
+ // first hidden non-desktop task view in recents view
+ return mOnDesktop ? 1 : (mWasDesktopTaskFilteredOut ? index + 1 : index);
}
- if (mControllerCallbacks.isTaskRunning(task)) {
- // Ignore attempts to run the selected task if it is already running.
- return -1;
- }
-
Runnable onStartCallback = () -> InteractionJankMonitorWrapper.begin(
mKeyboardQuickSwitchView, Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH);
Runnable onFinishCallback = () -> InteractionJankMonitorWrapper.end(
@@ -169,6 +171,24 @@
onStartCallback,
onFinishCallback),
"SlideInTransition");
+ if (index == mKeyboardQuickSwitchView.getDesktopTaskIndex()) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+ .showDesktopApps(
+ mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+ remoteTransition));
+ return -1;
+ }
+ // Even with a valid index, this can be null if the user tries to quick switch before the
+ // views have been added in the KeyboardQuickSwitchView.
+ GroupTask task = mControllerCallbacks.getTaskAt(index);
+ if (task == null) {
+ return mOnDesktop ? 1 : Math.max(0, index);
+ }
+ if (mControllerCallbacks.isTaskRunning(task)) {
+ // Ignore attempts to run the selected task if it is already running.
+ return -1;
+ }
mControllers.taskbarActivityContext.handleGroupTaskLaunch(
task,
remoteTransition,
@@ -195,6 +215,8 @@
pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
pw.println(prefix + "\tisCloseAnimationRunning=" + isCloseAnimationRunning());
pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
+ pw.println(prefix + "\tmOnDesktop=" + mOnDesktop);
+ pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
}
class ViewCallbacks {
@@ -222,7 +244,7 @@
boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
|| (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && isRTL)
|| (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !isRTL);
- int taskCount = mControllerCallbacks.getTaskCount();
+ int taskCount = mKeyboardQuickSwitchView.getTaskCount();
int toIndex = mCurrentFocusIndex == -1
// Focus the second-most recent app if possible
? (taskCount > 1 ? 1 : 0)
@@ -257,5 +279,9 @@
void updateIconInBackground(Task task, Consumer<Task> callback) {
mControllerCallbacks.updateIconInBackground(task, callback);
}
+
+ boolean isAspectRatioSquare() {
+ return mControllerCallbacks.isAspectRatioSquare();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 96a6d28..69da7b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.animation.Animator;
@@ -232,9 +231,7 @@
LauncherState state = mLauncher.getStateManager().getState();
boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
&& !state.isTaskbarAlignedWithHotseat(mLauncher);
- if ((ENABLE_SHELL_TRANSITIONS
- && isVisible
- && (nonInteractiveState || mSkipLauncherVisibilityChange))) {
+ if (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
return null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 475b516..ec710c5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -41,8 +41,8 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.NavHandle;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index e19042e..47ae741 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -283,7 +283,7 @@
TaskbarHotseatDimensionsProvider dimensionsProvider =
new DeviceProfileDimensionsProviderAdapter(this);
BubbleStashController bubbleStashController = isTransientTaskbar
- ? new TransientBubbleStashController(dimensionsProvider, getResources())
+ ? new TransientBubbleStashController(dimensionsProvider, this)
: new PersistentBubbleStashController(dimensionsProvider);
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index acf976f..2845cee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -171,6 +171,10 @@
}
private void updateBackgroundAlpha() {
+ if (mActivity.isPhoneMode()) {
+ return;
+ }
+
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
* mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 4df0223..2370dfd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -21,7 +21,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
-import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
+import static com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
import android.animation.ObjectAnimator;
import android.view.animation.Interpolator;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 56f88d1..60e65b3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -152,12 +152,12 @@
/**
* How long to delay the icon/stash handle alpha.
*/
- private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
+ public static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
/**
* How long the icon/stash handle alpha animation plays.
*/
- private static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+ public static final long TASKBAR_STASH_ALPHA_DURATION = 50;
/**
* How long to delay the icon/stash handle alpha for the home to app taskbar animation.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 43960a1..6b1173a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_HIDE;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
@@ -40,6 +39,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
@@ -394,7 +394,7 @@
if (overviewCommandHelper == null) {
return;
}
- overviewCommandHelper.addCommand(TYPE_HIDE);
+ overviewCommandHelper.addCommand(CommandType.HIDE);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 8b8b4da..32d6561 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -66,7 +66,7 @@
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.util.List;
import java.util.function.Predicate;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 296d379..5ec00ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -28,7 +28,7 @@
import com.android.internal.jank.Cuj;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
/**
* Callbacks for {@link TaskbarView} to interact with its controller.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index cdd3e13..d70a317 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -41,10 +41,10 @@
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.wm.shell.Flags;
import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
-import com.android.wm.shell.common.bubbles.RemovedBubble;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.RemovedBubble;
import java.util.ArrayList;
import java.util.List;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
index 39d1ed7..7a32ef1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
@@ -17,7 +17,7 @@
import android.graphics.Bitmap
import android.graphics.Path
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
/** An entity in the bubble bar. */
sealed class BubbleBarItem(open var key: String, open var view: BubbleView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index a6b0860..9c34307 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -28,8 +28,8 @@
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BaseBubblePinController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
/**
* Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c458936..06301c7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -48,7 +48,7 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.taskbar.bubbles.animation.BubbleAnimator;
import com.android.launcher3.util.DisplayController;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1303,7 +1303,10 @@
return totalIconSize + totalSpace + horizontalPadding;
}
- private float collapsedWidth() {
+ /**
+ * Get width of the bubble bar if it is collapsed
+ */
+ float collapsedWidth() {
final int bubbleChildCount = getBubbleChildCount();
final float horizontalPadding = 2 * mBubbleBarPadding;
// If there are more than 2 bubbles, the first 2 should be visible when collapsed,
@@ -1473,8 +1476,9 @@
pw.println("BubbleBarView state:");
pw.println(" visibility: " + getVisibility());
pw.println(" alpha: " + getAlpha());
- pw.println(" translation Y: " + getTranslationY());
- pw.println(" bubbles in bar (childCount = " + getChildCount() + ")");
+ pw.println(" translationY: " + getTranslationY());
+ pw.println(" childCount: " + getChildCount());
+ pw.println(" hasOverflow: " + hasOverflow());
for (BubbleView bubbleView: getBubbles()) {
BubbleBarItem bubble = bubbleView.getBubble();
String key = bubble == null ? "null" : bubble.getKey();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 5c1a546..d9e3406 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -43,7 +43,7 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.List;
@@ -80,12 +80,15 @@
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
private final MultiValueAlpha mBubbleBarAlpha;
- private final AnimatedFloat mBubbleBarScale = new AnimatedFloat(this::updateScale);
+ private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
+ private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
this::updateTranslationY);
// Modified when swipe up is happening on the bubble bar or task bar.
private float mBubbleBarSwipeUpTranslationY;
+ // Modified when bubble bar is springing back into the stash handle.
+ private float mBubbleBarStashTranslationY;
// Whether the bar is hidden for a sysui state.
private boolean mHiddenForSysui;
@@ -125,7 +128,7 @@
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
- mBubbleBarScale.updateValue(1f);
+ mBubbleBarScaleY.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
mBubbleBarClickListener = v -> expandBubbleBar();
mBubbleDragController.setupBubbleBarView(mBarView);
@@ -255,19 +258,48 @@
return mBubbleBarAlpha;
}
- public AnimatedFloat getBubbleBarScale() {
- return mBubbleBarScale;
+ public AnimatedFloat getBubbleBarScaleX() {
+ return mBubbleBarScaleX;
+ }
+
+ public AnimatedFloat getBubbleBarScaleY() {
+ return mBubbleBarScaleY;
}
public AnimatedFloat getBubbleBarTranslationY() {
return mBubbleBarTranslationY;
}
+ public float getBubbleBarCollapsedWidth() {
+ return mBarView.collapsedWidth();
+ }
+
public float getBubbleBarCollapsedHeight() {
return mBarView.getBubbleBarCollapsedHeight();
}
/**
+ * @see BubbleBarView#getRelativePivotX()
+ */
+ public float getBubbleBarRelativePivotX() {
+ return mBarView.getRelativePivotX();
+ }
+
+ /**
+ * @see BubbleBarView#getRelativePivotY()
+ */
+ public float getBubbleBarRelativePivotY() {
+ return mBarView.getRelativePivotY();
+ }
+
+ /**
+ * @see BubbleBarView#setRelativePivot(float, float)
+ */
+ public void setBubbleBarRelativePivot(float x, float y) {
+ mBarView.setRelativePivot(x, y);
+ }
+
+ /**
* Whether the bubble bar is visible or not.
*/
public boolean isBubbleBarVisible() {
@@ -287,6 +319,14 @@
}
/**
+ * @return {@code true} if bubble bar is on the left edge of the screen, {@code false} if on
+ * the right
+ */
+ public boolean isBubbleBarOnLeft() {
+ return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl());
+ }
+
+ /**
* Update bar {@link BubbleBarLocation}
*/
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
@@ -474,17 +514,24 @@
updateTranslationY();
}
- private void updateTranslationY() {
- mBarView.setTranslationY(mBubbleBarTranslationY.value
- + mBubbleBarSwipeUpTranslationY);
+ /**
+ * Sets the translation of the bubble bar during the stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mBubbleBarStashTranslationY = transY;
+ updateTranslationY();
}
- /**
- * Applies scale properties for the entire bubble bar.
- */
- private void updateScale() {
- float scale = mBubbleBarScale.value;
+ private void updateTranslationY() {
+ mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
+ + mBubbleBarStashTranslationY);
+ }
+
+ private void updateScaleX(float scale) {
mBarView.setScaleX(scale);
+ }
+
+ private void updateScaleY(float scale) {
mBarView.setScaleY(scale);
}
@@ -793,6 +840,7 @@
pw.println(" mShouldShowEducation: " + mShouldShowEducation);
pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
+ pw.println(" mOverflowAdded: " + mOverflowAdded);
if (mBarView != null) {
mBarView.dump(pw);
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
index 8e9a2f6..12b1487 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -51,7 +51,7 @@
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
/**
* Loads the necessary info to populate / present a bubble (name, icon, shortcut).
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index f554fcd..a459dd9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -29,7 +29,7 @@
import com.android.launcher3.R;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarDragLayer;
-import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DismissView;
import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
index 6c3f0d8..a8002a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
@@ -18,7 +18,7 @@
package com.android.launcher3.taskbar.bubbles
import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.DismissView
+import com.android.wm.shell.shared.bubbles.DismissView
/**
* Dismiss view is shared from WMShell. It requires setup with local resources.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 87f466f..adaba7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -29,8 +29,8 @@
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import com.android.launcher3.R;
-import com.android.wm.shell.common.bubbles.DismissCircleView;
-import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DismissCircleView;
+import com.android.wm.shell.shared.bubbles.DismissView;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 54b883c..42bd197 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -27,8 +27,8 @@
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController.LocationChangeListener;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
/**
* Controls bubble bar drag interactions.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
index 1341b53..af1666f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -28,8 +28,8 @@
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BaseBubblePinController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
/** Controller to manage pinning bubble bar to left or right when dragging starts from a bubble */
class BubblePinController(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 6bfe8f4..fdd385a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -21,6 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -28,6 +29,7 @@
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
@@ -37,9 +39,9 @@
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
/**
* Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -49,23 +51,29 @@
private final TaskbarActivityContext mActivity;
private final StashedHandleView mStashedHandleView;
private final MultiValueAlpha mStashedHandleAlpha;
+ private float mTranslationForSwipeY;
+ private float mTranslationForStashY;
// Initialized in init.
private BubbleBarViewController mBarViewController;
private BubbleStashController mBubbleStashController;
private RegionSamplingHelper mRegionSamplingHelper;
- private int mBarSize;
- private int mStashedTaskbarHeight;
+ // Height of the area for the stash handle. Handle will be drawn in the center of this.
+ // This is also the area where touch is handled on the handle.
+ private int mStashedBubbleBarHeight;
private int mStashedHandleWidth;
private int mStashedHandleHeight;
- // The bounds we want to clip to in the settled state when showing the stashed handle.
+ // The bounds of the stashed handle in settled state.
private final Rect mStashedHandleBounds = new Rect();
+ private float mStashedHandleRadius;
// When the reveal animation is cancelled, we can assume it's about to create a new animation,
// which should start off at the same point the cancelled one left off.
private float mStartProgressForNextRevealAnim;
- private boolean mWasLastRevealAnimReversed;
+ // Use a nullable boolean to handle initial case where the last animation direction is not known
+ @Nullable
+ private Boolean mWasLastRevealAnimReversed = null;
// XXX: if there are more of these maybe do state flags instead
private boolean mHiddenForSysui;
@@ -77,6 +85,7 @@
mActivity = activity;
mStashedHandleView = stashedHandleView;
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
+ mStashedHandleAlpha.setUpdateVisibility(true);
}
/** Initialize controller. */
@@ -84,26 +93,31 @@
mBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
mStashedHandleHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_height);
mStashedHandleWidth = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_width);
- mBarSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
- final int bottomMargin = resources.getDimensionPixelSize(
- R.dimen.transient_taskbar_bottom_margin);
- mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
+ int barSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
+ // Use the max translation for bubble bar whether it is on the home screen or in app.
+ // Use values directly from device profile to avoid referencing other bubble controllers
+ // during init flow.
+ int maxTy = Math.max(deviceProfile.hotseatBarBottomSpacePx,
+ deviceProfile.taskbarBottomMargin);
+ // Adjust handle view size to accommodate the handle morphing into the bubble bar
+ mStashedHandleView.getLayoutParams().height = barSize + maxTy;
mStashedHandleAlpha.get(0).setValue(0);
- mStashedTaskbarHeight = resources.getDimensionPixelSize(
+ mStashedBubbleBarHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_size);
mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- float stashedHandleRadius = view.getHeight() / 2f;
- outline.setRoundRect(mStashedHandleBounds, stashedHandleRadius);
+ mStashedHandleRadius = view.getHeight() / 2f;
+ outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
}
});
@@ -132,28 +146,25 @@
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
- final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
+ final int stashedCenterY = mStashedHandleView.getHeight() - mStashedBubbleBarHeight / 2;
+ final int stashedCenterX;
if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
final int left = mBarViewController.getHorizontalMargin();
- mStashedHandleBounds.set(
- left,
- stashedCenterY - mStashedHandleHeight / 2,
- left + mStashedHandleWidth,
- stashedCenterY + mStashedHandleHeight / 2);
- mStashedHandleView.setPivotX(0);
+ stashedCenterX = left + mStashedHandleWidth / 2;
} else {
final int right =
- mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
- mStashedHandleBounds.set(
- right - mStashedHandleWidth,
- stashedCenterY - mStashedHandleHeight / 2,
- right,
- stashedCenterY + mStashedHandleHeight / 2);
- mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
+ mStashedHandleView.getRight() - mBarViewController.getHorizontalMargin();
+ stashedCenterX = right - mStashedHandleWidth / 2;
}
-
+ mStashedHandleBounds.set(
+ stashedCenterX - mStashedHandleWidth / 2,
+ stashedCenterY - mStashedHandleHeight / 2,
+ stashedCenterX + mStashedHandleWidth / 2,
+ stashedCenterY + mStashedHandleHeight / 2
+ );
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
- mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
+ mStashedHandleView.setPivotX(stashedCenterX);
+ mStashedHandleView.setPivotY(stashedCenterY);
}
public void onDestroy() {
@@ -162,6 +173,13 @@
}
/**
+ * Returns the width of the stashed handle.
+ */
+ public int getStashedWidth() {
+ return mStashedHandleWidth;
+ }
+
+ /**
* Returns the height of the stashed handle.
*/
public int getStashedHeight() {
@@ -169,13 +187,6 @@
}
/**
- * Returns the height when the bubble bar is unstashed (so the height of the bubble bar).
- */
- public int getUnstashedHeight() {
- return mBarSize;
- }
-
- /**
* Called when system ui state changes. Bubbles don't show when the device is locked.
*/
public void setHiddenForSysui(boolean hidden) {
@@ -242,7 +253,20 @@
* Sets the translation of the stashed handle during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
- mStashedHandleView.setTranslationY(transY);
+ mTranslationForSwipeY = transY;
+ updateTranslationY();
+ }
+
+ /**
+ * Sets the translation of the stashed handle during the spring on stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mTranslationForStashY = transY;
+ updateTranslationY();
+ }
+
+ private void updateTranslationY() {
+ mStashedHandleView.setTranslationY(mTranslationForSwipeY + mTranslationForStashY);
}
/** Returns the translation of the stashed handle. */
@@ -263,18 +287,17 @@
* the size of where the bubble bar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
- Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+ Rect bubbleBarBounds = getLocalBubbleBarBounds();
- // Account for the full visual height of the bubble bar
- int heightDiff = (mBarSize - bubbleBarBounds.height()) / 2;
- bubbleBarBounds.top -= heightDiff;
- bubbleBarBounds.bottom += heightDiff;
- float stashedHandleRadius = mStashedHandleView.getHeight() / 2f;
+ float bubbleBarRadius = bubbleBarBounds.height() / 2f;
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
- stashedHandleRadius, stashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
+ bubbleBarRadius, mStashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
- boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+ // We are only changing direction when mWasLastRevealAnimReversed is set at least once
+ boolean changingDirection =
+ mWasLastRevealAnimReversed != null && mWasLastRevealAnimReversed != isReversed;
+
mWasLastRevealAnimReversed = isReversed;
if (changingDirection) {
mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
@@ -291,6 +314,21 @@
return revealAnim;
}
+ /**
+ * Get bounds for the bubble bar in the space of the handle view
+ */
+ private Rect getLocalBubbleBarBounds() {
+ // Position the bubble bar bounds to the space of handle view
+ Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+ // Start by moving bubble bar bounds to the bottom of handle view
+ int height = bubbleBarBounds.height();
+ bubbleBarBounds.bottom = mStashedHandleView.getHeight();
+ bubbleBarBounds.top = bubbleBarBounds.bottom - height;
+ // Then apply translation that is applied to the bubble bar
+ bubbleBarBounds.offset(0, (int) mBubbleStashController.getBubbleBarTranslationY());
+ return bubbleBarBounds;
+ }
+
/** Checks that the stash handle is visible and that the motion event is within bounds. */
public boolean isEventOverHandle(MotionEvent ev) {
if (mStashedHandleView.getVisibility() != VISIBLE) {
@@ -299,7 +337,7 @@
// the bounds of the handle only include the visible part, so we check that the Y coordinate
// is anywhere within the stashed height of bubble bar (same as taskbar stashed height).
- final int top = mActivity.getDeviceProfile().heightPx - mStashedTaskbarHeight;
+ final int top = mActivity.getDeviceProfile().heightPx - mStashedBubbleBarHeight;
final float x = ev.getRawX();
return ev.getRawY() >= top && x >= mStashedHandleBounds.left
&& x <= mStashedHandleBounds.right;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index eb3b24b..591a9da 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -34,9 +34,9 @@
import com.android.launcher3.R;
import com.android.launcher3.icons.DotRenderer;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
// TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
@@ -237,7 +237,11 @@
mBubble = bubble;
mIcon = bubble.getIcon();
updateBubbleIcon();
- mAppIcon.setImageBitmap(bubble.getBadge());
+ if (bubble.getInfo().showAppBadge()) {
+ mAppIcon.setImageBitmap(bubble.getBadge());
+ } else {
+ mAppIcon.setVisibility(GONE);
+ }
mDotColor = bubble.getDotColor();
mDotRenderer = new DotRenderer(mBubbleSize, bubble.getDotPath(), DEFAULT_PATH_SIZE);
String contentDesc = bubble.getInfo().getTitle();
@@ -302,8 +306,10 @@
}
void setBadgeScale(float fraction) {
- mAppIcon.setScaleX(fraction);
- mAppIcon.setScaleY(fraction);
+ if (mAppIcon.getVisibility() == VISIBLE) {
+ mAppIcon.setScaleX(fraction);
+ mAppIcon.setScaleY(fraction);
+ }
}
boolean hasUnseenContent() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 48eb7de..8d63217 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -23,8 +23,8 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
import java.io.PrintWriter
/** StashController that defines stashing behaviour for the taskbar modes. */
@@ -181,8 +181,5 @@
/** How long to translate Y coordinate of the BubbleBar. */
const val BAR_TRANSLATION_DURATION = 300L
-
- /** The scale bubble bar animates to when being stashed. */
- const val STASHED_BAR_SCALE = 0.5f
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 1b65019..eaf4bf9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -30,8 +30,8 @@
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
class PersistentBubbleStashController(
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
@@ -116,7 +116,7 @@
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlphaAnimator = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
- bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScale
+ bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScaleY
}
private fun animateAfterUnlock() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 1a4b982..1157305 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -17,30 +17,36 @@
package com.android.launcher3.taskbar.bubbles.stashing
import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
-import android.content.res.Resources
+import android.content.Context
import android.view.MotionEvent
import android.view.View
import androidx.annotation.VisibleForTesting
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.app.animation.Interpolators.LINEAR
import com.android.launcher3.R
import com.android.launcher3.anim.AnimatedFloat
-import com.android.launcher3.taskbar.StashedHandleViewController
+import com.android.launcher3.anim.SpringAnimationBuilder
import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import kotlin.math.max
class TransientBubbleStashController(
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
- resources: Resources
+ private val context: Context
) : BubbleStashController {
private lateinit var bubbleBarViewController: BubbleBarViewController
@@ -50,14 +56,21 @@
// stash view properties
private var bubbleStashedHandleViewController: BubbleStashedHandleViewController? = null
private var stashHandleViewAlpha: MultiPropertyFactory<View>.MultiProperty? = null
+ private var translationYDuringStash = AnimatedFloat { transY ->
+ bubbleStashedHandleViewController?.setTranslationYForStash(transY)
+ bubbleBarViewController.setTranslationYForStash(transY)
+ }
+ private val stashHandleStashVelocity =
+ context.resources.getDimension(R.dimen.bubblebar_stashed_handle_spring_velocity_dp_per_s)
private var stashedHeight: Int = 0
// bubble bar properties
private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty
private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
- private lateinit var bubbleBarScale: AnimatedFloat
- private val mHandleCenterFromScreenBottom =
- resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
+ private lateinit var bubbleBarScaleX: AnimatedFloat
+ private lateinit var bubbleBarScaleY: AnimatedFloat
+ private val handleCenterFromScreenBottom =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
private var animator: AnimatorSet? = null
@@ -136,12 +149,10 @@
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
- bubbleBarScale = bubbleBarViewController.bubbleBarScale
+ bubbleBarScaleX = bubbleBarViewController.bubbleBarScaleX
+ bubbleBarScaleY = bubbleBarViewController.bubbleBarScaleY
stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
- stashHandleViewAlpha =
- bubbleStashedHandleViewController
- ?.stashedHandleAlpha
- ?.get(StashedHandleViewController.ALPHA_INDEX_STASHED)
+ stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0)
}
private fun animateAfterUnlock() {
@@ -149,7 +160,8 @@
if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
isStashed = false
animatorSet.playTogether(
- bubbleBarScale.animateToValue(1f),
+ bubbleBarScaleX.animateToValue(1f),
+ bubbleBarScaleY.animateToValue(1f),
bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
bubbleBarAlpha.animateToValue(1f)
)
@@ -169,7 +181,8 @@
stashHandleViewAlpha?.value = 0f
this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
bubbleBarAlpha.setValue(1f)
- bubbleBarScale.updateValue(1f)
+ bubbleBarScaleX.updateValue(1f)
+ bubbleBarScaleY.updateValue(1f)
isStashed = false
onIsStashedChanged()
}
@@ -179,7 +192,8 @@
stashHandleViewAlpha?.value = 1f
this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
bubbleBarAlpha.setValue(0f)
- bubbleBarScale.updateValue(STASHED_BAR_SCALE)
+ bubbleBarScaleX.updateValue(getStashScaleX())
+ bubbleBarScaleY.updateValue(getStashScaleY())
isStashed = true
onIsStashedChanged()
}
@@ -223,11 +237,11 @@
// the difference between the centers of the handle and the bubble bar is the difference
// between their distance from the bottom of the screen.
val barCenter: Float = bubbleBarViewController.bubbleBarCollapsedHeight / 2f
- return mHandleCenterFromScreenBottom - barCenter
+ return handleCenterFromScreenBottom - barCenter
}
override fun getStashedHandleTranslationForNewBubbleAnimation(): Float {
- return -mHandleCenterFromScreenBottom
+ return -handleCenterFromScreenBottom
}
override fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>? {
@@ -245,7 +259,19 @@
override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
private fun getStashTranslation(): Float {
- return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
+ return bubbleBarTranslationY / 2f
+ }
+
+ @VisibleForTesting
+ fun getStashScaleX(): Float {
+ val handleWidth = bubbleStashedHandleViewController?.stashedWidth ?: 0
+ return handleWidth / bubbleBarViewController.bubbleBarCollapsedWidth
+ }
+
+ @VisibleForTesting
+ fun getStashScaleY(): Float {
+ val handleHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
+ return handleHeight / bubbleBarViewController.bubbleBarCollapsedHeight
}
/**
@@ -258,61 +284,93 @@
@Suppress("SameParameterValue")
private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet {
val animatorSet = AnimatorSet()
- val fullLengthAnimatorSet = AnimatorSet()
- // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
- val firstHalfAnimatorSet = AnimatorSet()
- val secondHalfAnimatorSet = AnimatorSet()
- val firstHalfDurationScale: Float
- val secondHalfDurationScale: Float
- val stashHandleAlphaValue: Float
- if (isStashed) {
- firstHalfDurationScale = 0.75f
- secondHalfDurationScale = 0.5f
- stashHandleAlphaValue = 1f
- fullLengthAnimatorSet.play(
- bubbleBarTranslationYAnimator.animateToValue(getStashTranslation())
- )
- firstHalfAnimatorSet.playTogether(
- bubbleBarAlpha.animateToValue(0f),
- bubbleBarScale.animateToValue(STASHED_BAR_SCALE)
- )
- } else {
- firstHalfDurationScale = 0.5f
- secondHalfDurationScale = 0.75f
- stashHandleAlphaValue = 0f
- fullLengthAnimatorSet.playTogether(
- bubbleBarScale.animateToValue(1f),
- bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY)
- )
- secondHalfAnimatorSet.playTogether(bubbleBarAlpha.animateToValue(1f))
- }
- stashHandleViewAlpha?.let {
- secondHalfAnimatorSet.playTogether(it.animateToValue(stashHandleAlphaValue))
- }
- bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.let {
- fullLengthAnimatorSet.play(it)
- }
- fullLengthAnimatorSet.setDuration(duration)
- firstHalfAnimatorSet.setDuration((duration * firstHalfDurationScale).toLong())
- secondHalfAnimatorSet.setDuration((duration * secondHalfDurationScale).toLong())
- secondHalfAnimatorSet.startDelay = (duration * (1 - secondHalfDurationScale)).toLong()
- animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, secondHalfAnimatorSet)
- animatorSet.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- animator = null
- controllersAfterInitAction.runAfterInit {
- if (isStashed) {
- bubbleBarViewController.isExpanded = false
- }
- taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
- }
- }
+
+ val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+ val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
+ animatorSet.play(
+ createStashAlphaAnimator(isStashed).apply {
+ this.duration = max(0L, alphaDuration - alphaDelay)
+ this.startDelay = alphaDelay
+ this.interpolator = LINEAR
}
)
+
+ animatorSet.play(
+ createSpringOnStashAnimator(isStashed).apply {
+ this.duration = duration
+ this.interpolator = LINEAR
+ }
+ )
+
+ animatorSet.play(
+ bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ val pivotX = if (bubbleBarViewController.isBubbleBarOnLeft) 0f else 1f
+ animatorSet.play(
+ createScaleAnimator(isStashed).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ this.setBubbleBarPivotDuringAnim(pivotX, 1f)
+ }
+ )
+
+ val translationYTarget = if (isStashed) getStashTranslation() else bubbleBarTranslationY
+ animatorSet.play(
+ bubbleBarTranslationYAnimator.animateToValue(translationYTarget).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ animatorSet.doOnEnd {
+ animator = null
+ controllersAfterInitAction.runAfterInit {
+ if (isStashed) {
+ bubbleBarViewController.isExpanded = false
+ }
+ taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+ }
return animatorSet
}
+ private fun createStashAlphaAnimator(isStashed: Boolean): AnimatorSet {
+ val stashHandleAlphaTarget = if (isStashed) 1f else 0f
+ val barAlphaTarget = if (isStashed) 0f else 1f
+ return AnimatorSet().apply {
+ play(bubbleBarAlpha.animateToValue(barAlphaTarget))
+ play(stashHandleViewAlpha?.animateToValue(stashHandleAlphaTarget))
+ }
+ }
+
+ private fun createSpringOnStashAnimator(isStashed: Boolean): Animator {
+ if (!isStashed) {
+ // Animate the stash translation back to 0
+ return translationYDuringStash.animateToValue(0f)
+ }
+ // Apply a spring to the handle
+ return SpringAnimationBuilder(context)
+ .setStartValue(translationYDuringStash.value)
+ .setEndValue(0f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setStartVelocity(stashHandleStashVelocity)
+ .build(translationYDuringStash, AnimatedFloat.VALUE)
+ }
+
+ private fun createScaleAnimator(isStashed: Boolean): AnimatorSet {
+ val scaleXTarget = if (isStashed) getStashScaleX() else 1f
+ val scaleYTarget = if (isStashed) getStashScaleY() else 1f
+ return AnimatorSet().apply {
+ play(bubbleBarScaleX.animateToValue(scaleXTarget))
+ play(bubbleBarScaleY.animateToValue(scaleYTarget))
+ }
+ }
+
private fun onIsStashedChanged() {
controllersAfterInitAction.runAfterInit {
taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -363,13 +421,23 @@
}
private fun Animator.updateTouchRegionOnAnimationEnd(): Animator {
- this.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- onIsStashedChanged()
- }
+ doOnEnd { onIsStashedChanged() }
+ return this
+ }
+
+ private fun Animator.setBubbleBarPivotDuringAnim(pivotX: Float, pivotY: Float): Animator {
+ var initialPivotX = Float.NaN
+ var initialPivotY = Float.NaN
+ doOnStart {
+ initialPivotX = bubbleBarViewController.bubbleBarRelativePivotX
+ initialPivotY = bubbleBarViewController.bubbleBarRelativePivotY
+ bubbleBarViewController.setBubbleBarRelativePivot(pivotX, pivotY)
+ }
+ doOnEnd {
+ if (!initialPivotX.isNaN() && !initialPivotY.isNaN()) {
+ bubbleBarViewController.setBubbleBarRelativePivot(initialPivotX, initialPivotY)
}
- )
+ }
return this
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 37e0034..4590efe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -379,12 +379,7 @@
}
@Override
- public void setIconVisible(boolean visible) {
- setForceHideRing(!visible);
- super.setIconVisible(visible);
- }
-
- private void setForceHideRing(boolean forceHideRing) {
+ public void setForceHideRing(boolean forceHideRing) {
if (mForceHideRing == forceHideRing) {
return;
}
@@ -417,7 +412,7 @@
private void drawEffect(Canvas canvas) {
// Don't draw ring effect if item is about to be dragged or if the icon is not visible.
- if (mDrawForDrag || !mIsIconVisible) {
+ if (mDrawForDrag || !mIsIconVisible || mForceHideRing) {
return;
}
mIconRingPaint.setColor(RING_SHADOW_COLOR);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 5eb5e75..55c1885 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -498,10 +498,8 @@
boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
if (started) {
DeviceProfile profile = getDeviceProfile();
- boolean willUserBeActive =
- (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
boolean visible = (state == NORMAL || state == OVERVIEW)
- && (willUserBeActive || isUserActive())
+ && isUserActive()
&& !profile.isVerticalBarLayout()
&& !mIsOverlayVisible;
SystemUiProxy.INSTANCE.get(this)
@@ -1271,10 +1269,6 @@
return ObjectWrapper.wrap(new Integer(info.id));
}
- public void setHintUserWillBeActive() {
- addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
- }
-
@Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
super.onDisplayInfoChanged(context, info, flags);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 2625646..1ba784b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import android.content.Context;
import android.graphics.Color;
@@ -107,8 +106,7 @@
@Override
public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
- if (ENABLE_SHELL_TRANSITIONS) return false;
- return super.isTaskbarAlignedWithHotseat(launcher);
+ return false;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3d94442..38d08e0 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -97,6 +97,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.Cuj;
import com.android.internal.util.LatencyTracker;
@@ -170,10 +171,12 @@
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
-public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
- Q extends RecentsView, S extends BaseState<S>>
- extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
- RecentsAnimationCallbacks.RecentsAnimationListener {
+public abstract class AbsSwipeUpHandler<
+ RECENTS_CONTAINER extends Context & RecentsViewContainer,
+ RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+ STATE extends BaseState<STATE>>
+ extends SwipeUpAnimationLogic
+ implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener {
private static final String TAG = "AbsSwipeUpHandler";
private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
@@ -181,7 +184,7 @@
// Fraction of the scroll and transform animation in which the current task fades out
private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f;
- protected final BaseContainerInterface<S, T> mContainerInterface;
+ protected final BaseContainerInterface<STATE, RECENTS_CONTAINER> mContainerInterface;
protected final InputConsumerProxy mInputConsumerProxy;
protected final ActivityInitListener mActivityInitListener;
// Callbacks to be made once the recents animation starts
@@ -192,8 +195,8 @@
protected @Nullable RecentsAnimationController mRecentsAnimationController;
protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
- protected @Nullable T mContainer;
- protected @Nullable Q mRecentsView;
+ protected @Nullable RECENTS_CONTAINER mContainer;
+ protected @Nullable RECENTS_VIEW mRecentsView;
protected Runnable mGestureEndCallback;
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
@@ -486,11 +489,11 @@
return false;
}
- T createdContainer = (T) mContainerInterface.getCreatedContainer();
+ RECENTS_CONTAINER createdContainer = mContainerInterface.getCreatedContainer();
if (createdContainer != null) {
initTransitionEndpoints(createdContainer.getDeviceProfile());
}
- final T container = (T) mContainerInterface.getCreatedContainer();
+ final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
if (mContainer == container) {
return true;
}
@@ -564,7 +567,7 @@
}
private void onLauncherStart() {
- final T container = (T) mContainerInterface.getCreatedContainer();
+ final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
if (container == null || mContainer != container) {
return;
}
@@ -949,7 +952,6 @@
// We will handle the sysui flags based on the centermost task view.
mRecentsAnimationController.setUseLauncherSystemBarFlags(swipeUpThresholdPassed
|| (quickswitchThresholdPassed && centermostTaskFlags != 0));
- mRecentsAnimationController.setSplitScreenMinimized(mContext, swipeUpThresholdPassed);
// Provide a hint to WM the direction that we will be settling in case the animation
// needs to be canceled
mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
@@ -1097,7 +1099,7 @@
*/
@UiThread
private void notifyGestureStarted() {
- final T curActivity = mContainer;
+ final RECENTS_CONTAINER curActivity = mContainer;
if (curActivity != null) {
// Once the gesture starts, we can no longer transition home through the button, so
// reset the force override of the activity visibility
@@ -1168,7 +1170,8 @@
/**
* Called if the end target has been set and the recents animation is started.
*/
- private void onCalculateEndTarget() {
+ @VisibleForTesting
+ protected void onCalculateEndTarget() {
final GestureEndTarget endTarget = mGestureState.getEndTarget();
switch (endTarget) {
@@ -1181,7 +1184,8 @@
}
}
- private void onSettledOnEndTarget() {
+ @VisibleForTesting
+ protected void onSettledOnEndTarget() {
// Fast-finish the attaching animation if it's still running.
maybeUpdateRecentsAttachedState(false);
final GestureEndTarget endTarget = mGestureState.getEndTarget();
@@ -1417,7 +1421,7 @@
}
}
Interpolator interpolator;
- S state = mContainerInterface.stateFromGestureEndTarget(endTarget);
+ STATE state = mContainerInterface.stateFromGestureEndTarget(endTarget);
if (isKeyboardTaskFocusPending()) {
interpolator = EMPHASIZED;
} else if (state.displayOverviewTasksAsGrid(mDp)) {
@@ -1767,8 +1771,7 @@
private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget,
RecentsOrientedState orientationState) {
- if (runningTaskTarget.rotationChange != 0
- && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ if (runningTaskTarget.rotationChange != 0) {
return Math.abs(runningTaskTarget.rotationChange) == ROTATION_90
? ROTATION_270 : ROTATION_90;
} else {
@@ -2499,7 +2502,7 @@
}
private void animateSplashScreenExit(
- @NonNull T activity,
+ @NonNull RECENTS_CONTAINER activity,
@NonNull RemoteAnimationTarget[] appearedTaskTargets,
@NonNull RemoteAnimationTarget[] animatingTargets) {
ViewGroup splashView = activity.getDragLayer();
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 3a8c141..777761b 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -68,8 +68,6 @@
public abstract void onAssistantVisibilityChanged(float assistantVisibility);
- public abstract boolean allowMinimizeSplitScreen();
-
public abstract boolean isResumed();
public abstract boolean isStarted();
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 89fbf4a..94a4527 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -133,12 +133,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- // TODO: Remove this once b/77875376 is fixed
- return false;
- }
-
- @Override
public boolean allowAllAppsFromOverview() {
return false;
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index b564fa7..e9fe2f7 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -271,11 +271,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- return true;
- }
-
- @Override
public boolean allowAllAppsFromOverview() {
return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
// If floating search bar would not show in overview, don't allow all apps gesture.
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index e17cdcd..f653e60 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -62,8 +62,8 @@
/**
* Temporary class to allow easier refactoring
*/
-public class LauncherSwipeHandlerV2 extends
- AbsSwipeUpHandler<QuickstepLauncher, RecentsView, LauncherState> {
+public class LauncherSwipeHandlerV2 extends AbsSwipeUpHandler<
+ QuickstepLauncher, RecentsView<QuickstepLauncher, LauncherState>, LauncherState> {
public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
@@ -107,9 +107,6 @@
|| !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
mContainer.getRootView().setForceHideBackArrow(true);
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- mContainer.setHintUserWillBeActive();
- }
if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
return new LauncherHomeAnimationFactory() {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index f6b9e4e..8873275 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -33,6 +33,8 @@
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.*
import com.android.launcher3.util.Executors
import com.android.launcher3.util.RunnableList
+import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus
+import com.android.quickstep.OverviewCommandHelper.CommandType.*
import com.android.quickstep.util.ActiveGestureLog
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
@@ -40,6 +42,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
import java.io.PrintWriter
+import java.util.concurrent.ConcurrentLinkedDeque
/** Helper class to handle various atomic commands for switching between Overview. */
class OverviewCommandHelper(
@@ -47,7 +50,7 @@
private val overviewComponentObserver: OverviewComponentObserver,
private val taskAnimationManager: TaskAnimationManager
) {
- private val pendingCommands = mutableListOf<CommandInfo>()
+ private val commandQueue = ConcurrentLinkedDeque<CommandInfo>()
/**
* Index of the TaskView that should be focused when launching Overview. Persisted so that we do
@@ -64,23 +67,39 @@
*/
private var waitForToggleCommandComplete = false
- /** Called when the command finishes execution. */
- private fun scheduleNextTask(command: CommandInfo) {
- if (pendingCommands.isEmpty()) {
- Log.d(TAG, "no pending commands to schedule")
+ private val activityInterface: BaseActivityInterface<*, *>
+ get() = overviewComponentObserver.activityInterface
+
+ private val visibleRecentsView: RecentsView<*, *>?
+ get() = activityInterface.getVisibleRecentsView<RecentsView<*, *>>()
+
+ /**
+ * Adds a command to be executed next, after all pending tasks are completed. Max commands that
+ * can be queued is [.MAX_QUEUE_SIZE]. Requests after reaching that limit will be silently
+ * dropped.
+ */
+ @BinderThread
+ fun addCommand(type: CommandType) {
+ if (commandQueue.size >= MAX_QUEUE_SIZE) {
+ Log.d(TAG, "commands queue is full ($commandQueue). command not added: $type")
return
}
- if (pendingCommands.first() !== command) {
- Log.d(
- TAG,
- "next task not scheduled. First pending command type " +
- "is ${pendingCommands.first()} - command type is: $command"
- )
- return
+
+ val command = CommandInfo(type)
+ commandQueue.add(command)
+ Log.d(TAG, "command added: $command")
+
+ if (commandQueue.size == 1) {
+ Executors.MAIN_EXECUTOR.execute { executeNext() }
}
- Log.d(TAG, "scheduleNextTask called: $command")
- pendingCommands.removeFirst()
- executeNext()
+ }
+
+ fun canStartHomeSafely(): Boolean = commandQueue.isEmpty() || commandQueue.first().type == HOME
+
+ /** Clear pending or completed commands from the queue */
+ fun clearPendingCommands() {
+ Log.d(TAG, "clearing pending commands: $commandQueue")
+ commandQueue.removeAll { it.status != CommandStatus.PROCESSING }
}
/**
@@ -90,67 +109,76 @@
*/
@UiThread
private fun executeNext() {
- if (pendingCommands.isEmpty()) {
- Log.d(TAG, "executeNext - pendingCommands is empty")
- return
- }
- val command = pendingCommands.first()
- val result = executeCommand(command)
- Log.d(TAG, "executeNext command type: $command, result: $result")
- if (result) {
- scheduleNextTask(command)
- }
- }
+ val command: CommandInfo =
+ commandQueue.firstOrNull()
+ ?: run {
+ Log.d(TAG, "no pending commands to be executed.")
+ return
+ }
- @UiThread
- private fun addCommand(command: CommandInfo) {
- val wasEmpty = pendingCommands.isEmpty()
- pendingCommands.add(command)
- if (wasEmpty) {
- executeNext()
+ command.status = CommandStatus.PROCESSING
+ Log.d(TAG, "executing command: $command")
+
+ val result = executeCommand(command)
+ Log.d(TAG, "command executed: $command with result: $result")
+ if (result) {
+ onCommandFinished(command)
+ } else {
+ Log.d(TAG, "waiting for command callback: $command")
}
}
/**
- * Adds a command to be executed next, after all pending tasks are completed. Max commands that
- * can be queued is [.MAX_QUEUE_SIZE]. Requests after reaching that limit will be silently
- * dropped.
+ * Executes the task and returns true if next task can be executed. If false, then the next task
+ * is deferred until [.scheduleNextTask] is called
*/
- @BinderThread
- fun addCommand(type: Int) {
- if (pendingCommands.size >= MAX_QUEUE_SIZE) {
- Log.d(
- TAG,
- "the pending command queue is full (${pendingCommands.size}). command not added: $type"
- )
- return
+ private fun executeCommand(command: CommandInfo): Boolean {
+ if (waitForToggleCommandComplete && command.type == TOGGLE) {
+ Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
+ return true
}
- Log.d(TAG, "adding command type: $type")
- val command = CommandInfo(type)
- Executors.MAIN_EXECUTOR.execute { addCommand(command) }
- }
- @UiThread
- fun clearPendingCommands() {
- Log.d(TAG, "clearing pending commands - size: ${pendingCommands.size}")
- pendingCommands.clear()
- }
-
- @UiThread
- fun canStartHomeSafely(): Boolean =
- pendingCommands.isEmpty() || pendingCommands.first().type == TYPE_HOME
-
- private fun getNextTask(view: RecentsView<*, *>): TaskView? {
- val runningTaskView = view.runningTaskView
-
- return if (runningTaskView == null) {
- view.getTaskViewAt(0)
+ val recentsView = visibleRecentsView
+ Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView")
+ return if (recentsView != null) {
+ executeWhenRecentsIsVisible(command, recentsView)
} else {
- val nextTask = view.nextTaskView
- nextTask ?: runningTaskView
+ executeWhenRecentsIsNotVisible(command)
}
}
+ private fun executeWhenRecentsIsVisible(
+ command: CommandInfo,
+ recentsView: RecentsView<*, *>,
+ ): Boolean =
+ when (command.type) {
+ SHOW -> true // already visible
+ KEYBOARD_INPUT,
+ HIDE -> {
+ if (recentsView.isHandlingTouch) {
+ true
+ } else {
+ keyboardTaskFocusIndex = PagedView.INVALID_PAGE
+ val currentPage = recentsView.nextPage
+ val taskView = recentsView.getTaskViewAt(currentPage)
+ launchTask(recentsView, taskView, command)
+ }
+ }
+ TOGGLE -> {
+ val taskView =
+ if (recentsView.runningTaskView == null) {
+ recentsView.getTaskViewAt(0)
+ } else {
+ recentsView.nextTaskView ?: recentsView.runningTaskView
+ }
+ launchTask(recentsView, taskView, command)
+ }
+ HOME -> {
+ recentsView.startHome()
+ true
+ }
+ }
+
private fun launchTask(
recents: RecentsView<*, *>,
taskView: TaskView?,
@@ -166,7 +194,7 @@
if (callbackList != null) {
callbackList.add {
Log.d(TAG, "launching task callback: $command")
- scheduleNextTask(command)
+ onCommandFinished(command)
waitForToggleCommandComplete = false
}
Log.d(TAG, "launching task - waiting for callback: $command")
@@ -178,94 +206,54 @@
}
}
- /**
- * Executes the task and returns true if next task can be executed. If false, then the next task
- * is deferred until [.scheduleNextTask] is called
- */
- private fun executeCommand(command: CommandInfo): Boolean {
- if (waitForToggleCommandComplete && command.type == TYPE_TOGGLE) {
- Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
- return true
- }
- val activityInterface: BaseActivityInterface<*, *> =
- overviewComponentObserver.activityInterface
+ private fun executeWhenRecentsIsNotVisible(command: CommandInfo): Boolean {
+ val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer
+ val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel()
+ val deviceProfile = recentsViewContainer?.getDeviceProfile()
+ val uiController = activityInterface.getTaskbarController()
+ val allowQuickSwitch =
+ FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() &&
+ uiController != null &&
+ deviceProfile != null &&
+ (deviceProfile.isTablet || deviceProfile.isTwoPanels)
- val visibleRecentsView: RecentsView<*, *>? =
- activityInterface.getVisibleRecentsView<RecentsView<*, *>>()
- val createdRecentsView: RecentsView<*, *>?
-
- Log.d(TAG, "executeCommand: $command - visibleRecentsView: $visibleRecentsView")
- if (visibleRecentsView == null) {
- val activity = activityInterface.getCreatedContainer() as? RecentsViewContainer
- createdRecentsView = activity?.getOverviewPanel()
- val deviceProfile = activity?.getDeviceProfile()
- val uiController = activityInterface.getTaskbarController()
- val allowQuickSwitch =
- FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() &&
- uiController != null &&
- deviceProfile != null &&
- (deviceProfile.isTablet || deviceProfile.isTwoPanels)
-
- when (command.type) {
- TYPE_HIDE -> {
- if (!allowQuickSwitch) return true
- keyboardTaskFocusIndex = uiController!!.launchFocusedTask()
- if (keyboardTaskFocusIndex == -1) return true
- }
- TYPE_KEYBOARD_INPUT ->
- if (allowQuickSwitch) {
- uiController!!.openQuickSwitchView()
- return true
- } else {
- keyboardTaskFocusIndex = 0
- }
- TYPE_HOME -> {
- ActiveGestureLog.INSTANCE.addLog(
- "OverviewCommandHelper.executeCommand(TYPE_HOME)"
- )
- // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
- // we should still call it on main thread because launcher is waiting for
- // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
- // could potentially delay resuming launcher. See b/348668521 for more details.
- touchInteractionService.startActivity(overviewComponentObserver.homeIntent)
+ when (command.type) {
+ HIDE -> {
+ if (!allowQuickSwitch) return true
+ keyboardTaskFocusIndex = uiController!!.launchFocusedTask()
+ if (keyboardTaskFocusIndex == -1) return true
+ }
+ KEYBOARD_INPUT ->
+ if (allowQuickSwitch) {
+ uiController!!.openQuickSwitchView()
return true
- }
- TYPE_SHOW ->
- // When Recents is not currently visible, the command's type is
- // TYPE_SHOW
- // when overview is triggered via the keyboard overview button or Action+Tab
- // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
- // nav is TYPE_TOGGLE.
+ } else {
keyboardTaskFocusIndex = 0
- else -> {}
- }
- } else {
- createdRecentsView = visibleRecentsView
- when (command.type) {
- TYPE_SHOW -> return true // already visible
- TYPE_KEYBOARD_INPUT,
- TYPE_HIDE -> {
- if (visibleRecentsView.isHandlingTouch) return true
-
- keyboardTaskFocusIndex = PagedView.INVALID_PAGE
- val currentPage = visibleRecentsView.nextPage
- val taskView = visibleRecentsView.getTaskViewAt(currentPage)
- return launchTask(visibleRecentsView, taskView, command)
}
- TYPE_TOGGLE ->
- return launchTask(visibleRecentsView, getNextTask(visibleRecentsView), command)
- TYPE_HOME -> {
- visibleRecentsView.startHome()
- return true
- }
+ HOME -> {
+ ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(HOME)")
+ // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
+ // we should still call it on main thread because launcher is waiting for
+ // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
+ // could potentially delay resuming launcher. See b/348668521 for more details.
+ touchInteractionService.startActivity(overviewComponentObserver.homeIntent)
+ return true
}
+ SHOW ->
+ // When Recents is not currently visible, the command's type is SHOW
+ // when overview is triggered via the keyboard overview button or Action+Tab
+ // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
+ // nav is TYPE_TOGGLE.
+ keyboardTaskFocusIndex = 0
+ TOGGLE -> {}
}
- createdRecentsView?.setKeyboardTaskFocusIndex(keyboardTaskFocusIndex)
+ recentsView?.setKeyboardTaskFocusIndex(keyboardTaskFocusIndex)
// Handle recents view focus when launching from home
val animatorListener: Animator.AnimatorListener =
object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
+ Log.d(TAG, "switching to Overview state - onAnimationStart: $command")
super.onAnimationStart(animation)
updateRecentsViewFocus(command)
logShowOverviewFrom(command.type)
@@ -275,7 +263,7 @@
Log.d(TAG, "switching to Overview state - onAnimationEnd: $command")
super.onAnimationEnd(animation)
onRecentsViewFocusUpdated(command)
- scheduleNextTask(command)
+ onCommandFinished(command)
}
}
if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
@@ -311,9 +299,11 @@
controller: RecentsAnimationController,
targets: RecentsAnimationTargets
) {
+ Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
logShowOverviewFrom(command.type)
activityInterface.runOnInitBackgroundStateUI {
+ Log.d(TAG, "recents animation started - onInitBackgroundStateUI: $command")
interactionHandler.onGestureEnded(0f, PointF())
}
command.removeListener(this)
@@ -322,11 +312,12 @@
override fun onRecentsAnimationCanceled(
thumbnailDatas: HashMap<Int, ThumbnailData>
) {
+ Log.d(TAG, "recents animation canceled: $command")
interactionHandler.onGestureCancelled()
command.removeListener(this)
activityInterface.getCreatedContainer() ?: return
- createdRecentsView?.onRecentsAnimationComplete()
+ recentsView?.onRecentsAnimationComplete()
}
}
@@ -347,7 +338,7 @@
taskAnimationManager.notifyRecentsAnimationState(recentAnimListener)
} else {
val intent =
- Intent(interactionHandler.launchIntent)
+ Intent(interactionHandler.getLaunchIntent())
.putExtra(ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID, gestureState.gestureId)
command.setAnimationCallbacks(
taskAnimationManager.startRecentsAnimation(gestureState, intent, interactionHandler)
@@ -365,17 +356,29 @@
command.removeListener(handler)
Trace.endAsyncSection(TRANSITION_NAME, 0)
onRecentsViewFocusUpdated(command)
- scheduleNextTask(command)
+ onCommandFinished(command)
+ }
+
+ /** Called when the command finishes execution. */
+ private fun onCommandFinished(command: CommandInfo) {
+ command.status = CommandStatus.COMPLETED
+ if (commandQueue.first() !== command) {
+ Log.d(
+ TAG,
+ "next task not scheduled. First pending command type " +
+ "is ${commandQueue.first()} - command type is: $command"
+ )
+ return
+ }
+
+ Log.d(TAG, "command executed successfully! $command")
+ commandQueue.remove(command)
+ executeNext()
}
private fun updateRecentsViewFocus(command: CommandInfo) {
- val recentsView: RecentsView<*, *> =
- overviewComponentObserver.activityInterface.getVisibleRecentsView() ?: return
- if (
- command.type != TYPE_KEYBOARD_INPUT &&
- command.type != TYPE_HIDE &&
- command.type != TYPE_SHOW
- ) {
+ val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+ if (command.type != KEYBOARD_INPUT && command.type != HIDE && command.type != SHOW) {
return
}
@@ -387,16 +390,16 @@
// here we launch overview with live tile.
recentsView.viewRootImpl.touchModeChanged(false)
// Ensure that recents view has focus so that it receives the followup key inputs
- if (requestFocus(recentsView.getTaskViewAt(keyboardTaskFocusIndex))) return
- if (requestFocus(recentsView.nextTaskView)) return
- if (requestFocus(recentsView.getTaskViewAt(0))) return
- requestFocus(recentsView)
+ // Stops requesting focused after first view gets focused.
+ recentsView.getTaskViewAt(keyboardTaskFocusIndex).requestFocus() ||
+ recentsView.nextTaskView.requestFocus() ||
+ recentsView.getTaskViewAt(0).requestFocus() ||
+ recentsView.requestFocus()
}
private fun onRecentsViewFocusUpdated(command: CommandInfo) {
- val recentsView: RecentsView<*, *> =
- overviewComponentObserver.activityInterface.getVisibleRecentsView() ?: return
- if (command.type != TYPE_HIDE || keyboardTaskFocusIndex == PagedView.INVALID_PAGE) {
+ val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+ if (command.type != HIDE || keyboardTaskFocusIndex == PagedView.INVALID_PAGE) {
return
}
recentsView.setKeyboardTaskFocusIndex(PagedView.INVALID_PAGE)
@@ -404,24 +407,22 @@
keyboardTaskFocusIndex = PagedView.INVALID_PAGE
}
- private fun requestFocus(taskView: View?): Boolean {
- if (taskView == null) return false
- taskView.post {
- taskView.requestFocus()
- taskView.requestAccessibilityFocus()
+ private fun View?.requestFocus(): Boolean {
+ if (this == null) return false
+ post {
+ requestFocus()
+ requestAccessibilityFocus()
}
return true
}
- private fun logShowOverviewFrom(commandType: Int) {
- val activityInterface: BaseActivityInterface<*, *> =
- overviewComponentObserver.activityInterface
+ private fun logShowOverviewFrom(commandType: CommandType) {
val container = activityInterface.getCreatedContainer() as? RecentsViewContainer ?: return
val event =
when (commandType) {
- TYPE_SHOW -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
- TYPE_HIDE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
- TYPE_TOGGLE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
+ SHOW -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
+ HIDE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
+ TOGGLE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
else -> return
}
StatsLogManager.newInstance(container.asContext())
@@ -438,16 +439,17 @@
fun dump(pw: PrintWriter) {
pw.println("OverviewCommandHelper:")
- pw.println(" pendingCommands=${pendingCommands.size}")
- if (pendingCommands.isNotEmpty()) {
- pw.println(" pendingCommandType=${pendingCommands.first().type}")
+ pw.println(" pendingCommands=${commandQueue.size}")
+ if (commandQueue.isNotEmpty()) {
+ pw.println(" pendingCommandType=${commandQueue.first().type}")
}
- pw.println(" mKeyboardTaskFocusIndex=$keyboardTaskFocusIndex")
- pw.println(" mWaitForToggleCommandComplete=$waitForToggleCommandComplete")
+ pw.println(" keyboardTaskFocusIndex=$keyboardTaskFocusIndex")
+ pw.println(" waitForToggleCommandComplete=$waitForToggleCommandComplete")
}
private data class CommandInfo(
- val type: Int,
+ val type: CommandType,
+ var status: CommandStatus = CommandStatus.IDLE,
val createTime: Long = SystemClock.elapsedRealtime(),
private var animationCallbacks: RecentsAnimationCallbacks? = null
) {
@@ -462,23 +464,30 @@
fun removeListener(listener: RecentsAnimationCallbacks.RecentsAnimationListener?) {
animationCallbacks?.removeListener(listener)
}
+
+ enum class CommandStatus {
+ IDLE,
+ PROCESSING,
+ COMPLETED
+ }
+ }
+
+ enum class CommandType {
+ SHOW,
+ KEYBOARD_INPUT,
+ HIDE,
+ TOGGLE, // Navigate to Overview
+ HOME, // Navigate to Home
}
companion object {
private const val TAG = "OverviewCommandHelper"
-
- const val TYPE_SHOW: Int = 1
- const val TYPE_KEYBOARD_INPUT: Int = 2
- const val TYPE_HIDE: Int = 3
- const val TYPE_TOGGLE: Int = 4
- const val TYPE_HOME: Int = 5
+ private const val TRANSITION_NAME = "Transition:toOverview"
/**
* Use case for needing a queue is double tapping recents button in 3 button nav. Size of 2
* should be enough. We'll toss in one more because we're kind hearted.
*/
private const val MAX_QUEUE_SIZE = 3
-
- private const val TRANSITION_NAME = "Transition:toOverview"
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 32e2389..7b9b560 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -54,17 +54,14 @@
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
private final SystemUiProxy mSystemUiProxy;
- private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
private RecentsAnimationController mController;
private boolean mCancelled;
- public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
- boolean allowMinimizeSplitScreen) {
+ public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy) {
mSystemUiProxy = systemUiProxy;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@UiThread
@@ -122,7 +119,7 @@
}
mController = new RecentsAnimationController(animationController,
- mAllowMinimizeSplitScreen, this::onAnimationFinished);
+ this::onAnimationFinished);
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
mController::finishAnimationToApp);
@@ -219,7 +216,6 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationCallbacks:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmCancelled=" + mCancelled);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 1b05e28..adcf4ef 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
import android.content.Context;
@@ -52,21 +51,17 @@
private static final String TAG = "RecentsAnimationController";
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationController> mOnFinishedListener;
- private final boolean mAllowMinimizeSplitScreen;
private boolean mUseLauncherSysBarFlags = false;
- private boolean mSplitScreenMinimized = false;
private boolean mFinishRequested = false;
// Only valid when mFinishRequested == true.
private boolean mFinishTargetIsLauncher;
private RunnableList mPendingFinishCallbacks = new RunnableList();
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
- boolean allowMinimizeSplitScreen,
Consumer<RecentsAnimationController> onFinishedListener) {
mController = controller;
mOnFinishedListener = onFinishedListener;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
/**
@@ -85,34 +80,17 @@
if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
mUseLauncherSysBarFlags = useLauncherSysBarFlags;
UI_HELPER_EXECUTOR.execute(() -> {
- if (!ENABLE_SHELL_TRANSITIONS) {
- mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
- } else {
- try {
- WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
- useLauncherSysBarFlags);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to reach window manager", e);
- }
+ try {
+ WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+ useLauncherSysBarFlags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
}
});
}
}
/**
- * Indicates that the gesture has crossed the window boundary threshold and we should minimize
- * if we are in splitscreen.
- */
- public void setSplitScreenMinimized(Context context, boolean splitScreenMinimized) {
- if (!mAllowMinimizeSplitScreen) {
- return;
- }
- if (mSplitScreenMinimized != splitScreenMinimized) {
- mSplitScreenMinimized = splitScreenMinimized;
- }
- }
-
- /**
* Remove task remote animation target from
* {@link RecentsAnimationCallbacks#onTasksAppeared}}.
*/
@@ -272,9 +250,7 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationController:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
- pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 4392255..dde16c8 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -81,7 +81,6 @@
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.bubbles.IBubbles;
import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.common.pip.IPip;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.desktopmode.IDesktopMode;
@@ -92,6 +91,7 @@
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.IShellTransitions;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 85eea3b..49ec597 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -60,9 +60,8 @@
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
- public static final boolean ENABLE_SHELL_TRANSITIONS = true;
- public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
- && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
+ public static final boolean SHELL_TRANSITIONS_ROTATION =
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
private RecentsAnimationController mController;
@@ -160,8 +159,7 @@
final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
mLastGestureState = gestureState;
- RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
- getSystemUiProxy(), containerInterface.allowMinimizeSplitScreen());
+ RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(getSystemUiProxy());
mCallbacks = newCallbacks;
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
@@ -191,7 +189,7 @@
}
mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
- if (ENABLE_SHELL_TRANSITIONS && mTargets.hasRecents
+ if (mTargets.hasRecents
// The filtered (MODE_CLOSING) targets only contain 1 home activity.
&& mTargets.apps.length == 1
&& mTargets.apps[0].windowConfiguration.getActivityType()
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b321b3e..4587bdd 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -109,6 +109,7 @@
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
@@ -246,7 +247,7 @@
return;
}
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
});
}
@@ -256,10 +257,9 @@
executeForTouchInteractionService(tis -> {
if (triggeredFromAltTab) {
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- tis.mOverviewCommandHelper.addCommand(
- OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
+ tis.mOverviewCommandHelper.addCommand(CommandType.KEYBOARD_INPUT);
} else {
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
+ tis.mOverviewCommandHelper.addCommand(CommandType.SHOW);
}
});
}
@@ -270,7 +270,7 @@
executeForTouchInteractionService(tis -> {
if (triggeredFromAltTab && !triggeredFromHomeKey) {
// onOverviewShownFromAltTab hides the overview and ends at the target app
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE);
+ tis.mOverviewCommandHelper.addCommand(CommandType.HIDE);
}
});
}
@@ -595,12 +595,12 @@
private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
@Override
public void onNavigateHome() {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+ mOverviewCommandHelper.addCommand(CommandType.HOME);
}
@Override
public void onToggleOverview() {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
}
};
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 14f47d1..b66d4cb 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -24,7 +24,6 @@
import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.animation.Animator;
@@ -212,15 +211,13 @@
// This will come back and cancel the interaction.
startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
mHomeLaunched = true;
- } else if (ENABLE_SHELL_TRANSITIONS) {
- if (mTaskAnimationManager.getCurrentCallbacks() != null) {
- if (mRecentsAnimationController != null) {
- finishRecentsAnimationForShell(dismissTask);
- } else {
- // the transition of recents animation hasn't started, wait for it
- mCancelWhenRecentsStart = true;
- mDismissTask = dismissTask;
- }
+ } else if (mTaskAnimationManager.getCurrentCallbacks() != null) {
+ if (mRecentsAnimationController != null) {
+ finishRecentsAnimationForShell(dismissTask);
+ } else {
+ // the transition of recents animation hasn't started, wait for it
+ mCancelWhenRecentsStart = true;
+ mDismissTask = dismissTask;
}
}
mStateCallback.setState(STATE_HANDLER_INVALIDATED);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 17a97fa..9284e13 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -46,6 +46,7 @@
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.systemui.shared.system.InputMonitorCompat;
/**
@@ -200,7 +201,7 @@
break;
case MotionEvent.ACTION_BUTTON_RELEASE:
if (isStashedTaskbarHovered) {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+ mOverviewCommandHelper.addCommand(CommandType.HOME);
}
break;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 36ea926..acc9959 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -41,6 +41,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.interaction.TutorialController.TutorialType;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.TISBindHelper;
import java.util.ArrayList;
@@ -54,8 +55,6 @@
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
static final String KEY_GESTURE_COMPLETE = "gesture_complete";
static final String KEY_USE_TUTORIAL_MENU = "use_tutorial_menu";
- public static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
- public static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
@Nullable private TutorialType[] mTutorialSteps;
private GestureSandboxFragment mCurrentFragment;
@@ -170,10 +169,7 @@
getApplicationContext()).getDeviceProfile(this);
if (deviceProfile.isTablet) {
// The tutorial will work in either orientation if the height and width are similar
- boolean isAspectRatioSquare =
- deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
- && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND;
- boolean showRotationPrompt = !isAspectRatioSquare
+ boolean showRotationPrompt = !LayoutUtils.isAspectRatioSquare(deviceProfile.aspectRatio)
&& getResources().getConfiguration().orientation
== ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index ec04cb7..658975c 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -37,6 +37,7 @@
import androidx.annotation.VisibleForTesting
import androidx.core.util.component1
import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags
import com.android.launcher3.LauncherAnimUtils
@@ -242,7 +243,30 @@
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
}
- override fun getDwbLayoutTranslations(
+ override fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ ) {
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+ banner.updateLayoutParams<FrameLayout.LayoutParams> {
+ gravity = Gravity.TOP or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+ width =
+ if (isGroupedTaskView) {
+ snapshotViewHeight
+ } else {
+ taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+ }
+ }
+ }
+
+ override fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitBounds?,
@@ -252,39 +276,25 @@
banner: View
): Pair<Float, Float> {
val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
- val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
val translationX = banner.height.toFloat()
-
- val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
- bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START
- banner.pivotX = 0f
- banner.pivotY = 0f
- banner.rotation = degreesRotated
-
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin
- return Pair(translationX, snapshotParams.topMargin.toFloat())
- }
-
- // Set correct width and translations
val translationY: Float
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].measuredHeight
+ if (splitBounds == null) {
translationY = snapshotParams.topMargin.toFloat()
} else {
- bannerParams.width = thumbnailViews[1].measuredHeight
- val topLeftTaskPlusDividerPercent =
- if (splitBounds.appsStackedVertically) {
- splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
- } else {
- splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
- }
- translationY =
- snapshotParams.topMargin +
- (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ translationY = snapshotParams.topMargin.toFloat()
+ } else {
+ val topLeftTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
+ } else {
+ splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
+ }
+ translationY =
+ snapshotParams.topMargin +
+ (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+ }
}
-
return Pair(translationX, translationY)
}
@@ -300,6 +310,7 @@
if (isRtl) displacement < 0 else displacement > 0
override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1
+
/* -------------------- */
override fun getChildBounds(
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index eeacee1..32d9052 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -243,54 +243,54 @@
}
@Override
- public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
- int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
- View[] thumbnailViews, int desiredTaskId, View banner) {
- float translationX = 0;
- float translationY = 0;
+ public void updateDwbBannerLayout(int taskViewWidth, int taskViewHeight,
+ boolean isGroupedTaskView, @NonNull DeviceProfile deviceProfile,
+ int snapshotViewWidth, int snapshotViewHeight, @NonNull View banner) {
FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
banner.setPivotX(0);
banner.setPivotY(0);
banner.setRotation(getDegreesRotated());
- if (splitBounds == null) {
- // Single, fullscreen case
+ if (isGroupedTaskView) {
+ bannerParams.gravity =
+ BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
+ bannerParams.width = snapshotViewWidth;
+ } else {
bannerParams.width = MATCH_PARENT;
bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL;
- return new Pair<>(translationX, translationY);
}
+ banner.setLayoutParams(bannerParams);
+ }
- bannerParams.gravity =
- BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
-
- // Set correct width
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].getMeasuredWidth();
- } else {
- bannerParams.width = thumbnailViews[1].getMeasuredWidth();
- }
-
- // Set translations
- if (deviceProfile.isLeftRightSplit) {
- if (desiredTaskId == splitBounds.rightBottomTaskId) {
- float leftTopTaskPercent = splitBounds.appsStackedVertically
- ? splitBounds.topTaskPercent
- : splitBounds.leftTaskPercent;
- float dividerThicknessPercent = splitBounds.appsStackedVertically
- ? splitBounds.dividerHeightPercent
- : splitBounds.dividerWidthPercent;
- translationX = ((taskViewWidth * leftTopTaskPercent)
- + (taskViewWidth * dividerThicknessPercent));
- }
- } else {
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) thumbnailViews[0]
- .getLayoutParams();
- float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (1f - splitBounds.topTaskPercent)
- : (1f - splitBounds.leftTaskPercent);
- translationY = -((taskViewHeight - snapshotParams.topMargin)
- * bottomRightTaskPlusDividerPercent);
+ @NonNull
+ @Override
+ public Pair<Float, Float> getDwbBannerTranslations(int taskViewWidth,
+ int taskViewHeight, SplitBounds splitBounds, @NonNull DeviceProfile deviceProfile,
+ @NonNull View[] thumbnailViews, int desiredTaskId, @NonNull View banner) {
+ float translationX = 0;
+ float translationY = 0;
+ if (splitBounds != null) {
+ if (deviceProfile.isLeftRightSplit) {
+ if (desiredTaskId == splitBounds.rightBottomTaskId) {
+ float leftTopTaskPercent = splitBounds.appsStackedVertically
+ ? splitBounds.topTaskPercent
+ : splitBounds.leftTaskPercent;
+ float dividerThicknessPercent = splitBounds.appsStackedVertically
+ ? splitBounds.dividerHeightPercent
+ : splitBounds.dividerWidthPercent;
+ translationX = ((taskViewWidth * leftTopTaskPercent)
+ + (taskViewWidth * dividerThicknessPercent));
+ }
+ } else {
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ FrameLayout.LayoutParams snapshotParams =
+ (FrameLayout.LayoutParams) thumbnailViews[0]
+ .getLayoutParams();
+ float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
+ ? (1f - splitBounds.topTaskPercent)
+ : (1f - splitBounds.leftTaskPercent);
+ translationY = -((taskViewHeight - snapshotParams.topMargin)
+ * bottomRightTaskPlusDividerPercent);
+ }
}
}
return new Pair<>(translationX, translationY);
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index df4b030..06a0685 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -199,6 +199,7 @@
parentWidth: Int,
parentHeight: Int
): Pair<Point, Point>
+
// Overview TaskMenuView methods
/** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
fun setTaskIconParams(
@@ -294,13 +295,24 @@
deviceProfile: DeviceProfile
)
+ /** Layout a Digital Wellbeing Banner on its parent. TaskView. */
+ fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ )
+
/**
- * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+ * Calculates the translations where a Digital Wellbeing Banner should be apply on its parent
* TaskView.
*
* @return A Pair of Floats representing the proper x and y translations.
*/
- fun getDwbLayoutTranslations(
+ fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitConfigurationOptions.SplitBounds?,
@@ -309,6 +321,7 @@
desiredTaskId: Int,
banner: View
): Pair<Float, Float>
+
// The following are only used by TaskViewTouchHandler.
/** @return Either VERTICAL or HORIZONTAL. */
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index 333359f..a972e8c 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -28,6 +28,7 @@
import android.widget.FrameLayout
import androidx.core.util.component1
import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags
import com.android.launcher3.R
@@ -125,7 +126,30 @@
}
}
- override fun getDwbLayoutTranslations(
+ override fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ ) {
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+ banner.updateLayoutParams<FrameLayout.LayoutParams> {
+ gravity = Gravity.BOTTOM or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+ width =
+ if (isGroupedTaskView) {
+ snapshotViewHeight
+ } else {
+ taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+ }
+ }
+ }
+
+ override fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitBounds?,
@@ -135,39 +159,26 @@
banner: View
): Pair<Float, Float> {
val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
- val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
-
- val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
- bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START
- banner.pivotX = 0f
- banner.pivotY = 0f
- banner.rotation = degreesRotated
-
val translationX: Float = (taskViewWidth - banner.height).toFloat()
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin
- return Pair(translationX, banner.height.toFloat())
- }
-
- // Set correct width and translations
val translationY: Float
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].measuredHeight
- val bottomRightTaskPlusDividerPercent =
- if (splitBounds.appsStackedVertically) {
- 1f - splitBounds.topTaskPercent
- } else {
- 1f - splitBounds.leftTaskPercent
- }
- translationY =
- banner.height -
- (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent
- } else {
- bannerParams.width = thumbnailViews[1].measuredHeight
+ if (splitBounds == null) {
translationY = banner.height.toFloat()
+ } else {
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ val bottomRightTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ 1f - splitBounds.topTaskPercent
+ } else {
+ 1f - splitBounds.leftTaskPercent
+ }
+ translationY =
+ banner.height -
+ (taskViewHeight - snapshotParams.topMargin) *
+ bottomRightTaskPlusDividerPercent
+ } else {
+ translationY = banner.height.toFloat()
+ }
}
-
return Pair(translationX, translationY)
}
@@ -339,6 +350,7 @@
if (isRtl) displacement > 0 else displacement < 0
override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1
+
/* -------------------- */
override fun getSplitIconsPosition(
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ec1eeb1..b9338a3 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -28,6 +28,8 @@
public class LayoutUtils {
+ private static final float SQUARE_ASPECT_RATIO_TOLERANCE = 0.05f;
+
/**
* The height for the swipe up motion
*/
@@ -61,4 +63,13 @@
}
}
}
+
+ /**
+ * Returns true iff the device's aspect ratio is within
+ * {@link LayoutUtils#SQUARE_ASPECT_RATIO_TOLERANCE} of 1:1
+ */
+ public static boolean isAspectRatioSquare(float aspectRatio) {
+ return Float.compare(aspectRatio, 1f - SQUARE_ASPECT_RATIO_TOLERANCE) >= 0
+ && Float.compare(aspectRatio, 1f + SQUARE_ASPECT_RATIO_TOLERANCE) <= 0;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
index 0a01d8b..cf08391 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
@@ -17,9 +17,11 @@
package com.android.quickstep.util
import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.quickstep.RecentsAnimationController
import com.android.quickstep.views.DesktopTaskView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.ThumbnailData
/**
* Helper class for [com.android.quickstep.views.RecentsView]. This util class contains refactored
@@ -68,4 +70,12 @@
if (taskView?.isLargeTile == true) taskView else null
}
}
+
+ fun screenshotTasks(
+ taskView: TaskView,
+ recentsAnimationController: RecentsAnimationController
+ ): Map<Int, ThumbnailData> =
+ taskView.taskContainers.associate {
+ it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index ae6757f..1af12f1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -886,8 +886,7 @@
Log.w(TAG, "Package not found: " + packageName, e);
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
DesktopSplitRecentsAnimationListener listener =
new DesktopSplitRecentsAnimationListener(splitPosition, taskBounds);
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 1c417eb..4c6e4ff 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -84,8 +84,7 @@
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
SplitWithKeyboardShortcutRecentsAnimationListener listener =
new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop);
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index e5c54bb..c7777d8 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
@@ -535,21 +534,12 @@
// If mDrawsBelowRecents is unset, no reordering will be enforced.
if (mDrawsBelowRecents != null) {
- // In legacy transitions, the animation leashes remain in same hierarchy in the
- // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will
- // conflict with layers that WM core positions (ie. the input consumers). For shell
- // transitions, the animation leashes are reparented to an animation container so we
- // can bump layers as needed.
- if (ENABLE_SHELL_TRANSITIONS) {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- // 1000 is an arbitrary number to give room for multiple layers.
- : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
- } else {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- : 0);
- }
+ // In shell transitions, the animation leashes are reparented to an animation container
+ // so we can bump layers as needed.
+ builder.setLayer(mDrawsBelowRecents
+ ? Integer.MIN_VALUE + app.prefixOrderIndex
+ // 1000 is an arbitrary number to give room for multiple layers.
+ : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
index 0ab36c9..f0fdd81 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
@@ -15,8 +15,10 @@
*/
package com.android.quickstep.views
+import android.annotation.SuppressLint
import android.app.ActivityOptions
import android.content.ActivityNotFoundException
+import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.content.pm.LauncherApps.AppUsageLimit
@@ -27,46 +29,58 @@
import android.icu.util.MeasureUnit
import android.os.UserHandle
import android.provider.Settings
+import android.util.AttributeSet
import android.util.Log
import android.view.View
-import android.view.ViewGroup.MarginLayoutParams
import android.view.ViewOutlineProvider
import android.view.accessibility.AccessibilityNodeInfo
-import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
import androidx.core.util.component1
import androidx.core.util.component2
-import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.util.Executors
import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
import com.android.quickstep.TaskUtils
import com.android.systemui.shared.recents.model.Task
import java.time.Duration
import java.util.Locale
-class DigitalWellBeingToast(
- private val container: RecentsViewContainer,
- private val taskView: TaskView
-) {
- private val launcherApps: LauncherApps? =
- container.asContext().getSystemService(LauncherApps::class.java)
+@SuppressLint("AppCompatCustomView")
+class DigitalWellBeingToast
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+ private val recentsViewContainer =
+ RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+
+ private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java)
private val bannerHeight =
- container
- .asContext()
- .resources
- .getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height)
+ context.resources.getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height)
private lateinit var task: Task
+ private lateinit var taskView: TaskView
+ private lateinit var snapshotView: View
+ @StagePosition private var stagePosition = STAGE_POSITION_UNDEFINED
private var appRemainingTimeMs: Long = 0
- private var banner: View? = null
- private var oldBannerOutlineProvider: ViewOutlineProvider? = null
private var splitOffsetTranslationY = 0f
- private var splitOffsetTranslationX = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+ updateTranslationY()
+ }
+ }
private var isDestroyed = false
@@ -76,65 +90,63 @@
set(value) {
if (field != value) {
field = value
- banner?.let {
- updateTranslationY()
- it.invalidateOutline()
- }
+ updateTranslationY()
}
}
+ init {
+ setOnClickListener(::openAppUsageSettings)
+ outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ BACKGROUND.getOutline(view, outline)
+ val verticalTranslation = splitOffsetTranslationY - translationY
+ outline.offset(0, Math.round(verticalTranslation))
+ }
+ }
+ clipToOutline = true
+ }
+
private fun setNoLimit() {
hasLimit = false
- taskView.contentDescription = task.titleDescription
- replaceBanner(null)
+ setContentDescription(appUsageLimitTimeMs = -1, appRemainingTimeMs = -1)
+ visibility = INVISIBLE
appRemainingTimeMs = -1
}
private fun setLimit(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
this.appRemainingTimeMs = appRemainingTimeMs
hasLimit = true
- val toast =
- container.viewCache
- .getView<TextView>(
- R.layout.digital_wellbeing_toast,
- container.asContext(),
- taskView
- )
- .apply {
- text =
- Utilities.prefixTextWithIcon(
- container.asContext(),
- R.drawable.ic_hourglass_top,
- getBannerText()
- )
- setOnClickListener(::openAppUsageSettings)
- }
- replaceBanner(toast)
-
- taskView.contentDescription =
- getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs)
+ text = Utilities.prefixTextWithIcon(context, R.drawable.ic_hourglass_top, getBannerText())
+ visibility = VISIBLE
+ setContentDescription(appUsageLimitTimeMs, appRemainingTimeMs)
}
- fun initialize(task: Task) {
+ private fun setContentDescription(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
+ val contentDescription =
+ getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs)
+ snapshotView.contentDescription = contentDescription
+ }
+
+ fun initialize() {
check(!isDestroyed) { "Cannot re-initialize a destroyed toast" }
- this.task = task
+ setupTranslations()
Executors.ORDERED_BG_EXECUTOR.execute {
var usageLimit: AppUsageLimit? = null
try {
usageLimit =
launcherApps?.getAppUsageLimit(
- this.task.topComponent.packageName,
- UserHandle.of(this.task.key.userId)
+ task.topComponent.packageName,
+ UserHandle.of(task.key.userId)
)
} catch (e: Exception) {
Log.e(TAG, "Error initializing digital well being toast", e)
}
val appUsageLimitTimeMs = usageLimit?.totalUsageLimit ?: -1
val appRemainingTimeMs = usageLimit?.usageRemaining ?: -1
+
taskView.post {
- if (isDestroyed) {
- return@post
- }
+ if (isDestroyed) return@post
if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
setNoLimit()
} else {
@@ -144,20 +156,36 @@
}
}
- /** Mark the DWB toast as destroyed and remove banner from TaskView. */
+ /** Bind the DWB toast to its dependencies. */
+ fun bind(
+ task: Task,
+ taskView: TaskView,
+ snapshotView: View,
+ @StagePosition stagePosition: Int
+ ) {
+ this.task = task
+ this.taskView = taskView
+ this.snapshotView = snapshotView
+ this.stagePosition = stagePosition
+ isDestroyed = false
+ }
+
+ /** Mark the DWB toast as destroyed and hide it. */
fun destroy() {
+ visibility = INVISIBLE
isDestroyed = true
- taskView.post { replaceBanner(null) }
}
private fun getSplitBannerConfig(): SplitBannerConfig {
val splitBounds = splitBounds
return when {
- splitBounds == null || !container.deviceProfile.isTablet || taskView.isLargeTile ->
- SplitBannerConfig.SPLIT_BANNER_FULLSCREEN
+ splitBounds == null ||
+ !recentsViewContainer.deviceProfile.isTablet ||
+ taskView.isLargeTile -> SplitBannerConfig.SPLIT_BANNER_FULLSCREEN
// For portrait grid only height of task changes, not width. So we keep the text the
// same
- !container.deviceProfile.isLeftRightSplit -> SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+ !recentsViewContainer.deviceProfile.isLeftRightSplit ->
+ SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
// For landscape grid, for 30% width we only show icon, otherwise show icon and time
task.key.id == splitBounds.leftTopTaskId ->
if (splitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY)
@@ -193,8 +221,7 @@
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(minutes, MeasureUnit.MINUTE))
// Use a specific string for usage less than one minute but non-zero.
- duration > Duration.ZERO ->
- container.asContext().getString(durationLessThanOneMinuteStringId)
+ duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId)
// Otherwise, return 0-minute string.
else ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
@@ -208,6 +235,7 @@
* [.SPLIT_BANNER_FULLSCREEN]
*/
@JvmOverloads
+ @VisibleForTesting
fun getBannerText(
remainingTime: Long = appRemainingTimeMs,
forContentDesc: Boolean = false
@@ -226,7 +254,7 @@
val splitBannerConfig = getSplitBannerConfig()
return when {
forContentDesc || splitBannerConfig == SplitBannerConfig.SPLIT_BANNER_FULLSCREEN ->
- container.asContext().getString(R.string.time_left_for_app, readableDuration)
+ context.getString(R.string.time_left_for_app, readableDuration)
// show no text
splitBannerConfig == SplitBannerConfig.SPLIT_GRID_BANNER_SMALL -> ""
// SPLIT_GRID_BANNER_LARGE only show time
@@ -241,7 +269,7 @@
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
try {
val options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.width, view.height)
- container.asContext().startActivity(intent, options.toBundle())
+ context.startActivity(intent, options.toBundle())
// TODO: add WW logging on the app usage settings click.
} catch (e: ActivityNotFoundException) {
@@ -259,99 +287,77 @@
appRemainingTimeMs: Long
): String? =
if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0)
- container
- .asContext()
- .getString(
- R.string.task_contents_description_with_remaining_time,
- task.titleDescription,
- getBannerText(appRemainingTimeMs, true /* forContentDesc */)
- )
+ context.getString(
+ R.string.task_contents_description_with_remaining_time,
+ task.titleDescription,
+ getBannerText(appRemainingTimeMs, true /* forContentDesc */)
+ )
else task.titleDescription
- private fun replaceBanner(view: View?) {
- resetOldBanner()
- setBanner(view)
- }
-
- private fun resetOldBanner() {
- val banner = banner ?: return
- banner.outlineProvider = oldBannerOutlineProvider
- taskView.removeView(banner)
- banner.setOnClickListener(null)
- container.viewCache.recycleView(R.layout.digital_wellbeing_toast, banner)
- }
-
- private fun setBanner(banner: View?) {
- this.banner = banner
- if (banner != null && taskView.recentsView != null) {
- setupAndAddBanner()
- setBannerOutline()
+ fun setupLayout() {
+ val snapshotWidth: Int
+ val snapshotHeight: Int
+ val splitBounds = splitBounds
+ if (splitBounds == null) {
+ snapshotWidth = taskView.layoutParams.width
+ snapshotHeight =
+ taskView.layoutParams.height -
+ recentsViewContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+ } else {
+ val groupedTaskSize =
+ taskView.pagedOrientationHandler.getGroupedTaskViewSizes(
+ recentsViewContainer.deviceProfile,
+ splitBounds,
+ taskView.layoutParams.width,
+ taskView.layoutParams.height
+ )
+ if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ snapshotWidth = groupedTaskSize.first.x
+ snapshotHeight = groupedTaskSize.first.y
+ } else {
+ snapshotWidth = groupedTaskSize.second.x
+ snapshotHeight = groupedTaskSize.second.y
+ }
}
+ taskView.pagedOrientationHandler.updateDwbBannerLayout(
+ taskView.layoutParams.width,
+ taskView.layoutParams.height,
+ taskView is GroupedTaskView,
+ recentsViewContainer.deviceProfile,
+ snapshotWidth,
+ snapshotHeight,
+ this
+ )
}
- private fun setupAndAddBanner() {
- val banner = banner ?: return
- banner.updateLayoutParams<FrameLayout.LayoutParams> {
- bottomMargin =
- (taskView.firstSnapshotView.layoutParams as MarginLayoutParams).bottomMargin
- }
+ private fun setupTranslations() {
val (translationX, translationY) =
- taskView.pagedOrientationHandler.getDwbLayoutTranslations(
- taskView.measuredWidth,
- taskView.measuredHeight,
+ taskView.pagedOrientationHandler.getDwbBannerTranslations(
+ taskView.layoutParams.width,
+ taskView.layoutParams.height,
splitBounds,
- container.deviceProfile,
+ recentsViewContainer.deviceProfile,
taskView.snapshotViews,
task.key.id,
- banner
+ this
)
- splitOffsetTranslationX = translationX
- splitOffsetTranslationY = translationY
- updateTranslationY()
- updateTranslationX()
- taskView.addView(banner)
- }
-
- private fun setBannerOutline() {
- val banner = banner ?: return
- // TODO(b\273367585) to investigate why mBanner.getOutlineProvider() can be null
- val oldBannerOutlineProvider =
- if (banner.outlineProvider != null) banner.outlineProvider
- else ViewOutlineProvider.BACKGROUND
- this.oldBannerOutlineProvider = oldBannerOutlineProvider
-
- banner.outlineProvider =
- object : ViewOutlineProvider() {
- override fun getOutline(view: View, outline: Outline) {
- oldBannerOutlineProvider.getOutline(view, outline)
- val verticalTranslation = -view.translationY + splitOffsetTranslationY
- outline.offset(0, Math.round(verticalTranslation))
- }
- }
- banner.clipToOutline = true
+ this.translationX = translationX
+ this.splitOffsetTranslationY = translationY
}
private fun updateTranslationY() {
- banner?.translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY
+ translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY
+ invalidateOutline()
}
- private fun updateTranslationX() {
- banner?.translationX = splitOffsetTranslationX
- }
-
- fun setBannerColorTint(color: Int, amount: Float) {
- val banner = banner ?: return
+ fun setColorTint(color: Int, amount: Float) {
if (amount == 0f) {
- banner.setLayerType(View.LAYER_TYPE_NONE, null)
+ setLayerType(View.LAYER_TYPE_NONE, null)
}
val layerPaint = Paint()
layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount))
- banner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint)
- banner.setLayerPaint(layerPaint)
- }
-
- fun setBannerVisibility(visibility: Int) {
- banner?.visibility = visibility
+ setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint)
+ setLayerPaint(layerPaint)
}
private fun getAccessibilityActionId(): Int =
@@ -361,9 +367,8 @@
fun getDWBAccessibilityAction(): AccessibilityNodeInfo.AccessibilityAction? {
if (!hasLimit) return null
- val context = container.asContext()
val label =
- if ((taskView.containsMultipleTasks()))
+ if (taskView.containsMultipleTasks())
context.getString(
R.string.split_app_usage_settings,
TaskUtils.getTitle(context, task)
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index ba4d786..4fae01e 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -115,6 +115,7 @@
R.id.snapshot,
R.id.icon,
R.id.show_windows,
+ R.id.digital_wellbeing_toast,
STAGE_POSITION_TOP_OR_LEFT,
taskOverlayFactory
),
@@ -123,6 +124,7 @@
R.id.bottomright_snapshot,
R.id.bottomRight_icon,
R.id.show_windows_right,
+ R.id.bottomRight_digital_wellbeing_toast,
STAGE_POSITION_BOTTOM_OR_RIGHT,
taskOverlayFactory
)
@@ -211,7 +213,7 @@
splitBoundsConfig = splitBounds
taskContainers.forEach {
it.digitalWellBeingToast?.splitBounds = splitBoundsConfig
- it.digitalWellBeingToast?.initialize(it.task)
+ it.digitalWellBeingToast?.initialize()
}
invalidate()
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 255619a..226ecf5 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3058,14 +3058,15 @@
}
private void setRunningTaskViewShowScreenshot(boolean showScreenshot) {
+ setRunningTaskViewShowScreenshot(showScreenshot, /*updatedThumbnails=*/null);
+ }
+
+ private void setRunningTaskViewShowScreenshot(boolean showScreenshot,
+ @Nullable Map<Integer, ThumbnailData> updatedThumbnails) {
mRunningTaskShowScreenshot = showScreenshot;
TaskView runningTaskView = getRunningTaskView();
if (runningTaskView != null) {
- runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot);
- if (!enableRefactorTaskThumbnail()) {
- runningTaskView.getTaskContainers().forEach(
- taskContainer -> taskContainer.getThumbnailViewDeprecated().refresh());
- }
+ runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot, updatedThumbnails);
}
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.setRunningTaskShowScreenshot(showScreenshot);
@@ -6154,20 +6155,12 @@
return;
}
+ Map<Integer, ThumbnailData> updatedThumbnails = mRecentsViewUtils.screenshotTasks(taskView,
+ mRecentsAnimationController);
if (enableRefactorTaskThumbnail()) {
- mHelper.switchToScreenshot(taskView, mRecentsAnimationController, onFinishRunnable);
+ mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable);
} else {
- setRunningTaskViewShowScreenshot(true);
- for (TaskContainer container : taskView.getTaskContainers()) {
- ThumbnailData thumbnailData =
- mRecentsAnimationController.screenshotTask(container.getTask().key.id);
- TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailViewDeprecated();
- if (thumbnailData != null) {
- thumbnailView.setThumbnail(container.getTask(), thumbnailData);
- } else {
- thumbnailView.refresh();
- }
- }
+ setRunningTaskViewShowScreenshot(true, updatedThumbnails);
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
}
}
@@ -6186,8 +6179,7 @@
if (enableRefactorTaskThumbnail()) {
mHelper.switchToScreenshot(taskView, thumbnailDatas, onFinishRunnable);
} else {
- taskView.setShouldShowScreenshot(true);
- taskView.refreshThumbnails(thumbnailDatas);
+ taskView.setShouldShowScreenshot(true, thumbnailDatas);
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
}
} else {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index f5b2176..4604b70 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -16,7 +16,6 @@
package com.android.quickstep.views
-import com.android.quickstep.RecentsAnimationController
import com.android.quickstep.ViewUtils
import com.android.quickstep.recents.viewmodel.RecentsViewModel
import com.android.systemui.shared.recents.model.ThumbnailData
@@ -42,18 +41,6 @@
fun switchToScreenshot(
taskView: TaskView,
- recentsAnimationController: RecentsAnimationController,
- onFinishRunnable: Runnable,
- ) {
- val updatedThumbnails =
- taskView.taskContainers.associate {
- it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
- }
- switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable)
- }
-
- fun switchToScreenshot(
- taskView: TaskView,
updatedThumbnails: Map<Int, ThumbnailData>?,
onFinishRunnable: Runnable,
) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index af32ba2..d34a93b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -146,6 +146,7 @@
}
fun bind() {
+ digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
if (enableRefactorTaskThumbnail()) {
bindThumbnailView()
} else {
@@ -171,4 +172,18 @@
thumbnailViewDeprecated.setOverlayEnabled(enabled)
}
}
+
+ fun addChildForAccessibility(outChildren: ArrayList<View>) {
+ addAccessibleChildToList(iconView.asView(), outChildren)
+ addAccessibleChildToList(snapshotView, outChildren)
+ showWindowsView?.let { addAccessibleChildToList(it, outChildren) }
+ }
+
+ private fun addAccessibleChildToList(view: View, outChildren: ArrayList<View>) {
+ if (view.includeForAccessibility()) {
+ outChildren.add(view)
+ } else {
+ view.addChildrenForAccessibility(outChildren)
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 815f8fa..5614af6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -79,7 +79,6 @@
import com.android.launcher3.views.ActivityContext
import com.android.quickstep.RecentsModel
import com.android.quickstep.RemoteAnimationTargets
-import com.android.quickstep.TaskAnimationManager
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
@@ -408,6 +407,7 @@
protected var shouldShowScreenshot = false
get() = !isRunningTask || field
+ private set
/** Enable or disable showing border on hover and focus change */
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -702,6 +702,7 @@
R.id.snapshot,
R.id.icon,
R.id.show_windows,
+ R.id.digital_wellbeing_toast,
STAGE_POSITION_UNDEFINED,
taskOverlayFactory
)
@@ -715,6 +716,7 @@
@IdRes thumbnailViewId: Int,
@IdRes iconViewId: Int,
@IdRes showWindowViewId: Int,
+ @IdRes digitalWellbeingBannerId: Int,
@StagePosition stagePosition: Int,
taskOverlayFactory: TaskOverlayFactory,
): TaskContainer {
@@ -730,6 +732,7 @@
thumbnailViewDeprecated
}
val iconView = getOrInflateIconView(iconViewId)
+ val digitalWellBeingToast = findViewById<DigitalWellBeingToast>(digitalWellbeingBannerId)!!
return TaskContainer(
this,
task,
@@ -737,7 +740,7 @@
iconView,
TransformingTouchDelegate(iconView.asView()),
stagePosition,
- DigitalWellBeingToast(container, this),
+ digitalWellBeingToast,
findViewById(showWindowViewId)!!,
taskOverlayFactory
)
@@ -775,7 +778,7 @@
protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) {
taskContainers.forEach {
it.overlay.updateOrientationState(orientationState)
- it.digitalWellBeingToast?.initialize(it.task)
+ it.digitalWellBeingToast?.initialize()
}
}
@@ -827,10 +830,8 @@
} else {
nonGridScale = 1f
boxTranslationY = 0f
- expectedWidth = if (enableOverviewIconMenu()) taskWidth else LayoutParams.MATCH_PARENT
- expectedHeight =
- if (enableOverviewIconMenu()) taskHeight + thumbnailPadding
- else LayoutParams.MATCH_PARENT
+ expectedWidth = taskWidth
+ expectedHeight = taskHeight + thumbnailPadding
}
this.nonGridScale = nonGridScale
this.boxTranslationY = boxTranslationY
@@ -847,6 +848,7 @@
taskContainers[0].snapshotView.updateLayoutParams<LayoutParams> {
topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
}
+ taskContainers.forEach { it.digitalWellBeingToast?.setupLayout() }
}
/** Returns the thumbnail's bounds, optionally relative to the screen. */
@@ -939,7 +941,7 @@
if (enableOverviewIconMenu()) {
setText(taskContainer.iconView, taskContainer.task.title)
}
- taskContainer.digitalWellBeingToast?.initialize(taskContainer.task)
+ taskContainer.digitalWellBeingToast?.initialize()
}
protected open fun onIconUnloaded(taskContainer: TaskContainer) {
@@ -974,7 +976,13 @@
iconView.setText(text)
}
- open fun refreshThumbnails(thumbnailDatas: Map<Int, ThumbnailData?>?) {
+ @JvmOverloads
+ open fun setShouldShowScreenshot(
+ shouldShowScreenshot: Boolean,
+ thumbnailDatas: Map<Int, ThumbnailData?>? = null
+ ) {
+ if (this.shouldShowScreenshot == shouldShowScreenshot) return
+ this.shouldShowScreenshot = shouldShowScreenshot
if (enableRefactorTaskThumbnail()) {
return
}
@@ -1034,21 +1042,22 @@
ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED
)
val recentsView = recentsView ?: return null
- if (recentsView.runningTaskViewId != -1) {
+ if (
+ recentsView.runningTaskViewId != -1 &&
+ recentsView.mRecentsAnimationController != null
+ ) {
recentsView.onTaskLaunchedInLiveTileMode()
// Return a fresh callback in the live tile case, so that it's not accidentally
// triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
return RunnableList().also { recentsView.addSideTaskLaunchCallback(it) }
}
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- // If the recents transition is running (ie. in live tile mode), then the start
- // of a new task will merge into the existing transition and it currently will
- // not be run independently, so we need to rely on the onTaskAppeared() call
- // for the new task to trigger the side launch callback to flush this runnable
- // list (which is usually flushed when the app launch animation finishes)
- recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
- }
+ // If the recents transition is running (ie. in live tile mode), then the start
+ // of a new task will merge into the existing transition and it currently will
+ // not be run independently, so we need to rely on the onTaskAppeared() call
+ // for the new task to trigger the side launch callback to flush this runnable
+ // list (which is usually flushed when the app launch animation finishes)
+ recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
return opts.onEndCallback
} else {
notifyTaskLaunchFailed()
@@ -1440,7 +1449,7 @@
it.thumbnailViewDeprecated.dimAlpha = amount
}
it.iconView.setIconColorTint(tintColor, amount)
- it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount)
+ it.digitalWellBeingToast?.setColorTint(tintColor, amount)
}
}
@@ -1454,7 +1463,7 @@
taskContainers.forEach {
if (visibility == VISIBLE || it.task.key.id == taskId) {
it.snapshotView.visibility = visibility
- it.digitalWellBeingToast?.setBannerVisibility(visibility)
+ it.digitalWellBeingToast?.visibility = visibility
it.showWindowsView?.visibility = visibility
it.overlay.setVisibility(visibility)
}
@@ -1658,6 +1667,12 @@
return thumbnailBounds.contains(x.toInt(), y.toInt())
}
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
+ (if (isLayoutRtl) taskContainers.reversed() else taskContainers).forEach {
+ it.addChildForAccessibility(outChildren)
+ }
+ }
+
companion object {
private const val TAG = "TaskView"
const val FLAG_UPDATE_ICON = 1
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
index d77ac5c..eb459ff 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
@@ -25,7 +25,7 @@
import android.view.LayoutInflater
import androidx.test.core.app.ApplicationProvider
import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
import org.junit.Rule
import org.junit.Test
@@ -99,7 +99,7 @@
val flags =
if (suppressNotification) Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION else 0
val bubbleInfo =
- BubbleInfo("key", flags, null, null, 0, context.packageName, null, null, false)
+ BubbleInfo("key", flags, null, null, 0, context.packageName, null, null, false, true)
val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null) as BubbleView
val dotPath =
PathParser.createPathFromPathData(
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
index 8bad3b9..94f9cf5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
@@ -27,7 +27,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,7 +65,7 @@
overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
val bubbleInfo =
- BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+ BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null, false) as BubbleView
bubble =
BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "")
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 7928ce9..84e872d 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -37,9 +37,9 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
-import com.android.wm.shell.common.bubbles.BubbleInfo
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
+import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -870,7 +870,7 @@
bubbleBarView.addView(overflowView)
val bubbleInfo =
- BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+ BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
bubbleView =
inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
bubble =
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index c0a5dfa..4106a2c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -251,7 +251,7 @@
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(translationY)
- whenever(bubbleBarViewController.bubbleBarScale).thenReturn(scale)
+ whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(scale)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(alpha)
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index b5809c2..262d8da 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -31,7 +31,6 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
import com.android.launcher3.util.MultiValueAlpha
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -55,11 +54,13 @@
companion object {
const val TASKBAR_BOTTOM_SPACE = 5
+ const val BUBBLE_BAR_WIDTH = 200f
const val BUBBLE_BAR_HEIGHT = 100f
const val HOTSEAT_TRANSLATION_Y = -45f
const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
+ const val HANDLE_VIEW_WIDTH = 150
const val HANDLE_VIEW_HEIGHT = 4
- const val BUBBLE_BAR_STASHED_TRANSLATION_Y = 48
+ const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -2.5f
}
@get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
@@ -76,7 +77,8 @@
private lateinit var bubbleBarView: BubbleBarView
private lateinit var stashedHandleView: StashedHandleView
private lateinit var barTranslationY: AnimatedFloat
- private lateinit var barScale: AnimatedFloat
+ private lateinit var barScaleX: AnimatedFloat
+ private lateinit var barScaleY: AnimatedFloat
private lateinit var barAlpha: MultiValueAlpha
private lateinit var stashedHandleAlpha: MultiValueAlpha
private lateinit var stashedHandleScale: AnimatedFloat
@@ -90,7 +92,7 @@
val taskbarHotseatDimensionsProvider =
DefaultDimensionsProvider(taskBarBottomSpace = TASKBAR_BOTTOM_SPACE)
mTransientBubbleStashController =
- TransientBubbleStashController(taskbarHotseatDimensionsProvider, context.resources)
+ TransientBubbleStashController(taskbarHotseatDimensionsProvider, context)
setUpBubbleBarView()
setUpBubbleBarController()
setUpStashedHandleView()
@@ -174,8 +176,8 @@
assertThat(mTransientBubbleStashController.isStashed).isTrue()
assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
assertThat(bubbleBarView.alpha).isEqualTo(0f)
- assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
- assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+ assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
// Handle view is visible
assertThat(stashedHandleView.translationY).isEqualTo(0)
assertThat(stashedHandleView.alpha).isEqualTo(1)
@@ -196,7 +198,7 @@
// Then
assertThat(barTranslationY.isAnimating).isTrue()
- assertThat(barScale.isAnimating).isTrue()
+ assertThat(barScaleX.isAnimating).isTrue()
// Wait until animation ends
advanceTimeBy(BubbleStashController.BAR_STASH_DURATION)
@@ -243,8 +245,8 @@
// Then all property values are updated
assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
assertThat(bubbleBarView.alpha).isEqualTo(0)
- assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
- assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+ assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
// Handle is visible at correct Y position
assertThat(stashedHandleView.alpha).isEqualTo(1)
assertThat(stashedHandleView.translationY).isEqualTo(0)
@@ -294,20 +296,16 @@
private fun setUpBubbleBarController() {
barTranslationY =
AnimatedFloat(Runnable { bubbleBarView.translationY = barTranslationY.value })
- barScale =
- AnimatedFloat(
- Runnable {
- val scale: Float = barScale.value
- bubbleBarView.scaleX = scale
- bubbleBarView.scaleY = scale
- }
- )
+ barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value }
+ barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value }
barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
- whenever(bubbleBarViewController.bubbleBarScale).thenReturn(barScale)
+ whenever(bubbleBarViewController.bubbleBarScaleX).thenReturn(barScaleX)
+ whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(barScaleY)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
+ whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
}
@@ -317,7 +315,7 @@
stashedHandleScale =
AnimatedFloat(
Runnable {
- val scale: Float = barScale.value
+ val scale: Float = barScaleX.value
bubbleBarView.scaleX = scale
bubbleBarView.scaleY = scale
}
@@ -327,6 +325,7 @@
whenever(bubbleStashedHandleViewController.stashedHandleAlpha)
.thenReturn(stashedHandleAlpha)
whenever(bubbleStashedHandleViewController.physicsAnimator).thenReturn(stashPhysicsAnimator)
+ whenever(bubbleStashedHandleViewController.stashedWidth).thenReturn(HANDLE_VIEW_WIDTH)
whenever(bubbleStashedHandleViewController.stashedHeight).thenReturn(HANDLE_VIEW_HEIGHT)
whenever(bubbleStashedHandleViewController.setTranslationYForSwipe(any())).thenAnswer {
invocation ->
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
new file mode 100644
index 0000000..2a0aa4c
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherRootView;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.util.SystemUiController;
+import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.system.InputConsumerController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Collections;
+import java.util.HashMap;
+
+public abstract class AbsSwipeUpHandlerTestCase<
+ RECENTS_CONTAINER extends Context & RecentsViewContainer,
+ STATE extends BaseState<STATE>,
+ RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+ ACTIVITY_TYPE extends StatefulActivity<STATE> & RecentsViewContainer,
+ ACTIVITY_INTERFACE extends BaseActivityInterface<STATE, ACTIVITY_TYPE>,
+ SWIPE_HANDLER extends AbsSwipeUpHandler<RECENTS_CONTAINER, RECENTS_VIEW, STATE>> {
+
+ protected final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ protected final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(mContext);
+ protected final RecentsAnimationDeviceState mRecentsAnimationDeviceState =
+ new RecentsAnimationDeviceState(mContext, true);
+ protected final InputConsumerController mInputConsumerController =
+ InputConsumerController.getRecentsAnimationInputConsumer();
+ protected final ActivityManager.RunningTaskInfo mRunningTaskInfo =
+ new ActivityManager.RunningTaskInfo();
+ protected final TopTaskTracker.CachedTaskInfo mCachedTaskInfo =
+ new TopTaskTracker.CachedTaskInfo(Collections.singletonList(mRunningTaskInfo));
+ protected final RemoteAnimationTarget mRemoteAnimationTarget = new RemoteAnimationTarget(
+ /* taskId= */ 0,
+ /* mode= */ RemoteAnimationTarget.MODE_CLOSING,
+ /* leash= */ new SurfaceControl(),
+ /* isTranslucent= */ false,
+ /* clipRect= */ null,
+ /* contentInsets= */ null,
+ /* prefixOrderIndex= */ 0,
+ /* position= */ null,
+ /* localBounds= */ null,
+ /* screenSpaceBounds= */ null,
+ new Configuration().windowConfiguration,
+ /* isNotInRecents= */ false,
+ /* startLeash= */ null,
+ /* startBounds= */ null,
+ /* taskInfo= */ mRunningTaskInfo,
+ /* allowEnterPip= */ false);
+ protected final RecentsAnimationTargets mRecentsAnimationTargets = new RecentsAnimationTargets(
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ /* homeContentInsets= */ new Rect(),
+ /* minimizedHomeBounds= */ null,
+ new Bundle());
+
+ @Mock protected ACTIVITY_INTERFACE mActivityInterface;
+ @Mock protected ActivityInitListener<?> mActivityInitListener;
+ @Mock protected RecentsAnimationController mRecentsAnimationController;
+ @Mock protected STATE mState;
+ @Mock protected ViewTreeObserver mViewTreeObserver;
+ @Mock protected DragLayer mDragLayer;
+ @Mock protected LauncherRootView mRootView;
+ @Mock protected SystemUiController mSystemUiController;
+ @Mock protected GestureState mGestureState;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setUpRunningTaskInfo() {
+ mRunningTaskInfo.baseIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ @Before
+ public void setUpGestureState() {
+ when(mGestureState.getRunningTask()).thenReturn(mCachedTaskInfo);
+ when(mGestureState.getLastAppearedTaskIds()).thenReturn(new int[0]);
+ when(mGestureState.getLastStartedTaskIds()).thenReturn(new int[1]);
+ when(mGestureState.getHomeIntent()).thenReturn(new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ doReturn(mActivityInterface).when(mGestureState).getContainerInterface();
+ }
+
+ @Before
+ public void setUpRecentsView() {
+ RECENTS_VIEW recentsView = getRecentsView();
+ when(recentsView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+ doAnswer(answer -> {
+ runOnMainSync(() -> answer.<Runnable>getArgument(0).run());
+ return this;
+ }).when(recentsView).runOnPageScrollsInitialized(any());
+ }
+
+ @Before
+ public void setUpRecentsContainer() {
+ RecentsViewContainer recentsContainer = getRecentsContainer();
+ RECENTS_VIEW recentsView = getRecentsView();
+
+ when(recentsContainer.getDeviceProfile()).thenReturn(new DeviceProfile());
+ when(recentsContainer.getOverviewPanel()).thenReturn(recentsView);
+ when(recentsContainer.getDragLayer()).thenReturn(mDragLayer);
+ when(recentsContainer.getRootView()).thenReturn(mRootView);
+ when(recentsContainer.getSystemUiController()).thenReturn(mSystemUiController);
+ when(mActivityInterface.createActivityInitListener(any()))
+ .thenReturn(mActivityInitListener);
+ doReturn(recentsContainer).when(mActivityInterface).getCreatedContainer();
+ doAnswer(answer -> {
+ answer.<Runnable>getArgument(0).run();
+ return this;
+ }).when(recentsContainer).runOnBindToTouchInteractionService(any());
+ }
+
+ @Test
+ public void testInitWhenReady_registersActivityInitListener() {
+ String reasonString = "because i said so";
+
+ createSwipeHandler().initWhenReady(reasonString);
+ verify(mActivityInitListener).register(eq(reasonString));
+ }
+
+ @Test
+ public void testOnRecentsAnimationCanceled_unregistersActivityInitListener() {
+ createSwipeHandler()
+ .onRecentsAnimationCanceled(new HashMap<>());
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister(eq("AbsSwipeUpHandler.onRecentsAnimationCanceled")));
+ }
+
+ @Test
+ public void testOnConsumerAboutToBeSwitched_unregistersActivityInitListener() {
+ createSwipeHandler().onConsumerAboutToBeSwitched();
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister("AbsSwipeUpHandler.invalidateHandler"));
+ }
+
+ @Test
+ public void testOnConsumerAboutToBeSwitched_midQuickSwitch_unregistersActivityInitListener() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.NEW_TASK)
+ .onConsumerAboutToBeSwitched();
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister(eq("AbsSwipeUpHandler.cancelCurrentAnimation")));
+ }
+
+ @Test
+ public void testStartNewTask_finishesRecentsAnimationController() {
+ SWIPE_HANDLER absSwipeUpHandler = createSwipeHandler();
+
+ onRecentsAnimationStart(absSwipeUpHandler);
+
+ runOnMainSync(() -> {
+ absSwipeUpHandler.startNewTask(unused -> {});
+ verify(mRecentsAnimationController).finish(anyBoolean(), any());
+ });
+ }
+
+ @Test
+ public void testHomeGesture_finishesRecentsAnimationController() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME);
+
+ runOnMainSync(() -> {
+ verify(mRecentsAnimationController).detachNavigationBarFromApp(true);
+ verify(mRecentsAnimationController).finish(anyBoolean(), any(), anyBoolean());
+ });
+ }
+
+ private SWIPE_HANDLER createSwipeUpHandlerForGesture(GestureState.GestureEndTarget endTarget) {
+ boolean isQuickSwitch = endTarget == GestureState.GestureEndTarget.NEW_TASK;
+
+ doReturn(mState).when(mActivityInterface).stateFromGestureEndTarget(any());
+
+ SWIPE_HANDLER swipeHandler = createSwipeHandler(SystemClock.uptimeMillis(), isQuickSwitch);
+
+ swipeHandler.onActivityInit(/* alreadyOnHome= */ false);
+ swipeHandler.onGestureStarted(isQuickSwitch);
+ onRecentsAnimationStart(swipeHandler);
+
+ when(mGestureState.getRunningTaskIds(anyBoolean())).thenReturn(new int[0]);
+ runOnMainSync(swipeHandler::switchToScreenshot);
+
+ when(mGestureState.getEndTarget()).thenReturn(endTarget);
+ when(mGestureState.isRecentsAnimationRunning()).thenReturn(isQuickSwitch);
+ float xVelocityPxPerMs = isQuickSwitch ? 100 : 0;
+ float yVelocityPxPerMs = isQuickSwitch ? 0 : -100;
+ swipeHandler.onGestureEnded(
+ yVelocityPxPerMs, new PointF(xVelocityPxPerMs, yVelocityPxPerMs));
+ swipeHandler.onCalculateEndTarget();
+ runOnMainSync(swipeHandler::onSettledOnEndTarget);
+
+ return swipeHandler;
+ }
+
+ private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
+ when(mActivityInterface.getOverviewWindowBounds(any(), any())).thenReturn(new Rect());
+ doNothing().when(mActivityInterface).setOnDeferredActivityLaunchCallback(any());
+
+ runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
+ mRecentsAnimationController, mRecentsAnimationTargets));
+ }
+
+ private static void runOnMainSync(Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
+
+ @NonNull
+ private SWIPE_HANDLER createSwipeHandler() {
+ return createSwipeHandler(SystemClock.uptimeMillis(), false);
+ }
+
+ @NonNull
+ protected abstract SWIPE_HANDLER createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture);
+
+ @NonNull
+ protected abstract RecentsViewContainer getRecentsContainer();
+
+ @NonNull
+ protected abstract RECENTS_VIEW getRecentsView();
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
new file mode 100644
index 0000000..dd0b4b3
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsState;
+
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class FallbackSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase<
+ RecentsActivity,
+ RecentsState,
+ FallbackRecentsView,
+ RecentsActivity,
+ FallbackActivityInterface,
+ FallbackSwipeHandler> {
+
+ @Mock private RecentsActivity mRecentsActivity;
+ @Mock private FallbackRecentsView mRecentsView;
+
+
+ @Override
+ protected FallbackSwipeHandler createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture) {
+ return new FallbackSwipeHandler(
+ mContext,
+ mRecentsAnimationDeviceState,
+ mTaskAnimationManager,
+ mGestureState,
+ touchTimeMs,
+ continuingLastGesture,
+ mInputConsumerController);
+ }
+
+ @Override
+ protected RecentsActivity getRecentsContainer() {
+ return mRecentsActivity;
+ }
+
+ @Override
+ protected FallbackRecentsView getRecentsView() {
+ return mRecentsView;
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
new file mode 100644
index 0000000..653dc01
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.WorkspaceStateTransitionAnimation;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.views.RecentsView;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase<
+ QuickstepLauncher,
+ LauncherState,
+ RecentsView<QuickstepLauncher, LauncherState>,
+ QuickstepLauncher,
+ LauncherActivityInterface,
+ LauncherSwipeHandlerV2> {
+
+ @Mock private QuickstepLauncher mQuickstepLauncher;
+ @Mock private RecentsView<QuickstepLauncher, LauncherState> mRecentsView;
+ @Mock private Workspace<?> mWorkspace;
+ @Mock private Hotseat mHotseat;
+ @Mock private WorkspaceStateTransitionAnimation mTransitionAnimation;
+
+ @Before
+ public void setUpQuickStepLauncher() {
+ when(mQuickstepLauncher.createAtomicAnimationFactory())
+ .thenReturn(new AtomicAnimationFactory<>(0));
+ when(mQuickstepLauncher.getHotseat()).thenReturn(mHotseat);
+ doReturn(mWorkspace).when(mQuickstepLauncher).getWorkspace();
+ doReturn(new StateManager(mQuickstepLauncher, LauncherState.NORMAL))
+ .when(mQuickstepLauncher).getStateManager();
+
+ }
+
+ @Before
+ public void setUpWorkspace() {
+ when(mWorkspace.getStateTransitionAnimation()).thenReturn(mTransitionAnimation);
+ }
+
+ @Override
+ protected LauncherSwipeHandlerV2 createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture) {
+ return new LauncherSwipeHandlerV2(
+ mContext,
+ mRecentsAnimationDeviceState,
+ mTaskAnimationManager,
+ mGestureState,
+ touchTimeMs,
+ continuingLastGesture,
+ mInputConsumerController);
+ }
+
+ @Override
+ protected QuickstepLauncher getRecentsContainer() {
+ return mQuickstepLauncher;
+ }
+
+ @Override
+ protected RecentsView<QuickstepLauncher, LauncherState> getRecentsView() {
+ return mRecentsView;
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index 2087016..9bc1c59 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -15,20 +15,18 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.platform.test.annotations.PlatinumTest;
+import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask;
import com.android.launcher3.tapl.OverviewTaskMenu;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
import org.junit.Test;
@@ -70,39 +68,17 @@
@Test
public void testSplitTaskTapBothIconMenus() {
- createAndLaunchASplitPair();
+ Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
- OverviewTaskMenu taskMenu =
- mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+ OverviewTaskMenu taskMenu = overview.getCurrentTask().tapMenu();
assertTrue("App info item not appearing in expanded task menu.",
taskMenu.hasMenuItem("App info"));
taskMenu.touchOutsideTaskMenuToDismiss();
- OverviewTaskMenu splitMenu =
- mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu(
+ OverviewTaskMenu splitMenu = overview.getCurrentTask().tapMenu(
OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT);
assertTrue("App info item not appearing in expanded split task's menu.",
splitMenu.hasMenuItem("App info"));
splitMenu.touchOutsideTaskMenuToDismiss();
}
-
- private void createAndLaunchASplitPair() {
- clearAllRecentTasks();
-
- startTestActivity(2);
- startTestActivity(3);
-
- if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- } else {
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
- }
-}
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index f971afb..943c1bd 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -290,9 +290,6 @@
}
}
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -481,7 +478,8 @@
// assertTrue("Launcher internal state didn't remain in Overview",
// isInState(() -> LauncherState.OVERVIEW));
// overview.getCurrentTask().dismiss();
-// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
+// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple
+// dismissals",
// (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
// launcher)) <= 1)));
@@ -592,7 +590,8 @@
if (overview.hasTasks()) {
currentTask = overview.getCurrentTask();
assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home",
- currentTask.containsContentDescription("ExcludeFromRecents")
+ currentTask.containsContentDescription(
+ "ExcludeFromRecents")
|| currentTask.containsContentDescription(null));
} else {
// Presumably the test started with 0 tasks and remains that way after going home.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 733ea4e..daa4ec3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -17,8 +17,6 @@
import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -33,7 +31,7 @@
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.tapl.TaskbarAppIcon;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
import com.android.wm.shell.Flags;
import org.junit.After;
@@ -110,9 +108,8 @@
assumeTrue("App pairs feature is currently not enabled, no test needed",
Flags.enableAppPairs());
- createAndLaunchASplitPair();
+ Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
- Overview overview = mLauncher.goHome().switchToOverview();
if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) {
assertTrue("Save app pair menu item is missing",
overview.getCurrentTask()
@@ -156,24 +153,4 @@
TaskbarAppIcon firstApp = taskbar.getAppIcon(firstAppName);
firstApp.launchIntoSplitScreen();
}
-
- private void createAndLaunchASplitPair() {
- clearAllRecentTasks();
-
- startTestActivity(2);
- startTestActivity(3);
-
- if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- } else {
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
- }
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 3a83ae3..28c8a4a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -59,8 +59,6 @@
@Test
public void startRecentsActivity_allowBackgroundLaunch() {
- assumeTrue(TaskAnimationManager.ENABLE_SHELL_TRANSITIONS);
-
final LauncherActivityInterface activityInterface = mock(LauncherActivityInterface.class);
final GestureState gestureState = mock(GestureState.class);
final RecentsAnimationCallbacks.RecentsAnimationListener listener =
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
new file mode 100644
index 0000000..82361aa
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import androidx.test.uiautomator.By
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.launcher3.tapl.Overview
+import com.android.launcher3.tapl.OverviewTask
+import com.android.launcher3.ui.AbstractLauncherUiTest
+
+object SplitScreenTestUtils {
+
+ /** Creates 2 tasks and makes a split mode pair. Also asserts the accessibility labels. */
+ @JvmStatic
+ fun createAndLaunchASplitPairInOverview(launcher: LauncherInstrumentation): Overview {
+ clearAllRecentTasks(launcher)
+
+ AbstractLauncherUiTest.startTestActivity(2)
+ AbstractLauncherUiTest.startTestActivity(3)
+
+ val overView = launcher.goHome().switchToOverview()
+ if (launcher.isTablet && !launcher.isGridOnlyOverviewEnabled) {
+ overView.overviewActions.clickSplit().getTestActivityTask(2).open()
+ } else {
+ overView.currentTask.tapMenu().tapSplitMenuItem().currentTask.open()
+ }
+
+ val overviewWithSplitPair = launcher.goHome().switchToOverview()
+ val currentTask = overviewWithSplitPair.currentTask
+ currentTask.containsContentDescription(
+ By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(),
+ OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT
+ )
+ currentTask.containsContentDescription(
+ By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(),
+ OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT
+ )
+ return overviewWithSplitPair
+ }
+
+ private fun clearAllRecentTasks(launcher: LauncherInstrumentation) {
+ if (launcher.recentTasks.isNotEmpty()) {
+ launcher.goHome().switchToOverview().dismissAllTasks()
+ }
+ }
+}
diff --git a/res/color-night-v31/popup_color_background.xml b/res/color-night-v31/popup_color_background.xml
deleted file mode 100644
index 13ceaa0..0000000
--- a/res/color-night-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@android:color/system_neutral1_900"
- android:lStar="12" />
-</selector>
diff --git a/res/color-v31/popup_color_background.xml b/res/color-v31/popup_color_background.xml
deleted file mode 100644
index 99155d8..0000000
--- a/res/color-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@android:color/system_neutral1_50"
- android:lStar="94" />
-</selector>
diff --git a/res/color/popup_color_background.xml b/res/color/popup_color_background.xml
deleted file mode 100644
index e87e772..0000000
--- a/res/color/popup_color_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:color="?attr/popupColorBackground" />
-</selector>
diff --git a/res/drawable/popup_background.xml b/res/drawable/popup_background.xml
index 6eedecb..4ddd228 100644
--- a/res/drawable/popup_background.xml
+++ b/res/drawable/popup_background.xml
@@ -15,6 +15,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/popupColorBackground"/>
+ <solid android:color="?attr/materialColorSurfaceContainer"/>
<corners android:radius="@dimen/dialogCornerRadius"/>
</shape>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 6151b5f..57c9bc7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -25,7 +25,6 @@
<attr name="popupColorPrimary" format="color" />
<attr name="popupColorSecondary" format="color" />
<attr name="popupColorTertiary" format="color" />
- <attr name="popupColorBackground" format="color" />
<attr name="popupTextColor" format="color" />
<attr name="popupShadeFirst" format="color" />
<attr name="popupShadeSecond" format="color" />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ee7ed26..728c523 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -77,6 +77,10 @@
<item name="materialColorError">@color/system_error_light</item>
</style>
+ <style name="DynamicColorsBaseLauncherTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
<style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme">
<item name="android:textColorSecondary">#DE000000</item>
@@ -86,7 +90,6 @@
<item name="popupColorPrimary">@color/popup_color_primary_light</item>
<item name="popupColorSecondary">@color/popup_color_secondary_light</item>
<item name="popupColorTertiary">@color/popup_color_tertiary_light</item>
- <item name="popupColorBackground">#EFEDED</item>
<item name="popupTextColor">@color/system_on_surface_light</item>
<item name="popupShadeFirst">@color/popup_shade_first_light</item>
<item name="popupShadeSecond">@color/popup_shade_second_light</item>
@@ -161,7 +164,6 @@
<item name="popupColorPrimary">@color/popup_color_primary_dark</item>
<item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
<item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
- <item name="popupColorBackground">#1F2020</item>
<item name="popupTextColor">@color/system_on_surface_dark</item>
<item name="popupNotificationDotColor">@color/popup_notification_dot_dark</item>
<item name="popupShadeFirst">@color/popup_shade_first_dark</item>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index ef56246..b51e850 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -37,8 +37,6 @@
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.debug.TestEvent;
-import com.android.launcher3.debug.TestEventEmitter;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
@@ -223,9 +221,6 @@
dl.addView(frame);
frame.mIsOpen = true;
frame.post(() -> frame.snapToWidget(false));
- TestEventEmitter.INSTANCE.get(widget.getContext()).sendEvent(
- TestEvent.RESIZE_FRAME_SHOWING
- );
}
private void setCornerRadiusFromWidget() {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 633091d..fec94fe 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -110,11 +110,6 @@
public static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 4;
/**
- * State flag indicating if the user will be active shortly.
- */
- public static final int ACTIVITY_STATE_USER_WILL_BE_ACTIVE = 1 << 5;
-
- /**
* State flag indicating that a state transition is in progress
*/
public static final int ACTIVITY_STATE_TRANSITION_ACTIVE = 1 << 6;
@@ -316,7 +311,6 @@
*/
public void setResumed() {
addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
- removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
public boolean isUserActive() {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 26e900d..8121e53 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -89,7 +89,7 @@
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import java.text.NumberFormat;
import java.util.HashMap;
@@ -101,7 +101,7 @@
* too aggressive.
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
- IconLabelDotView, DraggableView, Reorderable {
+ FloatingIconViewCompanion, DraggableView, Reorderable {
public static final String TAG = "BubbleTextView";
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 5cbf6fb..8ae6d73 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -316,6 +316,74 @@
// DragController
public int flingToDeleteThresholdVelocity;
+ /** Used only as an alternative to mocking when null values cannot be used. */
+ @VisibleForTesting
+ public DeviceProfile() {
+ inv = null;
+ mInfo = null;
+ mMetrics = null;
+ mIconSizeSteps = null;
+ isTablet = false;
+ isPhone = false;
+ transposeLayoutWithOrientation = false;
+ isMultiDisplay = false;
+ isTwoPanels = false;
+ isPredictiveBackSwipe = false;
+ isQsbInline = false;
+ isLandscape = false;
+ isMultiWindowMode = false;
+ isGestureMode = false;
+ isLeftRightSplit = false;
+ windowX = 0;
+ windowY = 0;
+ widthPx = 0;
+ heightPx = 0;
+ availableWidthPx = 0;
+ availableHeightPx = 0;
+ rotationHint = 0;
+ aspectRatio = 1;
+ mIsScalableGrid = false;
+ mTypeIndex = 0;
+ mIsResponsiveGrid = false;
+ desiredWorkspaceHorizontalMarginOriginalPx = 0;
+ edgeMarginPx = 0;
+ workspaceContentScale = 0;
+ workspaceSpringLoadedMinNextPageVisiblePx = 0;
+ extraSpace = 0;
+ workspacePageIndicatorHeight = 0;
+ mWorkspacePageIndicatorOverlapWorkspace = 0;
+ numFolderRows = 0;
+ numFolderColumns = 0;
+ folderLabelTextScale = 0;
+ areNavButtonsInline = false;
+ mHotseatBarEdgePaddingPx = 0;
+ mHotseatBarWorkspaceSpacePx = 0;
+ hotseatQsbWidth = 0;
+ hotseatQsbHeight = 0;
+ hotseatQsbVisualHeight = 0;
+ hotseatQsbShadowHeight = 0;
+ hotseatBorderSpace = 0;
+ mMinHotseatIconSpacePx = 0;
+ mMinHotseatQsbWidthPx = 0;
+ mMaxHotseatIconSpacePx = 0;
+ inlineNavButtonsEndSpacingPx = 0;
+ mBubbleBarSpaceThresholdPx = 0;
+ numShownAllAppsColumns = 0;
+ overviewActionsHeight = 0;
+ overviewActionsTopMarginPx = 0;
+ overviewActionsButtonSpacing = 0;
+ mViewScaleProvider = null;
+ mDotRendererWorkSpace = null;
+ mDotRendererAllApps = null;
+ taskbarHeight = 0;
+ stashedTaskbarHeight = 0;
+ taskbarBottomMargin = 0;
+ taskbarIconSize = 0;
+ mTransientTaskbarClaimedSpace = 0;
+ startAlignTaskbar = false;
+ isTransientTaskbar = false;
+ }
+
/** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */
DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
SparseArray<DotRenderer> dotRendererCache, boolean isMultiWindowMode,
diff --git a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
index e218b4d..52b454f 100644
--- a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
+++ b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
@@ -27,6 +27,8 @@
WORKSPACE_ON_DROP("WORKSPACE_ON_DROP"),
RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"),
WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"),
+ SPRING_LOADED_STATE_STARTED("SPRING_LOADED_STATE_STARTED"),
+ SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"),
}
/** Interface to create TestEventEmitters. */
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a0b695a..de1bcc3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -83,7 +83,7 @@
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
@@ -93,7 +93,7 @@
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
+public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
DraggableView, Reorderable {
private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 4d4a8f7..c2debfa 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,8 +16,6 @@
package com.android.launcher3.popup;
-import static androidx.core.content.ContextCompat.getColorStateList;
-
import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.app.animation.Interpolators.LINEAR;
@@ -56,8 +54,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
-import java.util.Arrays;
-
/**
* A container for shortcuts to deep links and notifications associated with an app.
*
@@ -130,7 +126,7 @@
// Tag for Views that have children that will need to be iterated to add styling.
private final String mIterateChildrenTag;
- protected final int[] mColorIds;
+ protected final int[] mColors;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -142,8 +138,7 @@
// Initialize arrow view
final Resources resources = getResources();
- mArrowColor = getColorStateList(getContext(), R.color.popup_color_background)
- .getDefaultColor();
+ mArrowColor = Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceContainer);
mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
@@ -158,21 +153,25 @@
mRoundedTop = new GradientDrawable();
int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
mRoundedTop.setColor(popupPrimaryColor);
- mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
+ mRoundedTop.setCornerRadii(new float[]{mOutlineRadius, mOutlineRadius, mOutlineRadius,
mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
mRoundedBottom = new GradientDrawable();
mRoundedBottom.setColor(popupPrimaryColor);
- mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
+ mRoundedBottom.setCornerRadii(new float[]{smallerRadius, smallerRadius, smallerRadius,
smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
if (mActivityContext.canUseMultipleShadesForPopup()) {
- mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
- R.color.popup_shade_third};
+ mColors = new int[]{
+ getContext().getColor(R.color.popup_shade_first),
+ getContext().getColor(R.color.popup_shade_second),
+ getContext().getColor(R.color.popup_shade_third)
+ };
} else {
- mColorIds = new int[]{R.color.popup_color_background};
+ mColors = new int[]{Themes.getAttrColor(getContext(),
+ R.attr.materialColorSurfaceContainer)};
}
}
@@ -219,15 +218,14 @@
}
/**
- * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}.
+ * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}.
* Otherwise, we will use this color for all child views.
*/
protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
int[] colors = null;
if (backgroundColor == Color.TRANSPARENT) {
// Lazily get the colors so they match the current wallpaper colors.
- colors = Arrays.stream(mColorIds).map(
- r -> getColorStateList(getContext(), r).getDefaultColor()).toArray();
+ colors = mColors;
}
int count = viewGroup.getChildCount();
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 84f8049..d2ae93b 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -20,7 +20,7 @@
/**
* Views that contain {@link BubbleTextView} should implement this interface.
*/
-public interface BubbleTextHolder extends IconLabelDotView {
+public interface BubbleTextHolder extends FloatingIconViewCompanion {
BubbleTextView getBubbleText();
@Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 37482ac..4ee6aff 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -22,7 +22,7 @@
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.animation.Animator;
import android.content.Context;
@@ -516,6 +516,10 @@
// When closing an app, we want the item on the workspace to be invisible immediately
updateViewsVisibility(false /* isVisible */);
}
+ if (mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(true);
+ fivc.setForceHideRing(true);
+ }
}
@Override
@@ -653,6 +657,10 @@
if (view.mFadeOutView != null) {
view.mFadeOutView.setAlpha(1f);
}
+ if (view.mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(false);
+ fivc.setForceHideRing(false);
+ }
if (hideOriginal) {
view.updateViewsVisibility(true /* isVisible */);
@@ -674,10 +682,10 @@
private void updateViewsVisibility(boolean isVisible) {
if (mOriginalIcon != null) {
- setIconAndDotVisible(mOriginalIcon, isVisible);
+ setPropertiesVisible(mOriginalIcon, isVisible);
}
if (mMatchVisibilityView != null) {
- setIconAndDotVisible(mMatchVisibilityView, isVisible);
+ setPropertiesVisible(mMatchVisibilityView, isVisible);
}
}
diff --git a/src/com/android/launcher3/views/FloatingIconViewCompanion.java b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
new file mode 100644
index 0000000..fc23903
--- /dev/null
+++ b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import android.view.View;
+
+/**
+ * A view that can be drawn (in some capacity) via) {@link FloatingIconView}.
+ * This interface allows us to hide certain properties of the view that the FloatingIconView
+ * cannot draw, which allows us to make a seamless handoff between the FloatingIconView and
+ * the companion view.
+ */
+public interface FloatingIconViewCompanion {
+ void setIconVisible(boolean visible);
+ void setForceHideDot(boolean hide);
+ default void setForceHideRing(boolean hide) {}
+
+ /**
+ * Sets the visibility of icon and dot of the view
+ */
+ static void setPropertiesVisible(View view, boolean visible) {
+ if (view instanceof FloatingIconViewCompanion) {
+ ((FloatingIconViewCompanion) view).setIconVisible(visible);
+ ((FloatingIconViewCompanion) view).setForceHideDot(!visible);
+ ((FloatingIconViewCompanion) view).setForceHideRing(!visible);
+ } else {
+ view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index cab7982..7fa7517 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -17,7 +17,7 @@
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.content.Context;
import android.graphics.Canvas;
@@ -237,7 +237,7 @@
private void setCurrentIconVisible(boolean isVisible) {
if (mIcon != null) {
- setIconAndDotVisible(mIcon, isVisible);
+ setPropertiesVisible(mIcon, isVisible);
}
}
}
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
deleted file mode 100644
index e9113cf..0000000
--- a/src/com/android/launcher3/views/IconLabelDotView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.view.View;
-
-/**
- * A view that has an icon, label, and notification dot.
- */
-public interface IconLabelDotView {
- void setIconVisible(boolean visible);
- void setForceHideDot(boolean hide);
-
- /**
- * Sets the visibility of icon and dot of the view
- */
- static void setIconAndDotVisible(View view, boolean visible) {
- if (view instanceof IconLabelDotView) {
- ((IconLabelDotView) view).setIconVisible(visible);
- ((IconLabelDotView) view).setForceHideDot(!visible);
- } else {
- view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 62eed5c..82cc40d 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.views;
-import static androidx.core.content.ContextCompat.getColorStateList;
-
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
@@ -147,8 +145,7 @@
@Override
public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
- assignMarginsAndBackgrounds(viewGroup,
- getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+ assignMarginsAndBackgrounds(viewGroup, mColors[0]);
// last shortcut doesn't need bottom margin
final int count = viewGroup.getChildCount() - 1;
for (int i = 0; i < count; i++) {
diff --git a/tests/Android.bp b/tests/Android.bp
index 1fa6e05..9f62d02 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -127,9 +127,9 @@
"com_android_launcher3_flags_lib",
],
libs: [
- "android.test.base",
- "android.test.runner",
- "android.test.mock",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
+ "android.test.mock.stubs.system",
],
// Libraries used by mockito inline extended
jni_libs: [
@@ -229,9 +229,9 @@
"android.appwidget.flags-aconfig-java",
],
libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"truth",
],
instrumentation_for: "Launcher3",
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index ab48a21..5433fa7 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -284,8 +284,9 @@
*
* TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed.
*/
- public boolean containsContentDescription(@Nullable String expected) {
- String actual = mTask.getContentDescription();
+ public boolean containsContentDescription(@Nullable String expected,
+ OverviewSplitTask overviewSplitTask) {
+ String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription();
if (actual == null && expected == null) {
return true;
}
@@ -295,6 +296,14 @@
return actual.contains(expected);
}
+ /**
+ * Returns whether the given String is contained in this Task's contentDescription. Also returns
+ * true if both Strings are null
+ */
+ public boolean containsContentDescription(@Nullable String expected) {
+ return containsContentDescription(expected, DEFAULT);
+ }
+
private TaskViewType getType() {
String resourceName = mTask.getResourceName();
if (resourceName.endsWith("task_view_grouped")) {