Merge "Create an XML parser for WorkspaceSpecs" into tm-qpr-dev
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 951be4e..0c7b48fe 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -40,6 +40,7 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.VIBRATE"/>
<!-- for rotating surface by arbitrary degree -->
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
diff --git a/quickstep/res/drawable/hotseat_icon.xml b/quickstep/res/drawable/hotseat_icon.xml
new file mode 100644
index 0000000..b849fe9
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/mock_app_icon" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/hotseat_icon_home.xml b/quickstep/res/drawable/hotseat_icon_home.xml
new file mode 100644
index 0000000..d59dd4a
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_icon_home.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/gesture_home_tutorial_background" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/hotseat_search_bar.xml b/quickstep/res/drawable/hotseat_search_bar.xml
new file mode 100644
index 0000000..ea332e9
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_search_bar.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/mock_search_bar" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_search_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/top_task_view.xml b/quickstep/res/drawable/top_task_view.xml
new file mode 100644
index 0000000..d2176c3
--- /dev/null
+++ b/quickstep/res/drawable/top_task_view.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/gesture_tutorial_fake_previous_task_view_color" />
+ <corners android:radius="@dimen/gesture_tutorial_small_task_view_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
index 1e2e014..c7e176a 100644
--- a/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
@@ -24,54 +24,50 @@
android:paddingStart="56dp"
android:paddingEnd="56dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintVertical_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_2"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_3"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_2"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_4"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_3"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
index f04fbb6..28d32a4 100644
--- a/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
@@ -22,84 +22,77 @@
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_search_bar"
android:layout_width="200dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:layout_constraintHorizontal_chainStyle="spread_inside"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_1"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_search_bar"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 8eeef67..3bd0df0 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -57,33 +57,34 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+
+ <View
android:id="@+id/top_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:visibility="invisible"
android:layout_marginBottom="@dimen/gesture_tutorial_multi_row_task_view_spacing"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
+ android:visibility="invisible"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
app:layout_constraintVertical_chainStyle="spread"
- app:layout_constraintTop_toTopOf="@id/full_task_view"
app:layout_constraintBottom_toTopOf="@id/bottom_task_view"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
+ app:layout_constraintTop_toTopOf="@id/full_task_view" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/bottom_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:layout_constraintTop_toBottomOf="@id/top_task_view"
app:layout_constraintBottom_toBottomOf="@id/full_task_view"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
+ app:layout_constraintTop_toBottomOf="@id/top_task_view" />
</com.android.quickstep.interaction.AnimatedTaskView>
diff --git a/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
index 8513dcf..8ee0339 100644
--- a/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
@@ -8,67 +8,62 @@
android:paddingStart="26dp"
android:paddingEnd="26dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
index 363f14e..63c51e8 100644
--- a/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
@@ -22,84 +22,78 @@
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_search_bar"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index 13b7238..13482ac 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -57,29 +57,29 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+
+ <View
android:id="@+id/top_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="@dimen/gesture_tutorial_multi_row_task_view_spacing"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintBottom_toTopOf="@id/bottom_task_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@id/full_task_view"
- app:layout_constraintVertical_chainStyle="spread" />
+ app:layout_constraintTop_toTopOf="@id/full_task_view" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/bottom_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintBottom_toBottomOf="@id/full_task_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -99,13 +99,13 @@
android:background="@drawable/gesture_tutorial_ripple" />
<include
- layout="@layout/gesture_tutorial_tablet_mock_taskbar"
android:id="@+id/gesture_tutorial_fake_taskbar_view"
- android:layout_width="match_parent"
- android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height"
+ layout="@layout/gesture_tutorial_tablet_mock_taskbar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentEnd="true" />
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/gesture_tutorial_taskbar_margin_bottom" />
<ImageView
android:id="@+id/gesture_tutorial_edge_gesture_video"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
index 6d9ffae..b1c8b31 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -21,70 +21,64 @@
android:layout_height="wrap_content"
android:paddingBottom="70dp"
android:paddingStart="26dp"
- android:paddingEnd="26dp"
- android:background="@color/gesture_home_tutorial_swipe_up_rect">
+ android:paddingEnd="26dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1" />
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index b5afda3..df95dc1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -39,6 +39,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -62,6 +63,7 @@
private static final long TRANSLATION_ANIM_MIN_DURATION_MS = 80;
private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
+ private final VibratorWrapper mVibratorWrapper;
private final RecentsView mRecentsView;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
@@ -82,6 +84,7 @@
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
+ mVibratorWrapper = VibratorWrapper.INSTANCE.get(l.getApplicationContext());
}
@Override
@@ -188,6 +191,11 @@
// need to manually set the duration to a reasonable value.
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
}
+ if (FeatureFlags.ENABLE_HAPTICS_ALL_APPS.get() &&
+ ((mFromState == NORMAL && mToState == ALL_APPS)
+ || (mFromState == ALL_APPS && mToState == NORMAL)) && isFling) {
+ mVibratorWrapper.vibrateForDragBump();
+ }
}
private void onMotionPauseDetected() {
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 53ad138..3ccd683 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -30,7 +30,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -46,8 +45,8 @@
public class AnimatedTaskView extends ConstraintLayout {
private View mFullTaskView;
- private CardView mTopTaskView;
- private CardView mBottomTaskView;
+ private View mTopTaskView;
+ private View mBottomTaskView;
private ViewOutlineProvider mTaskViewOutlineProvider = null;
private final Rect mTaskViewAnimatedRect = new Rect();
@@ -185,8 +184,6 @@
void setFakeTaskViewFillColor(@ColorInt int colorResId) {
mFullTaskView.setBackgroundColor(colorResId);
- mTopTaskView.setCardBackgroundColor(colorResId);
- mBottomTaskView.setCardBackgroundColor(colorResId);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index c89d4b6..bce639b 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -61,10 +61,10 @@
@Override
protected int getMockAppTaskLayoutResId() {
- return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_webpage
- : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.swipe_up_gesture_tutorial_shape
+ return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+ ? R.layout.swipe_up_gesture_tutorial_shape
+ : mTutorialFragment.isLargeScreen()
+ ? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index ccdb266..6fcb840 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -154,7 +154,6 @@
mFeedbackTitleView.setText(getIntroductionTitle());
mFeedbackSubtitleView.setText(getIntroductionSubtitle());
- mSkipButton.setVisibility(GONE);
}
mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9f34775..bc5fa19 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -191,7 +191,7 @@
mLauncher.goHome().switchToOverview().getCurrentTask()
.tapMenu()
.tapSplitMenuItem()
- .getTestActivityTask(2)
+ .getCurrentTask()
.open();
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fa54dcf..cfb8ca4 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -501,7 +501,7 @@
}
private boolean isTwoPanelEnabled() {
- return mLauncher.mDeviceProfile.isTwoPanels;
+ return !FOLDABLE_SINGLE_PAGE.get() && mLauncher.mDeviceProfile.isTwoPanels;
}
@Override
@@ -663,8 +663,9 @@
// Inflate the cell layout, but do not add it automatically so that we can get the newly
// created CellLayout.
+ DeviceProfile dp = mLauncher.getDeviceProfile();
CellLayout newScreen;
- if (FOLDABLE_SINGLE_PAGE.get() && isTwoPanelEnabled()) {
+ if (FOLDABLE_SINGLE_PAGE.get() && dp.isTwoPanels) {
newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen_foldable, this, false /* attachToRoot */);
} else {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4a1c334..b618724 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -32,6 +32,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.util.FloatProperty;
import android.view.HapticFeedbackConstants;
import android.view.View;
@@ -47,17 +48,21 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.ScrimView;
/**
@@ -78,6 +83,8 @@
private static final int REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS = 200;
private static final float NAV_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.1f;
+ private static final float SWIPE_DRAG_COMMIT_THRESHOLD =
+ 1 - AllAppsSwipeController.ALL_APPS_STATE_TRANSITION_MANUAL;
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -181,6 +188,7 @@
private boolean mIsTablet;
private boolean mHasScaleEffect;
+ private final VibratorWrapper mVibratorWrapper;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -193,6 +201,7 @@
setShiftRange(dp.allAppsShiftRange);
mLauncher.addOnDeviceProfileChangeListener(this);
+ mVibratorWrapper = VibratorWrapper.INSTANCE.get(mLauncher.getApplicationContext());
}
public float getShiftRange() {
@@ -311,6 +320,11 @@
/**
* Creates an animation which updates the vertical transition progress and updates all the
* dependent UI using various animation events
+ *
+ * This method also dictates where along the progress the haptics should be played. As the user
+ * scrolls up from workspace or down from AllApps, a drag haptic is being played until the
+ * commit point where it plays a commit haptic. Where we play the haptics differs when going
+ * from workspace -> allApps and vice versa.
*/
@Override
public void setStateWithAnimation(LauncherState toState,
@@ -339,6 +353,20 @@
});
}
+ if(FeatureFlags.ENABLE_HAPTICS_ALL_APPS.get() && config.userControlled
+ && Utilities.ATLEAST_S) {
+ if (toState == ALL_APPS) {
+ builder.addOnFrameListener(
+ new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
+ SWIPE_DRAG_COMMIT_THRESHOLD, 1));
+ } else {
+ builder.addOnFrameListener(
+ new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
+ 0, SWIPE_DRAG_COMMIT_THRESHOLD));
+ }
+ builder.addEndListener(mVibratorWrapper::cancelVibrate);
+ }
+
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -356,7 +384,7 @@
setAlphas(toState, config, builder);
- if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
+ if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL) && !(Utilities.ATLEAST_S)) {
mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
}
@@ -494,4 +522,45 @@
}
}
}
+
+ /**
+ * This VibrationAnimatorUpdateListener class takes in four parameters, a controller, start
+ * threshold, end threshold, and a Vibrator wrapper. We use the progress given by the controller
+ * as it gives an accurate progress that dictates where the vibrator should vibrate.
+ * Note: once the user begins a gesture and does the commit haptic, there should not be anymore
+ * haptics played for that gesture.
+ */
+ private static class VibrationAnimatorUpdateListener implements
+ ValueAnimator.AnimatorUpdateListener {
+ private final VibratorWrapper mVibratorWrapper;
+ private final AllAppsTransitionController mController;
+ private final float mStartThreshold;
+ private final float mEndThreshold;
+ private boolean mHasCommitted;
+
+ VibrationAnimatorUpdateListener(AllAppsTransitionController controller,
+ VibratorWrapper vibratorWrapper, float startThreshold,
+ float endThreshold) {
+ mController = controller;
+ mVibratorWrapper = vibratorWrapper;
+ mStartThreshold = startThreshold;
+ mEndThreshold = endThreshold;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (mHasCommitted) {
+ return;
+ }
+ float currentProgress =
+ AllAppsTransitionController.ALL_APPS_PROGRESS.get(mController);
+ if (currentProgress > mStartThreshold && currentProgress < mEndThreshold) {
+ mVibratorWrapper.vibrateForDragTexture();
+ } else if (!(currentProgress == 0 || currentProgress == 1)) {
+ // This check guards against committing at the location of the start of the gesture
+ mVibratorWrapper.vibrateForDragCommit();
+ mHasCommitted = true;
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index ff0a867..aca9393 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -371,6 +371,8 @@
"ENABLE_LAUNCH_FROM_STAGED_APP", true,
"Enable the ability to tap a staged app during split select to launch it in full screen"
);
+ public static final BooleanFlag ENABLE_HAPTICS_ALL_APPS = getDebugFlag(
+ "ENABLE_HAPTICS_ALL_APPS", false, "Enables haptics opening/closing All apps");
public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(
"ENABLE_FORCED_MONO_ICON", false,
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index bfd0e1b..a53751f 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -129,10 +129,7 @@
Interpolators.clampToProgress(
Interpolators.mapToProgress(EMPHASIZED_DECELERATE, 0.4f, 1f),
ALL_APPS_STATE_TRANSITION_ATOMIC, 1f);
- public static final Interpolator ALL_APPS_VERTICAL_PROGRESS_MANUAL =
- Interpolators.clampToProgress(
- Interpolators.mapToProgress(LINEAR, ALL_APPS_STATE_TRANSITION_MANUAL, 1f),
- ALL_APPS_STATE_TRANSITION_MANUAL, 1f);
+ public static final Interpolator ALL_APPS_VERTICAL_PROGRESS_MANUAL = LINEAR;
// --------
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 932bcfc..ceba0db 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -17,7 +17,6 @@
import static android.os.VibrationEffect.createPredefined;
import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
-
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -28,12 +27,17 @@
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.os.Build;
+import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.Utilities;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.anim.PendingAnimation;
+
+import java.util.function.Consumer;
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
@@ -52,6 +56,21 @@
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
+ private static final float DRAG_TEXTURE_SCALE = 0.03f;
+ private static final float DRAG_COMMIT_SCALE = 0.5f;
+ private static final float DRAG_BUMP_SCALE = 0.4f;
+ private static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
+
+ @Nullable
+ private final VibrationEffect mDragEffect;
+ @Nullable
+ private final VibrationEffect mCommitEffect;
+ @Nullable
+ private final VibrationEffect mBumpEffect;
+
+ private long mLastDragTime;
+ private final int mThresholdUntilNextDragCallMillis;
+
/**
* Haptic when entering overview.
*/
@@ -62,7 +81,7 @@
private boolean mIsHapticFeedbackEnabled;
- public VibratorWrapper(Context context) {
+ private VibratorWrapper(Context context) {
mVibrator = context.getSystemService(Vibrator.class);
mHasVibrator = mVibrator.hasVibrator();
if (mHasVibrator) {
@@ -75,12 +94,88 @@
}
};
resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
- false /* notifyForDescendents */, observer);
+ false /* notifyForDescendants */, observer);
} else {
mIsHapticFeedbackEnabled = false;
}
+
+ if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK)) {
+
+ // Drag texture, Commit, and Bump should only be used for premium phones.
+ // Before using these haptics make sure check if the device can use it
+ VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
+ for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
+ dragEffect.addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
+ }
+ mDragEffect = dragEffect.compose();
+ mCommitEffect = VibrationEffect.startComposition().addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose();
+ mBumpEffect = VibrationEffect.startComposition().addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK, DRAG_BUMP_SCALE).compose();
+ int primitiveDuration = mVibrator.getPrimitiveDurations(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK)[0];
+
+ mThresholdUntilNextDragCallMillis =
+ DRAG_TEXTURE_EFFECT_SIZE * primitiveDuration + 100;
+ } else {
+ mDragEffect = null;
+ mCommitEffect = null;
+ mBumpEffect = null;
+ mThresholdUntilNextDragCallMillis = 0;
+ }
}
+ /**
+ * This is called when the user swipes to/from all apps. This is meant to be used in between
+ * long animation progresses so that it gives a dragging texture effect. For a better
+ * experience, this should be used in combination with vibrateForDragCommit().
+ */
+ public void vibrateForDragTexture() {
+ if (mDragEffect == null) {
+ return;
+ }
+ long currentTime = SystemClock.elapsedRealtime();
+ long elapsedTimeSinceDrag = currentTime - mLastDragTime;
+ if (elapsedTimeSinceDrag >= mThresholdUntilNextDragCallMillis) {
+ vibrate(mDragEffect);
+ mLastDragTime = currentTime;
+ }
+ }
+
+ /**
+ * This is used when user reaches the commit threshold when swiping to/from from all apps.
+ */
+ public void vibrateForDragCommit() {
+ if (mCommitEffect != null) {
+ vibrate(mCommitEffect);
+ }
+ // resetting dragTexture timestamp to be able to play dragTexture again
+ mLastDragTime = 0;
+ }
+
+ /**
+ * The bump haptic is used to be called at the end of a swipe and only if it the gesture is a
+ * FLING going to/from all apps. Client can just call this method elsewhere just for the
+ * effect.
+ */
+ public void vibrateForDragBump() {
+ if (mBumpEffect != null) {
+ vibrate(mBumpEffect);
+ }
+ }
+
+ /**
+ * This should be used to cancel a haptic in case where the haptic shouldn't be vibrating. For
+ * example, when no animation is happening but a vibrator happens to be vibrating still. Need
+ * boolean parameter for {@link PendingAnimation#addEndListener(Consumer)}.
+ */
+ public void cancelVibrate(boolean unused) {
+ UI_HELPER_EXECUTOR.execute(mVibrator::cancel);
+ // reset dragTexture timestamp to be able to play dragTexture again whenever cancelled
+ mLastDragTime = 0;
+ }
private boolean isHapticFeedbackEnabled(ContentResolver resolver) {
return Settings.System.getInt(resolver, HAPTIC_FEEDBACK_ENABLED, 0) == 1;
}