Snap for 12304452 from a4ce092bea to 24Q4-release
Change-Id: I5217a8dc04051904a2ae9546a6c0c5cc215c4ed6
This commit is contained in:
+3
-3
@@ -221,7 +221,7 @@ launcher_compose_tests_java_defaults {
|
||||
android_library {
|
||||
name: "launcher-aosp-tapl",
|
||||
libs: [
|
||||
"framework-statsd",
|
||||
"framework-statsd.stubs.module_lib",
|
||||
],
|
||||
static_libs: [
|
||||
"androidx.annotation_annotation",
|
||||
@@ -388,7 +388,7 @@ android_library {
|
||||
"quickstep/res",
|
||||
],
|
||||
libs: [
|
||||
"framework-statsd",
|
||||
"framework-statsd.stubs.module_lib",
|
||||
],
|
||||
static_libs: [
|
||||
"Launcher3ResLib",
|
||||
@@ -453,7 +453,7 @@ android_library {
|
||||
],
|
||||
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
|
||||
|
||||
+2
-3
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
+16
-12
@@ -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"
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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:clipToOutline="true"
|
||||
android:importantForAccessibility="yes"
|
||||
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="@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">
|
||||
|
||||
<TextView
|
||||
style="@style/KeyboardQuickSwitchText.LargeText"
|
||||
android:id="@+id/large_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
|
||||
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"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -65,7 +65,6 @@ import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VAL
|
||||
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 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
* 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 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
protected void unregisterRemoteTransitions() {
|
||||
if (ENABLE_SHELL_TRANSITIONS) {
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
|
||||
}
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
|
||||
if (SEPARATE_RECENTS_ACTIVITY.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
|
||||
import static android.view.WindowInsets.Type.navigationBars;
|
||||
import static android.view.WindowInsets.Type.statusBars;
|
||||
|
||||
import static com.android.launcher3.Flags.enablePredictiveBackGesture;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
@@ -170,11 +169,6 @@ public class WidgetPickerActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
protected void registerBackDispatcher() {
|
||||
if (!enablePredictiveBackGesture()) {
|
||||
super.registerBackDispatcher();
|
||||
return;
|
||||
}
|
||||
|
||||
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||
new BackAnimationCallback());
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.android.quickstep.LauncherActivityInterface;
|
||||
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 @@ public final class KeyboardQuickSwitchController implements
|
||||
|
||||
@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 @@ public final class KeyboardQuickSwitchController implements
|
||||
/* 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 @@ public final class KeyboardQuickSwitchController implements
|
||||
/* updateTasks= */ true,
|
||||
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
|
||||
? 0 : currentFocusedIndex,
|
||||
onDesktop);
|
||||
onDesktop,
|
||||
mHasDesktopTask,
|
||||
mWasDesktopTaskFilteredOut);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -152,9 +162,22 @@ public final class KeyboardQuickSwitchController implements
|
||||
// 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 @@ public final class KeyboardQuickSwitchController implements
|
||||
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 @@ public final class KeyboardQuickSwitchController implements
|
||||
|
||||
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 @@ public final class KeyboardQuickSwitchController implements
|
||||
boolean isFirstTaskRunning() {
|
||||
return isTaskRunning(getTaskAt(0));
|
||||
}
|
||||
|
||||
boolean isAspectRatioSquare() {
|
||||
return mControllers != null && LayoutUtils.isAspectRatioSquare(
|
||||
mControllers.taskbarActivityContext.getDeviceProfile().aspectRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +50,10 @@ import kotlin.Unit;
|
||||
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 @@ public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
|
||||
|
||||
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 @@ public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
|
||||
|
||||
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 -> {
|
||||
|
||||
@@ -36,14 +36,12 @@ import android.view.ViewOutlineProvider;
|
||||
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.Utilities;
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
private KeyboardQuickSwitchTaskView createAndAddTaskView(
|
||||
int index,
|
||||
boolean isFinalView,
|
||||
boolean useSmallStartSpacing,
|
||||
@LayoutRes int resId,
|
||||
@NonNull LayoutInflater layoutInflater,
|
||||
@Nullable View previousView) {
|
||||
@@ -156,7 +159,7 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
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 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
});
|
||||
}
|
||||
|
||||
int getOverviewTaskIndex() {
|
||||
return mOverviewTaskIndex;
|
||||
}
|
||||
|
||||
int getDesktopTaskIndex() {
|
||||
return mDesktopTaskIndex;
|
||||
}
|
||||
|
||||
protected Animator getCloseAnimation() {
|
||||
AnimatorSet closeAnimation = new AnimatorSet();
|
||||
|
||||
@@ -370,7 +387,7 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
}
|
||||
});
|
||||
animateFocusMove(-1, Math.min(
|
||||
mContent.getChildCount() - 1,
|
||||
getTaskCount() - 1,
|
||||
currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
|
||||
displayedContent.setVisibility(VISIBLE);
|
||||
setVisibility(VISIBLE);
|
||||
@@ -577,7 +594,11 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
+40
-14
@@ -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.internal.jank.Cuj;
|
||||
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 @@ public class KeyboardQuickSwitchViewController {
|
||||
private int mCurrentFocusIndex = -1;
|
||||
|
||||
private boolean mOnDesktop;
|
||||
private boolean mWasDesktopTaskFilteredOut;
|
||||
|
||||
protected KeyboardQuickSwitchViewController(
|
||||
@NonNull TaskbarControllers controllers,
|
||||
@@ -77,9 +81,12 @@ public class KeyboardQuickSwitchViewController {
|
||||
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 @@ public class KeyboardQuickSwitchViewController {
|
||||
numHiddenTasks,
|
||||
updateTasks,
|
||||
currentFocusIndexOverride,
|
||||
mViewCallbacks);
|
||||
mViewCallbacks,
|
||||
/* useDesktopTaskView= */ !onDesktop && hasDesktopTask);
|
||||
}
|
||||
|
||||
boolean isCloseAnimationRunning() {
|
||||
@@ -136,7 +144,7 @@ public class KeyboardQuickSwitchViewController {
|
||||
}
|
||||
// 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 @@ public class KeyboardQuickSwitchViewController {
|
||||
// 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 @@ public class KeyboardQuickSwitchViewController {
|
||||
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 @@ public class KeyboardQuickSwitchViewController {
|
||||
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 @@ public class KeyboardQuickSwitchViewController {
|
||||
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 @@ public class KeyboardQuickSwitchViewController {
|
||||
void updateIconInBackground(Task task, Consumer<Task> callback) {
|
||||
mControllerCallbacks.updateIconInBackground(task, callback);
|
||||
}
|
||||
|
||||
boolean isAspectRatioSquare() {
|
||||
return mControllerCallbacks.isAspectRatioSquare();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR
|
||||
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 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ import com.android.launcher3.util.Executors;
|
||||
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;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
|
||||
import static com.android.launcher3.Flags.enableCursorHoverStates;
|
||||
import static com.android.launcher3.Flags.enableTaskbarCustomization;
|
||||
import static com.android.launcher3.Utilities.calculateTextHeight;
|
||||
import static com.android.launcher3.Utilities.isRunningInTestHarness;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
|
||||
@@ -230,15 +229,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
mNavigationBarPanelContext = navigationBarPanelContext;
|
||||
applyDeviceProfile(launcherDp);
|
||||
final Resources resources = getResources();
|
||||
|
||||
if (enableTaskbarCustomization()) {
|
||||
mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
|
||||
mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
|
||||
this,
|
||||
mTaskbarFeatureEvaluator,
|
||||
mDeviceProfile.inv.numRows,
|
||||
mDeviceProfile.inv.numColumns);
|
||||
}
|
||||
mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
|
||||
mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
|
||||
this,
|
||||
mTaskbarFeatureEvaluator,
|
||||
mDeviceProfile.inv.numRows,
|
||||
mDeviceProfile.inv.numColumns);
|
||||
|
||||
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
|
||||
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
|
||||
@@ -287,7 +283,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
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),
|
||||
@@ -1761,12 +1757,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
return mControllers.taskbarStashController.isInStashedLauncherState();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskbarFeatureEvaluator getTaskbarFeatureEvaluator() {
|
||||
return mTaskbarFeatureEvaluator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskbarSpecsEvaluator getTaskbarSpecsEvaluator() {
|
||||
return mTaskbarSpecsEvaluator;
|
||||
}
|
||||
|
||||
@@ -169,8 +169,11 @@ constructor(
|
||||
|
||||
override fun addArrow() {
|
||||
super.addArrow()
|
||||
val location = IntArray(2)
|
||||
popupContainer.getLocationInDragLayer(dividerView, location)
|
||||
val dividerViewX = location[0].toFloat()
|
||||
// Change arrow location to the middle of popup.
|
||||
mArrow.x = (dividerView.x + dividerView.width / 2) - (mArrowWidth / 2)
|
||||
mArrow.x = (dividerViewX + dividerView.width / 2) - (mArrowWidth / 2)
|
||||
}
|
||||
|
||||
override fun updateArrowColor() {
|
||||
|
||||
@@ -171,6 +171,10 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
|
||||
}
|
||||
|
||||
private void updateBackgroundAlpha() {
|
||||
if (mActivity.isPhoneMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final float bgNavbar = mBgNavbar.value;
|
||||
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
|
||||
* mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
|
||||
|
||||
@@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
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.popup.SystemShortcut;
|
||||
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 @@ public class TaskbarUIController {
|
||||
if (overviewCommandHelper == null) {
|
||||
return;
|
||||
}
|
||||
overviewCommandHelper.addCommand(TYPE_HIDE);
|
||||
overviewCommandHelper.addCommand(CommandType.HIDE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,10 +22,8 @@ import static com.android.launcher3.Flags.enableCursorHoverStates;
|
||||
import static com.android.launcher3.Flags.enableRecentsInTaskbar;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
|
||||
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
@@ -39,12 +37,9 @@ import android.view.InputDevice;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -62,13 +57,12 @@ import com.android.launcher3.model.data.CollectionInfo;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.taskbar.customization.TaskbarAllAppsButtonContainer;
|
||||
import com.android.launcher3.taskbar.customization.TaskbarDividerContainer;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.LauncherBindableItemsContainer;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.IconButtonView;
|
||||
import com.android.quickstep.DeviceConfigWrapper;
|
||||
import com.android.quickstep.util.AssistStateManager;
|
||||
import com.android.quickstep.util.DesktopTask;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
@@ -100,16 +94,13 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
private View.OnLongClickListener mIconLongClickListener;
|
||||
|
||||
// Only non-null when the corresponding Folder is open.
|
||||
private @Nullable FolderIcon mLeaveBehindFolderIcon;
|
||||
@Nullable private FolderIcon mLeaveBehindFolderIcon;
|
||||
|
||||
// Only non-null when device supports having an All Apps button.
|
||||
private @Nullable IconButtonView mAllAppsButton;
|
||||
private Runnable mAllAppsTouchRunnable;
|
||||
private long mAllAppsButtonTouchDelayMs;
|
||||
private boolean mAllAppsTouchTriggered;
|
||||
@Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
|
||||
|
||||
// Only non-null when device supports having an All Apps button, or Recent Apps.
|
||||
private @Nullable IconButtonView mTaskbarDivider;
|
||||
// Only non-null when device supports having an All Apps button.
|
||||
@Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
|
||||
|
||||
/**
|
||||
* Whether the divider is between Hotseat icons and Recents,
|
||||
@@ -173,55 +164,14 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
// Needed to draw folder leave-behind when opening one.
|
||||
setWillNotDraw(false);
|
||||
|
||||
mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
|
||||
.inflate(R.layout.taskbar_all_apps_button, this, false);
|
||||
mAllAppsButton.setIconDrawable(resources.getDrawable(
|
||||
getAllAppsButton(isTransientTaskbar)));
|
||||
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
|
||||
mAllAppsButton.setForegroundTint(
|
||||
mActivityContext.getColor(R.color.all_apps_button_color));
|
||||
mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
|
||||
|
||||
if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
|
||||
mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
|
||||
R.layout.taskbar_divider,
|
||||
this, false);
|
||||
mTaskbarDivider.setIconDrawable(
|
||||
resources.getDrawable(R.drawable.taskbar_divider_button));
|
||||
mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
|
||||
mTaskbarDividerContainer = new TaskbarDividerContainer(context);
|
||||
}
|
||||
|
||||
// TODO: Disable touch events on QSB otherwise it can crash.
|
||||
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
|
||||
|
||||
// Default long press (touch) delay = 400ms
|
||||
mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
private int getAllAppsButton(boolean isTransientTaskbar) {
|
||||
boolean shouldSelectTransientIcon =
|
||||
(isTransientTaskbar || enableTaskbarPinning())
|
||||
&& !mActivityContext.isThreeButtonNav();
|
||||
if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
|
||||
return shouldSelectTransientIcon
|
||||
? R.drawable.ic_transient_taskbar_all_apps_search_button
|
||||
: R.drawable.ic_taskbar_all_apps_search_button;
|
||||
} else {
|
||||
return shouldSelectTransientIcon
|
||||
? R.drawable.ic_transient_taskbar_all_apps_button
|
||||
: R.drawable.ic_taskbar_all_apps_button;
|
||||
}
|
||||
}
|
||||
|
||||
@DimenRes
|
||||
public int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
|
||||
if (isTransientTaskbar) {
|
||||
return R.dimen.transient_taskbar_all_apps_button_translation_x_offset;
|
||||
} else {
|
||||
return ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()
|
||||
? R.dimen.taskbar_all_apps_search_button_translation_x_offset
|
||||
: R.dimen.taskbar_all_apps_button_translation_x_offset;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -306,27 +256,11 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
mIconClickListener = mControllerCallbacks.getIconOnClickListener();
|
||||
mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
|
||||
|
||||
if (mAllAppsButton != null) {
|
||||
mAllAppsButton.setOnClickListener(this::onAllAppsButtonClick);
|
||||
mAllAppsButton.setOnLongClickListener(this::onAllAppsButtonLongClick);
|
||||
mAllAppsButton.setOnTouchListener(this::onAllAppsButtonTouch);
|
||||
mAllAppsButton.setHapticFeedbackEnabled(
|
||||
mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
|
||||
mAllAppsTouchRunnable = () -> {
|
||||
mControllerCallbacks.triggerAllAppsButtonLongClick();
|
||||
mAllAppsTouchTriggered = true;
|
||||
};
|
||||
AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(mContext);
|
||||
if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
|
||||
&& assistStateManager.getLPNHDurationMillis().isPresent()) {
|
||||
mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
|
||||
}
|
||||
if (mAllAppsButtonContainer != null) {
|
||||
mAllAppsButtonContainer.setUpCallbacks(callbacks);
|
||||
}
|
||||
if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
|
||||
mTaskbarDivider.setOnLongClickListener(
|
||||
mControllerCallbacks.getTaskbarDividerLongClickListener());
|
||||
mTaskbarDivider.setOnTouchListener(
|
||||
mControllerCallbacks.getTaskbarDividerRightClickListener());
|
||||
if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
|
||||
mTaskbarDividerContainer.setUpCallbacks(callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,11 +282,11 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
int numViewsAnimated = 0;
|
||||
mAddedDividerForRecents = false;
|
||||
|
||||
if (mAllAppsButton != null) {
|
||||
removeView(mAllAppsButton);
|
||||
if (mAllAppsButtonContainer != null) {
|
||||
removeView(mAllAppsButtonContainer);
|
||||
|
||||
if (mTaskbarDivider != null) {
|
||||
removeView(mTaskbarDivider);
|
||||
if (mTaskbarDividerContainer != null) {
|
||||
removeView(mTaskbarDividerContainer);
|
||||
}
|
||||
}
|
||||
removeView(mQsb);
|
||||
@@ -439,8 +373,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
nextViewIndex++;
|
||||
}
|
||||
|
||||
if (mTaskbarDivider != null && !recentTasks.isEmpty()) {
|
||||
addView(mTaskbarDivider, nextViewIndex++);
|
||||
if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
|
||||
addView(mTaskbarDividerContainer, nextViewIndex++);
|
||||
mAddedDividerForRecents = true;
|
||||
}
|
||||
|
||||
@@ -504,12 +438,14 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
removeAndRecycle(getChildAt(nextViewIndex));
|
||||
}
|
||||
|
||||
if (mAllAppsButton != null) {
|
||||
addView(mAllAppsButton, mIsRtl ? hotseatItemInfos.length : 0);
|
||||
if (mAllAppsButtonContainer != null) {
|
||||
addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
|
||||
|
||||
// If there are no recent tasks, add divider after All Apps (unless it's the only view).
|
||||
if (!mAddedDividerForRecents && mTaskbarDivider != null && getChildCount() > 1) {
|
||||
addView(mTaskbarDivider, mIsRtl ? (getChildCount() - 1) : 1);
|
||||
if (!mAddedDividerForRecents
|
||||
&& mTaskbarDividerContainer != null
|
||||
&& getChildCount() > 1) {
|
||||
addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
|
||||
}
|
||||
}
|
||||
if (mActivityContext.getDeviceProfile().isQsbInline) {
|
||||
@@ -637,7 +573,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
|
||||
int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
|
||||
child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
|
||||
} else if (child == mTaskbarDivider) {
|
||||
} else if (child == mTaskbarDividerContainer) {
|
||||
iconEnd += mItemMarginLeftRight;
|
||||
int iconStart = iconEnd - mIconTouchSize;
|
||||
child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
|
||||
@@ -727,16 +663,16 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
* Returns the all apps button in the taskbar.
|
||||
*/
|
||||
@Nullable
|
||||
public View getAllAppsButtonView() {
|
||||
return mAllAppsButton;
|
||||
public TaskbarAllAppsButtonContainer getAllAppsButtonContainer() {
|
||||
return mAllAppsButtonContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the taskbar divider in the taskbar.
|
||||
*/
|
||||
@Nullable
|
||||
public View getTaskbarDividerView() {
|
||||
return mTaskbarDivider;
|
||||
public TaskbarDividerContainer getTaskbarDividerViewContainer() {
|
||||
return mTaskbarDividerContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -832,48 +768,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
}
|
||||
}
|
||||
}
|
||||
return mAllAppsButton;
|
||||
}
|
||||
|
||||
private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mAllAppsTouchTriggered = false;
|
||||
MAIN_EXECUTOR.getHandler().postDelayed(
|
||||
mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
cancelAllAppsButtonTouch();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void cancelAllAppsButtonTouch() {
|
||||
MAIN_EXECUTOR.getHandler().removeCallbacks(mAllAppsTouchRunnable);
|
||||
// ACTION_UP is first triggered, then click listener / long-click listener is triggered on
|
||||
// the next frame, so we need to post twice and delay the reset.
|
||||
if (mAllAppsButton != null) {
|
||||
mAllAppsButton.post(() -> {
|
||||
mAllAppsButton.post(() -> {
|
||||
mAllAppsTouchTriggered = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void onAllAppsButtonClick(View view) {
|
||||
if (!mAllAppsTouchTriggered) {
|
||||
mControllerCallbacks.triggerAllAppsButtonClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle long click from Switch Access and Voice Access
|
||||
private boolean onAllAppsButtonLongClick(View view) {
|
||||
if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
|
||||
&& !mAllAppsTouchTriggered) {
|
||||
mControllerCallbacks.triggerAllAppsButtonLongClick();
|
||||
}
|
||||
return true;
|
||||
return mAllAppsButtonContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class TaskbarViewCallbacks {
|
||||
}
|
||||
|
||||
/** Trigger All Apps button click action. */
|
||||
protected void triggerAllAppsButtonClick(View v) {
|
||||
public void triggerAllAppsButtonClick(View v) {
|
||||
InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
|
||||
/* tag= */ "TASKBAR_BUTTON");
|
||||
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
|
||||
@@ -59,7 +59,7 @@ public class TaskbarViewCallbacks {
|
||||
}
|
||||
|
||||
/** Trigger All Apps button long click action. */
|
||||
protected void triggerAllAppsButtonLongClick() {
|
||||
public void triggerAllAppsButtonLongClick() {
|
||||
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,11 @@ public class TaskbarViewCallbacks {
|
||||
};
|
||||
}
|
||||
|
||||
/** Check to see if we support long press on taskbar divider */
|
||||
public boolean supportsDividerLongPress() {
|
||||
return !mActivity.isThreeButtonNav();
|
||||
}
|
||||
|
||||
public View.OnTouchListener getTaskbarDividerRightClickListener() {
|
||||
return (v, event) -> {
|
||||
if (event.isFromSource(InputDevice.SOURCE_MOUSE)
|
||||
|
||||
@@ -72,7 +72,6 @@ import com.android.launcher3.util.LauncherBindableItemsContainer;
|
||||
import com.android.launcher3.util.MultiPropertyFactory;
|
||||
import com.android.launcher3.util.MultiTranslateDelegate;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.views.IconButtonView;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
@@ -299,7 +298,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
|
||||
@Nullable
|
||||
public View getAllAppsButtonView() {
|
||||
return mTaskbarView.getAllAppsButtonView();
|
||||
return mTaskbarView.getAllAppsButtonContainer();
|
||||
}
|
||||
|
||||
public AnimatedFloat getTaskbarIconScaleForStash() {
|
||||
@@ -366,9 +365,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
View[] iconViews = mTaskbarView.getIconViews();
|
||||
float scale = mTaskbarIconTranslationXForPinning.value;
|
||||
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
|
||||
mTaskbarView.getAllAppsButtonTranslationXOffset(true));
|
||||
mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(true));
|
||||
float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
|
||||
mTaskbarView.getAllAppsButtonTranslationXOffset(false));
|
||||
mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(false));
|
||||
|
||||
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
|
||||
persistentTaskbarAllAppsOffset);
|
||||
@@ -383,7 +382,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
}
|
||||
|
||||
if (mActivity.isThreeButtonNav()) {
|
||||
((IconButtonView) mTaskbarView.getAllAppsButtonView())
|
||||
mTaskbarView.getAllAppsButtonContainer()
|
||||
.setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
|
||||
return;
|
||||
}
|
||||
@@ -408,8 +407,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
-finalMarginScale * (iconIndex - halfIconCount));
|
||||
}
|
||||
|
||||
if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
|
||||
((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
|
||||
if (iconView.equals(mTaskbarView.getAllAppsButtonContainer())) {
|
||||
mTaskbarView.getAllAppsButtonContainer().setTranslationXForTaskbarAllAppsIcon(
|
||||
allAppIconTranslateRange);
|
||||
}
|
||||
}
|
||||
@@ -537,7 +536,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
}
|
||||
|
||||
public View getTaskbarDividerView() {
|
||||
return mTaskbarView.getTaskbarDividerView();
|
||||
return mTaskbarView.getTaskbarDividerViewContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -753,8 +752,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
int firstRecentTaskIndex = -1;
|
||||
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
|
||||
View child = mTaskbarView.getChildAt(i);
|
||||
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
|
||||
boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerView();
|
||||
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
|
||||
boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
|
||||
boolean isRecentTask = child.getTag() instanceof GroupTask;
|
||||
// TODO(b/343522351): show recents on the home screen.
|
||||
final boolean isRecentsInHotseat = false;
|
||||
|
||||
+11
-16
@@ -16,7 +16,6 @@
|
||||
package com.android.launcher3.taskbar.allapps;
|
||||
|
||||
import static com.android.app.animation.Interpolators.EMPHASIZED;
|
||||
import static com.android.launcher3.Flags.enablePredictiveBackGesture;
|
||||
import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
|
||||
import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
|
||||
|
||||
@@ -193,14 +192,12 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mActivityContext.addOnDeviceProfileChangeListener(this);
|
||||
if (enablePredictiveBackGesture()) {
|
||||
mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
|
||||
mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
|
||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
||||
if (dispatcher != null) {
|
||||
dispatcher.registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
|
||||
}
|
||||
mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
|
||||
mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
|
||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
||||
if (dispatcher != null) {
|
||||
dispatcher.registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,13 +205,11 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mActivityContext.removeOnDeviceProfileChangeListener(this);
|
||||
if (enablePredictiveBackGesture()) {
|
||||
mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
|
||||
mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
|
||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
||||
if (dispatcher != null) {
|
||||
dispatcher.unregisterOnBackInvokedCallback(this);
|
||||
}
|
||||
mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
|
||||
mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
|
||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
||||
if (dispatcher != null) {
|
||||
dispatcher.unregisterOnBackInvokedCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1473,8 +1473,9 @@ public class BubbleBarView extends FrameLayout {
|
||||
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();
|
||||
|
||||
@@ -80,12 +80,14 @@ public class BubbleBarViewController {
|
||||
|
||||
// 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 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 +127,7 @@ public class BubbleBarViewController {
|
||||
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,8 +257,8 @@ public class BubbleBarViewController {
|
||||
return mBubbleBarAlpha;
|
||||
}
|
||||
|
||||
public AnimatedFloat getBubbleBarScale() {
|
||||
return mBubbleBarScale;
|
||||
public AnimatedFloat getBubbleBarScaleY() {
|
||||
return mBubbleBarScaleY;
|
||||
}
|
||||
|
||||
public AnimatedFloat getBubbleBarTranslationY() {
|
||||
@@ -267,6 +269,27 @@ public class BubbleBarViewController {
|
||||
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.
|
||||
*/
|
||||
@@ -474,17 +497,20 @@ public class BubbleBarViewController {
|
||||
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;
|
||||
mBarView.setScaleX(scale);
|
||||
private void updateTranslationY() {
|
||||
mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
|
||||
+ mBubbleBarStashTranslationY);
|
||||
}
|
||||
|
||||
private void updateScaleY(float scale) {
|
||||
mBarView.setScaleY(scale);
|
||||
}
|
||||
|
||||
@@ -793,6 +819,7 @@ public class BubbleBarViewController {
|
||||
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 {
|
||||
|
||||
+76
-45
@@ -21,6 +21,7 @@ import static android.view.View.VISIBLE;
|
||||
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.MotionEvent;
|
||||
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.taskbar.bubbles.stashing.BubbleStashController;
|
||||
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.handles.RegionSamplingHelper;
|
||||
|
||||
/**
|
||||
* Handles properties/data collection, then passes the results to our stashed handle View to render.
|
||||
@@ -49,23 +51,29 @@ public class BubbleStashedHandleViewController {
|
||||
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 @@ public class BubbleStashedHandleViewController {
|
||||
mActivity = activity;
|
||||
mStashedHandleView = stashedHandleView;
|
||||
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
|
||||
mStashedHandleAlpha.setUpdateVisibility(true);
|
||||
}
|
||||
|
||||
/** Initialize controller. */
|
||||
@@ -84,26 +93,31 @@ public class BubbleStashedHandleViewController {
|
||||
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 @@ public class BubbleStashedHandleViewController {
|
||||
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() {
|
||||
@@ -168,13 +179,6 @@ public class BubbleStashedHandleViewController {
|
||||
return mStashedHandleHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -242,7 +246,20 @@ public class BubbleStashedHandleViewController {
|
||||
* 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 +280,17 @@ public class BubbleStashedHandleViewController {
|
||||
* 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 +307,21 @@ public class BubbleStashedHandleViewController {
|
||||
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 +330,7 @@ public class BubbleStashedHandleViewController {
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -237,7 +237,11 @@ public class BubbleView extends ConstraintLayout {
|
||||
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 @@ public class BubbleView extends ConstraintLayout {
|
||||
}
|
||||
|
||||
void setBadgeScale(float fraction) {
|
||||
mAppIcon.setScaleX(fraction);
|
||||
mAppIcon.setScaleY(fraction);
|
||||
if (mAppIcon.getVisibility() == VISIBLE) {
|
||||
mAppIcon.setScaleX(fraction);
|
||||
mAppIcon.setScaleY(fraction);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasUnseenContent() {
|
||||
|
||||
+3
-3
@@ -179,10 +179,10 @@ interface BubbleStashController {
|
||||
/** How long to stash/unstash. */
|
||||
const val BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE.toLong()
|
||||
|
||||
const val BAR_STASH_ALPHA_DURATION = 50L
|
||||
const val BAR_STASH_ALPHA_DELAY = 33L
|
||||
|
||||
/** 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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ class PersistentBubbleStashController(
|
||||
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() {
|
||||
|
||||
+120
-72
@@ -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.bubbles.BubbleBarViewController
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
|
||||
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DELAY
|
||||
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DURATION
|
||||
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 kotlin.math.max
|
||||
|
||||
class TransientBubbleStashController(
|
||||
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
|
||||
resources: Resources
|
||||
private val context: Context
|
||||
) : BubbleStashController {
|
||||
|
||||
private lateinit var bubbleBarViewController: BubbleBarViewController
|
||||
@@ -50,14 +56,20 @@ class TransientBubbleStashController(
|
||||
// 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 val handleCenterFromScreenBottom =
|
||||
context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
|
||||
|
||||
private var animator: AnimatorSet? = null
|
||||
|
||||
@@ -136,12 +148,9 @@ class TransientBubbleStashController(
|
||||
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
|
||||
// bubble bar has only alpha property, getting it at index 0
|
||||
bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
|
||||
bubbleBarScale = bubbleBarViewController.bubbleBarScale
|
||||
bubbleBarScale = bubbleBarViewController.bubbleBarScaleY
|
||||
stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
|
||||
stashHandleViewAlpha =
|
||||
bubbleStashedHandleViewController
|
||||
?.stashedHandleAlpha
|
||||
?.get(StashedHandleViewController.ALPHA_INDEX_STASHED)
|
||||
stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0)
|
||||
}
|
||||
|
||||
private fun animateAfterUnlock() {
|
||||
@@ -179,7 +188,7 @@ class TransientBubbleStashController(
|
||||
stashHandleViewAlpha?.value = 1f
|
||||
this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
|
||||
bubbleBarAlpha.setValue(0f)
|
||||
bubbleBarScale.updateValue(STASHED_BAR_SCALE)
|
||||
bubbleBarScale.updateValue(getStashScale())
|
||||
isStashed = true
|
||||
onIsStashedChanged()
|
||||
}
|
||||
@@ -223,11 +232,11 @@ class TransientBubbleStashController(
|
||||
// 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 +254,13 @@ class TransientBubbleStashController(
|
||||
override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
|
||||
|
||||
private fun getStashTranslation(): Float {
|
||||
return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
|
||||
return bubbleBarTranslationY / 2f
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun getStashScale(): Float {
|
||||
val handleHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
|
||||
return handleHeight / bubbleBarViewController.bubbleBarCollapsedHeight
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,61 +273,84 @@ class TransientBubbleStashController(
|
||||
@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 BAR_STASH_ALPHA_DURATION
|
||||
val alphaDelay = if (isStashed) BAR_STASH_ALPHA_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 scaleTarget = if (isStashed) getStashScale() else 1f
|
||||
animatorSet.play(
|
||||
bubbleBarScale.animateToValue(scaleTarget).apply {
|
||||
this.duration = duration
|
||||
this.interpolator = EMPHASIZED
|
||||
this.setBubbleBarPivotDuringAnim(0.5f, 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 onIsStashedChanged() {
|
||||
controllersAfterInitAction.runAfterInit {
|
||||
taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
|
||||
@@ -363,13 +401,23 @@ class TransientBubbleStashController(
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+78
-19
@@ -18,18 +18,27 @@ package com.android.launcher3.taskbar.customization
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color.TRANSPARENT
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.view.setPadding
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.Utilities.dpToPx
|
||||
import com.android.launcher3.config.FeatureFlags
|
||||
import com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR
|
||||
import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
|
||||
import com.android.launcher3.taskbar.TaskbarActivityContext
|
||||
import com.android.launcher3.taskbar.TaskbarViewCallbacks
|
||||
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
|
||||
import com.android.launcher3.views.ActivityContext
|
||||
import com.android.launcher3.views.IconButtonView
|
||||
import com.android.quickstep.DeviceConfigWrapper
|
||||
import com.android.quickstep.util.AssistStateManager
|
||||
|
||||
/** Taskbar all apps button container for customizable taskbar. */
|
||||
class TaskbarAllAppsButtonContainer
|
||||
@@ -38,19 +47,21 @@ constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : LinearLayout(context, attrs), TaskbarContainer {
|
||||
) : IconButtonView(context, attrs), TaskbarContainer {
|
||||
|
||||
private val allAppsButton: IconButtonView =
|
||||
LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, this, false)
|
||||
as IconButtonView
|
||||
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
|
||||
private var allAppsTouchTriggered = false
|
||||
private var allAppsTouchRunnable: Runnable? = null
|
||||
private var allAppsButtonTouchDelayMs: Long = ViewConfiguration.getLongPressTimeout().toLong()
|
||||
private lateinit var taskbarViewCallbacks: TaskbarViewCallbacks
|
||||
|
||||
override val spaceNeeded: Int
|
||||
get() {
|
||||
return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
|
||||
return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
|
||||
}
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, null, false)
|
||||
setUpIcon()
|
||||
}
|
||||
|
||||
@@ -58,24 +69,39 @@ constructor(
|
||||
private fun setUpIcon() {
|
||||
val drawable =
|
||||
resources.getDrawable(
|
||||
getAllAppsButton(activityContext.taskbarFeatureEvaluator!!.isTransient)
|
||||
getAllAppsButton(activityContext.taskbarFeatureEvaluator.isTransient)
|
||||
)
|
||||
val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
|
||||
backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
|
||||
setIconDrawable(drawable)
|
||||
setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
|
||||
setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
|
||||
}
|
||||
|
||||
allAppsButton.setIconDrawable(drawable)
|
||||
allAppsButton.setPadding(padding)
|
||||
allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
|
||||
|
||||
// TODO(b/356465292) : add click listeners in future cl
|
||||
addView(allAppsButton)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
|
||||
taskbarViewCallbacks = callbacks
|
||||
setOnClickListener(this::onAllAppsButtonClick)
|
||||
setOnLongClickListener(this::onAllAppsButtonLongClick)
|
||||
setOnTouchListener(this::onAllAppsButtonTouch)
|
||||
isHapticFeedbackEnabled = taskbarViewCallbacks.isAllAppsButtonHapticFeedbackEnabled()
|
||||
allAppsTouchRunnable = Runnable {
|
||||
taskbarViewCallbacks.triggerAllAppsButtonLongClick()
|
||||
allAppsTouchTriggered = true
|
||||
}
|
||||
val assistStateManager = AssistStateManager.INSTANCE[mContext]
|
||||
if (
|
||||
DeviceConfigWrapper.get().customLpaaThresholds &&
|
||||
assistStateManager.lpnhDurationMillis.isPresent
|
||||
) {
|
||||
allAppsButtonTouchDelayMs = assistStateManager.lpnhDurationMillis.get()
|
||||
}
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
private fun getAllAppsButton(isTransientTaskbar: Boolean): Int {
|
||||
val shouldSelectTransientIcon =
|
||||
isTransientTaskbar ||
|
||||
(FeatureFlags.enableTaskbarPinning() && !activityContext.isThreeButtonNav)
|
||||
return if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
|
||||
isTransientTaskbar || (enableTaskbarPinning() && !activityContext.isThreeButtonNav)
|
||||
return if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
|
||||
if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button
|
||||
else R.drawable.ic_taskbar_all_apps_search_button
|
||||
} else {
|
||||
@@ -88,10 +114,43 @@ constructor(
|
||||
fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int {
|
||||
return if (isTransientTaskbar) {
|
||||
R.dimen.transient_taskbar_all_apps_button_translation_x_offset
|
||||
} else if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
|
||||
} else if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
|
||||
R.dimen.taskbar_all_apps_search_button_translation_x_offset
|
||||
} else {
|
||||
R.dimen.taskbar_all_apps_button_translation_x_offset
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAllAppsButtonTouch(view: View, ev: MotionEvent): Boolean {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
allAppsTouchTriggered = false
|
||||
MAIN_EXECUTOR.handler.postDelayed(allAppsTouchRunnable!!, allAppsButtonTouchDelayMs)
|
||||
}
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_CANCEL -> cancelAllAppsButtonTouch()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun cancelAllAppsButtonTouch() {
|
||||
MAIN_EXECUTOR.handler.removeCallbacks(allAppsTouchRunnable!!)
|
||||
// ACTION_UP is first triggered, then click listener / long-click listener is triggered on
|
||||
// the next frame, so we need to post twice and delay the reset.
|
||||
this.post { this.post { allAppsTouchTriggered = false } }
|
||||
}
|
||||
|
||||
private fun onAllAppsButtonClick(view: View) {
|
||||
if (!allAppsTouchTriggered) {
|
||||
taskbarViewCallbacks.triggerAllAppsButtonClick(view)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle long click from Switch Access and Voice Access
|
||||
private fun onAllAppsButtonLongClick(view: View): Boolean {
|
||||
if (!MAIN_EXECUTOR.handler.hasCallbacks(allAppsTouchRunnable!!) && !allAppsTouchTriggered) {
|
||||
taskbarViewCallbacks.triggerAllAppsButtonLongClick()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+14
-13
@@ -18,13 +18,15 @@ package com.android.launcher3.taskbar.customization
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color.TRANSPARENT
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.setPadding
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.Utilities.dpToPx
|
||||
import com.android.launcher3.taskbar.TaskbarActivityContext
|
||||
import com.android.launcher3.taskbar.TaskbarViewCallbacks
|
||||
import com.android.launcher3.views.ActivityContext
|
||||
import com.android.launcher3.views.IconButtonView
|
||||
|
||||
@@ -35,31 +37,30 @@ constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : LinearLayout(context, attrs), TaskbarContainer {
|
||||
|
||||
private val taskbarDivider: IconButtonView =
|
||||
LayoutInflater.from(context).inflate(R.layout.taskbar_divider, this, false)
|
||||
as IconButtonView
|
||||
) : IconButtonView(context, attrs), TaskbarContainer {
|
||||
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
|
||||
|
||||
override val spaceNeeded: Int
|
||||
get() {
|
||||
return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
|
||||
return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
|
||||
}
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.taskbar_divider, null, false)
|
||||
setUpIcon()
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
fun setUpIcon() {
|
||||
backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
|
||||
val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
|
||||
val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
|
||||
setIconDrawable(drawable)
|
||||
setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
|
||||
}
|
||||
|
||||
taskbarDivider.setIconDrawable(drawable)
|
||||
taskbarDivider.setPadding(padding)
|
||||
|
||||
// TODO(b/356465292):: add click listeners in future cl
|
||||
addView(taskbarDivider)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
|
||||
setOnLongClickListener(callbacks.taskbarDividerLongClickListener)
|
||||
setOnTouchListener(callbacks.taskbarDividerRightClickListener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ package com.android.launcher3.taskbar.customization
|
||||
/** Taskbar Icon Specs */
|
||||
object TaskbarIconSpecs {
|
||||
|
||||
val iconSize40dp = TaskbarIconSize(40)
|
||||
val iconSize44dp = TaskbarIconSize(44)
|
||||
val iconSize48dp = TaskbarIconSize(48)
|
||||
val iconSize52dp = TaskbarIconSize(52)
|
||||
// Mapping of visual icon size to icon specs value http://b/235886078
|
||||
val iconSize40dp = TaskbarIconSize(44)
|
||||
val iconSize44dp = TaskbarIconSize(48)
|
||||
val iconSize48dp = TaskbarIconSize(52)
|
||||
val iconSize52dp = TaskbarIconSize(57)
|
||||
|
||||
val transientTaskbarIconSizes = arrayOf(iconSize44dp, iconSize48dp, iconSize52dp)
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ class TaskbarSpecsEvaluator(
|
||||
numRows: Int = taskbarActivityContext.deviceProfile.inv.numRows,
|
||||
numColumns: Int = taskbarActivityContext.deviceProfile.inv.numColumns,
|
||||
) {
|
||||
var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numRows, numColumns)
|
||||
var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numColumns, numRows)
|
||||
|
||||
// TODO(b/341146605) : initialize it to taskbar container in later cl.
|
||||
private var taskbarContainer: List<TaskbarContainer> = emptyList()
|
||||
|
||||
val taskbarIconPadding: Int =
|
||||
if (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size > taskbarIconSize.size) {
|
||||
(TaskbarIconSpecs.minimumTaskbarIconTouchSize.size - taskbarIconSize.size) / 2
|
||||
if (TaskbarIconSpecs.iconSize52dp.size > taskbarIconSize.size) {
|
||||
(TaskbarIconSpecs.iconSize52dp.size - taskbarIconSize.size) / 2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -44,10 +44,10 @@ class TaskbarSpecsEvaluator(
|
||||
TaskbarIconSpecs.defaultPersistentIconMargin
|
||||
}
|
||||
|
||||
fun getIconSizeByGrid(row: Int, column: Int): TaskbarIconSize {
|
||||
fun getIconSizeByGrid(columns: Int, rows: Int): TaskbarIconSize {
|
||||
return if (taskbarFeatureEvaluator.isTransient) {
|
||||
TaskbarIconSpecs.transientTaskbarIconSizeByGridSize.getOrDefault(
|
||||
TransientTaskbarIconSizeKey(row, column, taskbarFeatureEvaluator.isLandscape),
|
||||
TransientTaskbarIconSizeKey(columns, rows, taskbarFeatureEvaluator.isLandscape),
|
||||
TaskbarIconSpecs.defaultTransientIconSize,
|
||||
)
|
||||
} else {
|
||||
@@ -102,6 +102,6 @@ class TaskbarSpecsEvaluator(
|
||||
|
||||
data class TaskbarIconSize(val size: Int)
|
||||
|
||||
data class TransientTaskbarIconSizeKey(val row: Int, val column: Int, val isLandscape: Boolean)
|
||||
data class TransientTaskbarIconSizeKey(val columns: Int, val rows: Int, val isLandscape: Boolean)
|
||||
|
||||
data class TaskbarIconMarginSize(val size: Int)
|
||||
|
||||
@@ -379,12 +379,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
|
||||
}
|
||||
|
||||
@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 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
|
||||
|
||||
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);
|
||||
|
||||
@@ -22,7 +22,6 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
|
||||
|
||||
import static com.android.app.animation.Interpolators.EMPHASIZED;
|
||||
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
|
||||
import static com.android.launcher3.Flags.enablePredictiveBackGesture;
|
||||
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
|
||||
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
|
||||
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
|
||||
@@ -499,10 +498,8 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
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)
|
||||
@@ -696,9 +693,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
// Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
|
||||
// work, we must opt-in BEFORE registering back dispatcher. So we need to call
|
||||
// setEnableOnBackInvokedCallback() before super.onCreate()
|
||||
if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
|
||||
getApplicationInfo().setEnableOnBackInvokedCallback(true);
|
||||
}
|
||||
getApplicationInfo().setEnableOnBackInvokedCallback(true);
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
|
||||
@@ -910,8 +905,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
// event won't go through ViewRootImpl#InputStage#onProcess.
|
||||
// So when receive back key, try to do the same check thing in
|
||||
// ViewRootImpl#NativePreImeInputStage#onProcess
|
||||
if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
|
||||
|| event.getKeyCode() != KeyEvent.KEYCODE_BACK
|
||||
if (event.getKeyCode() != KeyEvent.KEYCODE_BACK
|
||||
|| event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
|
||||
return false;
|
||||
}
|
||||
@@ -922,10 +916,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
|
||||
@Override
|
||||
protected void registerBackDispatcher() {
|
||||
if (!enablePredictiveBackGesture()) {
|
||||
super.registerBackDispatcher();
|
||||
return;
|
||||
}
|
||||
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||
new OnBackAnimationCallback() {
|
||||
@@ -1279,10 +1269,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
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);
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.android.launcher3.uioverrides.states;
|
||||
|
||||
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 @@ public class BackgroundAppState extends OverviewState {
|
||||
|
||||
@Override
|
||||
public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
|
||||
if (ENABLE_SHELL_TRANSITIONS) return false;
|
||||
return super.isTaskbarAlignedWithHotseat(launcher);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -97,6 +97,7 @@ import android.window.PictureInPictureSurfaceTransaction;
|
||||
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 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* 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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
// 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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
}
|
||||
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
// 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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
*/
|
||||
@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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
/**
|
||||
* 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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
}
|
||||
}
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
}
|
||||
|
||||
private void animateSplashScreenExit(
|
||||
@NonNull T activity,
|
||||
@NonNull RECENTS_CONTAINER activity,
|
||||
@NonNull RemoteAnimationTarget[] appearedTaskTargets,
|
||||
@NonNull RemoteAnimationTarget[] animatingTargets) {
|
||||
ViewGroup splashView = activity.getDragLayer();
|
||||
|
||||
@@ -68,8 +68,6 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_
|
||||
|
||||
public abstract void onAssistantVisibilityChanged(float assistantVisibility);
|
||||
|
||||
public abstract boolean allowMinimizeSplitScreen();
|
||||
|
||||
public abstract boolean isResumed();
|
||||
|
||||
public abstract boolean isStarted();
|
||||
|
||||
@@ -132,12 +132,6 @@ public final class FallbackActivityInterface extends
|
||||
return target.screenSpaceBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowMinimizeSplitScreen() {
|
||||
// TODO: Remove this once b/77875376 is fixed
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAllAppsFromOverview() {
|
||||
return false;
|
||||
|
||||
@@ -270,11 +270,6 @@ public final class LauncherActivityInterface extends
|
||||
return homeBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowMinimizeSplitScreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAllAppsFromOverview() {
|
||||
return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
|
||||
|
||||
@@ -62,8 +62,8 @@ import java.util.List;
|
||||
/**
|
||||
* 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 @@ public class LauncherSwipeHandlerV2 extends
|
||||
|| !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
|
||||
|
||||
mContainer.getRootView().setForceHideBackArrow(true);
|
||||
if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
|
||||
mContainer.setHintUserWillBeActive();
|
||||
}
|
||||
|
||||
if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
|
||||
return new LauncherHomeAnimationFactory() {
|
||||
|
||||
@@ -33,6 +33,8 @@ import com.android.launcher3.logging.StatsLogManager
|
||||
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.quickstep.views.TaskView
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
*/
|
||||
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 commands from the queue */
|
||||
fun clearPendingCommands() {
|
||||
Log.d(TAG, "clearing pending commands: $commandQueue")
|
||||
commandQueue.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,67 +109,76 @@ class OverviewCommandHelper(
|
||||
*/
|
||||
@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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
// 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 @@ class OverviewCommandHelper(
|
||||
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 @@ class OverviewCommandHelper(
|
||||
|
||||
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 @@ class OverviewCommandHelper(
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,17 +54,14 @@ public class RecentsAnimationCallbacks implements
|
||||
|
||||
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 @@ public class RecentsAnimationCallbacks implements
|
||||
}
|
||||
|
||||
mController = new RecentsAnimationController(animationController,
|
||||
mAllowMinimizeSplitScreen, this::onAnimationFinished);
|
||||
this::onAnimationFinished);
|
||||
if (mCancelled) {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
|
||||
mController::finishAnimationToApp);
|
||||
@@ -219,7 +216,6 @@ public class RecentsAnimationCallbacks implements
|
||||
public void dump(String prefix, PrintWriter pw) {
|
||||
pw.println(prefix + "RecentsAnimationCallbacks:");
|
||||
|
||||
pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
|
||||
pw.println(prefix + "\tmCancelled=" + mCancelled);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.android.quickstep;
|
||||
|
||||
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 @@ public class RecentsAnimationController {
|
||||
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,33 +80,16 @@ public class RecentsAnimationController {
|
||||
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 class RecentsAnimationController {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -60,9 +60,8 @@ import java.io.PrintWriter;
|
||||
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 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
|
||||
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 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
}
|
||||
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()
|
||||
|
||||
@@ -109,6 +109,7 @@ import com.android.launcher3.util.PluginManagerWrapper;
|
||||
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 @@ public class TouchInteractionService extends Service {
|
||||
return;
|
||||
}
|
||||
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
|
||||
tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -256,10 +257,9 @@ public class TouchInteractionService extends Service {
|
||||
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 @@ public class TouchInteractionService extends Service {
|
||||
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 @@ public class TouchInteractionService extends Service {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ public class BubbleBarInputConsumer implements InputConsumer {
|
||||
|
||||
private boolean mSwipeUpOnBubbleHandle;
|
||||
private boolean mPassedTouchSlop;
|
||||
private boolean mStashedOrCollapsedOnDown;
|
||||
|
||||
private final int mTouchSlop;
|
||||
private final PointF mDownPos = new PointF();
|
||||
@@ -69,13 +70,13 @@ public class BubbleBarInputConsumer implements InputConsumer {
|
||||
|
||||
@Override
|
||||
public void onMotionEvent(MotionEvent ev) {
|
||||
final boolean isStashed = mBubbleStashController.isStashed();
|
||||
final int action = ev.getAction();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
mDownPos.set(ev.getX(), ev.getY());
|
||||
mLastPos.set(mDownPos);
|
||||
mStashedOrCollapsedOnDown = mBubbleStashController.isStashed() || isCollapsed();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
@@ -89,7 +90,7 @@ public class BubbleBarInputConsumer implements InputConsumer {
|
||||
if (!mPassedTouchSlop) {
|
||||
mPassedTouchSlop = Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
|
||||
}
|
||||
if ((isCollapsed() || isStashed) && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
|
||||
if (mStashedOrCollapsedOnDown && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
|
||||
boolean verticalGesture = Math.abs(dY) > Math.abs(dX);
|
||||
if (verticalGesture && !mBubbleDragController.isDragging()) {
|
||||
mSwipeUpOnBubbleHandle = true;
|
||||
@@ -102,11 +103,10 @@ public class BubbleBarInputConsumer implements InputConsumer {
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForTap;
|
||||
if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop) {
|
||||
if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop
|
||||
&& mStashedOrCollapsedOnDown) {
|
||||
// Taps on the handle / collapsed state should open the bar
|
||||
if (isStashed || isCollapsed()) {
|
||||
mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
|
||||
}
|
||||
mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
|
||||
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 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
// 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);
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.launcher3.util.DisplayController;
|
||||
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 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
|
||||
break;
|
||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
||||
if (isStashedTaskbarHovered) {
|
||||
mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
|
||||
mOverviewCommandHelper.addCommand(CommandType.HOME);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.launcher3.config.FeatureFlags;
|
||||
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 @@ public class GestureSandboxActivity extends FragmentActivity {
|
||||
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 @@ public class GestureSandboxActivity extends FragmentActivity {
|
||||
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;
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
|
||||
|
||||
public class LayoutUtils {
|
||||
|
||||
private static final float SQUARE_ASPECT_RATIO_TOLERANCE = 0.05f;
|
||||
|
||||
/**
|
||||
* The height for the swipe up motion
|
||||
*/
|
||||
@@ -61,4 +63,13 @@ public class LayoutUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ class RecentsViewUtils {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,8 +886,7 @@ public class SplitSelectStateController {
|
||||
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);
|
||||
|
||||
@@ -84,8 +84,7 @@ public class SplitWithKeyboardShortcutController {
|
||||
return;
|
||||
}
|
||||
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
|
||||
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
|
||||
false /* allowMinimizeSplitScreen */);
|
||||
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
|
||||
SplitWithKeyboardShortcutRecentsAnimationListener listener =
|
||||
new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO
|
||||
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 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isUninitialized()) return;
|
||||
positionViews();
|
||||
if (mOnTargetChangeRunnable != null) {
|
||||
boolean positionsChanged = positionViews();
|
||||
if (mOnTargetChangeRunnable != null && positionsChanged) {
|
||||
mOnTargetChangeRunnable.run();
|
||||
}
|
||||
}
|
||||
@@ -212,21 +212,43 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
|
||||
onGlobalLayout();
|
||||
}
|
||||
|
||||
/** Sets the layout parameters of the floating view and its background view child. */
|
||||
private void positionViews() {
|
||||
/**
|
||||
* Sets the layout parameters of the floating view and its background view child.
|
||||
* @return true if any of the views positions change due to this call.
|
||||
*/
|
||||
private boolean positionViews() {
|
||||
boolean positionsChanged = false;
|
||||
|
||||
LayoutParams layoutParams = (LayoutParams) getLayoutParams();
|
||||
layoutParams.setMargins(0, 0, 0, 0);
|
||||
setLayoutParams(layoutParams);
|
||||
|
||||
if (layoutParams.topMargin != 0 || layoutParams.bottomMargin != 0
|
||||
|| layoutParams.rightMargin != 0 || layoutParams.leftMargin != 0) {
|
||||
positionsChanged = true;
|
||||
layoutParams.setMargins(0, 0, 0, 0);
|
||||
setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
// FloatingWidgetView layout is forced LTR
|
||||
mBackgroundView.setTranslationX(mBackgroundPosition.left);
|
||||
mBackgroundView.setTranslationY(mBackgroundPosition.top + mIconOffsetY);
|
||||
float targetY = mBackgroundPosition.top + mIconOffsetY;
|
||||
if (mBackgroundView.getTranslationX() != mBackgroundPosition.left
|
||||
|| mBackgroundView.getTranslationY() != targetY) {
|
||||
positionsChanged = true;
|
||||
mBackgroundView.setTranslationX(mBackgroundPosition.left);
|
||||
mBackgroundView.setTranslationY(targetY);
|
||||
}
|
||||
|
||||
LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams();
|
||||
backgroundParams.leftMargin = 0;
|
||||
backgroundParams.topMargin = 0;
|
||||
backgroundParams.width = (int) mBackgroundPosition.width();
|
||||
backgroundParams.height = (int) mBackgroundPosition.height();
|
||||
mBackgroundView.setLayoutParams(backgroundParams);
|
||||
if (backgroundParams.leftMargin != 0 || backgroundParams.topMargin != 0
|
||||
|| backgroundParams.width != Math.round(mBackgroundPosition.width())
|
||||
|| backgroundParams.height != Math.round(mBackgroundPosition.height())) {
|
||||
positionsChanged = true;
|
||||
|
||||
backgroundParams.leftMargin = 0;
|
||||
backgroundParams.topMargin = 0;
|
||||
backgroundParams.width = Math.round(mBackgroundPosition.width());
|
||||
backgroundParams.height = Math.round(mBackgroundPosition.height());
|
||||
mBackgroundView.setLayoutParams(backgroundParams);
|
||||
}
|
||||
|
||||
if (mForegroundOverlayView != null) {
|
||||
sTmpMatrix.reset();
|
||||
@@ -237,8 +259,15 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
|
||||
sTmpMatrix.postScale(foregroundScale, foregroundScale);
|
||||
sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top
|
||||
+ mIconOffsetY);
|
||||
mForegroundOverlayView.setMatrix(sTmpMatrix);
|
||||
|
||||
// We use the animation matrix here, because calling setMatrix on the GhostView
|
||||
// actually sets the animation matrix, not the regular one.
|
||||
if (!sTmpMatrix.equals(mForegroundOverlayView.getAnimationMatrix())) {
|
||||
positionsChanged = true;
|
||||
mForegroundOverlayView.setMatrix(sTmpMatrix);
|
||||
}
|
||||
}
|
||||
return positionsChanged;
|
||||
}
|
||||
|
||||
private void finish(DragLayer dragLayer) {
|
||||
|
||||
@@ -3058,14 +3058,15 @@ public abstract class RecentsView<
|
||||
}
|
||||
|
||||
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 @@ public abstract class RecentsView<
|
||||
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 @@ public abstract class RecentsView<
|
||||
if (enableRefactorTaskThumbnail()) {
|
||||
mHelper.switchToScreenshot(taskView, thumbnailDatas, onFinishRunnable);
|
||||
} else {
|
||||
taskView.setShouldShowScreenshot(true);
|
||||
taskView.refreshThumbnails(thumbnailDatas);
|
||||
taskView.setShouldShowScreenshot(true, thumbnailDatas);
|
||||
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -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
|
||||
@@ -40,18 +39,6 @@ class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) {
|
||||
viewAttachedScope.cancel("RecentsView detaching from window")
|
||||
}
|
||||
|
||||
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>?,
|
||||
|
||||
@@ -79,7 +79,6 @@ import com.android.launcher3.util.rects.set
|
||||
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 @@ constructor(
|
||||
|
||||
protected var shouldShowScreenshot = false
|
||||
get() = !isRunningTask || field
|
||||
private set
|
||||
|
||||
/** Enable or disable showing border on hover and focus change */
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
|
||||
@@ -974,7 +974,13 @@ constructor(
|
||||
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
|
||||
}
|
||||
@@ -1041,14 +1047,12 @@ constructor(
|
||||
// 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()
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
|
||||
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(
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ class BubbleViewTest {
|
||||
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(), "")
|
||||
|
||||
+1
-1
@@ -870,7 +870,7 @@ class BubbleBarViewAnimatorTest {
|
||||
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 =
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ class PersistentBubbleStashControllerTest {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
+7
-8
@@ -31,7 +31,6 @@ import com.android.launcher3.taskbar.TaskbarInsetsController
|
||||
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
|
||||
@@ -59,7 +58,7 @@ class TransientBubbleStashControllerTest {
|
||||
const val HOTSEAT_TRANSLATION_Y = -45f
|
||||
const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
|
||||
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)
|
||||
@@ -90,7 +89,7 @@ class TransientBubbleStashControllerTest {
|
||||
val taskbarHotseatDimensionsProvider =
|
||||
DefaultDimensionsProvider(taskBarBottomSpace = TASKBAR_BOTTOM_SPACE)
|
||||
mTransientBubbleStashController =
|
||||
TransientBubbleStashController(taskbarHotseatDimensionsProvider, context.resources)
|
||||
TransientBubbleStashController(taskbarHotseatDimensionsProvider, context)
|
||||
setUpBubbleBarView()
|
||||
setUpBubbleBarController()
|
||||
setUpStashedHandleView()
|
||||
@@ -174,8 +173,8 @@ class TransientBubbleStashControllerTest {
|
||||
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.getStashScale())
|
||||
assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScale())
|
||||
// Handle view is visible
|
||||
assertThat(stashedHandleView.translationY).isEqualTo(0)
|
||||
assertThat(stashedHandleView.alpha).isEqualTo(1)
|
||||
@@ -243,8 +242,8 @@ class TransientBubbleStashControllerTest {
|
||||
// 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.getStashScale())
|
||||
assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScale())
|
||||
// Handle is visible at correct Y position
|
||||
assertThat(stashedHandleView.alpha).isEqualTo(1)
|
||||
assertThat(stashedHandleView.translationY).isEqualTo(0)
|
||||
@@ -306,7 +305,7 @@ class TransientBubbleStashControllerTest {
|
||||
|
||||
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
|
||||
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
|
||||
whenever(bubbleBarViewController.bubbleBarScale).thenReturn(barScale)
|
||||
whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(barScale)
|
||||
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
|
||||
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
|
||||
}
|
||||
|
||||
+276
@@ -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();
|
||||
}
|
||||
+64
@@ -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;
|
||||
}
|
||||
}
|
||||
+92
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -59,8 +59,6 @@ public class TaskAnimationManagerTest {
|
||||
|
||||
@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 =
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -109,11 +109,6 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@@ -316,7 +311,6 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
|
||||
*/
|
||||
public void setResumed() {
|
||||
addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
|
||||
removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
|
||||
}
|
||||
|
||||
public boolean isUserActive() {
|
||||
|
||||
@@ -89,7 +89,7 @@ import com.android.launcher3.util.SafeCloseable;
|
||||
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 @@ import java.util.Locale;
|
||||
* too aggressive.
|
||||
*/
|
||||
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
IconLabelDotView, DraggableView, Reorderable {
|
||||
FloatingIconViewCompanion, DraggableView, Reorderable {
|
||||
|
||||
public static final String TAG = "BubbleTextView";
|
||||
|
||||
|
||||
@@ -316,6 +316,74 @@ public class DeviceProfile {
|
||||
// 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,
|
||||
|
||||
@@ -435,6 +435,10 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
mIsColdStartupAfterReboot = sIsNewProcess
|
||||
&& !LockedUserState.get(this).isUserUnlockedAtLauncherStartup();
|
||||
if (mIsColdStartupAfterReboot) {
|
||||
/*
|
||||
* This trace is used to calculate the time from create to the point that icons are
|
||||
* visible.
|
||||
*/
|
||||
Trace.beginAsyncSection(
|
||||
COLD_STARTUP_TRACE_METHOD_NAME, COLD_STARTUP_TRACE_COOKIE);
|
||||
}
|
||||
@@ -2384,10 +2388,6 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
.logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
|
||||
.log()
|
||||
.reset();
|
||||
if (mIsColdStartupAfterReboot) {
|
||||
Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
|
||||
COLD_STARTUP_TRACE_COOKIE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2396,6 +2396,10 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
|
||||
mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
|
||||
workspaceItemCount, isBindSync);
|
||||
if (mIsColdStartupAfterReboot) {
|
||||
Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
|
||||
COLD_STARTUP_TRACE_COOKIE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,8 @@ enum class TestEvent(val event: String) {
|
||||
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. */
|
||||
|
||||
@@ -83,7 +83,7 @@ import com.android.launcher3.util.Executors;
|
||||
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 @@ import java.util.function.Predicate;
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.android.launcher3.BubbleTextView;
|
||||
/**
|
||||
* Views that contain {@link BubbleTextView} should implement this interface.
|
||||
*/
|
||||
public interface BubbleTextHolder extends IconLabelDotView {
|
||||
public interface BubbleTextHolder extends FloatingIconViewCompanion {
|
||||
BubbleTextView getBubbleText();
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,7 +22,7 @@ import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
|
||||
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 @@ public class FloatingIconView extends FrameLayout implements
|
||||
// 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 @@ public class FloatingIconView extends FrameLayout implements
|
||||
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 @@ public class FloatingIconView extends FrameLayout implements
|
||||
|
||||
private void updateViewsVisibility(boolean isVisible) {
|
||||
if (mOriginalIcon != null) {
|
||||
setIconAndDotVisible(mOriginalIcon, isVisible);
|
||||
setPropertiesVisible(mOriginalIcon, isVisible);
|
||||
}
|
||||
if (mMatchVisibilityView != null) {
|
||||
setIconAndDotVisible(mMatchVisibilityView, isVisible);
|
||||
setPropertiesVisible(mMatchVisibilityView, isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-6
@@ -18,19 +18,24 @@ package com.android.launcher3.views;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* A view that has an icon, label, and notification dot.
|
||||
* 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 IconLabelDotView {
|
||||
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 setIconAndDotVisible(View view, boolean visible) {
|
||||
if (view instanceof IconLabelDotView) {
|
||||
((IconLabelDotView) view).setIconVisible(visible);
|
||||
((IconLabelDotView) view).setForceHideDot(!visible);
|
||||
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);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ package com.android.launcher3.views;
|
||||
|
||||
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 @@ public class FloatingSurfaceView extends AbstractFloatingView implements
|
||||
|
||||
private void setCurrentIconVisible(boolean isVisible) {
|
||||
if (mIcon != null) {
|
||||
setIconAndDotVisible(mIcon, isVisible);
|
||||
setPropertiesVisible(mIcon, isVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -127,9 +127,9 @@ android_test {
|
||||
"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_robolectric_test {
|
||||
"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",
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package com.android.launcher3.ui.widget;
|
||||
|
||||
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 android.platform.test.annotations.PlatinumTest;
|
||||
@@ -33,7 +30,6 @@ import com.android.launcher3.ui.AbstractLauncherUiTest;
|
||||
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
|
||||
import com.android.launcher3.ui.TestViewHelpers;
|
||||
import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
|
||||
import org.junit.Assume;
|
||||
@@ -102,7 +98,6 @@ public class TaplAddWidgetTest extends AbstractLauncherUiTest<Launcher> {
|
||||
/**
|
||||
* Test dragging a widget to the workspace and resize it.
|
||||
*/
|
||||
@Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/316910614
|
||||
@PlatinumTest(focusArea = "launcher")
|
||||
@Test
|
||||
public void testResizeWidget() throws Throwable {
|
||||
|
||||
Reference in New Issue
Block a user