Merge "Redesign the tutorial for the go home gesture" into tm-qpr-dev am: 334094da9e

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/21150239

Change-Id: Ic9945132bfd6c048136dea36abbfcb846750d954
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Saumya Prakash
2023-02-02 22:12:23 +00:00
committed by Automerger Merge Worker
15 changed files with 604 additions and 14 deletions

View File

@@ -0,0 +1,23 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="@android:color/black"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41L9,16.17z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="148dp"
android:height="148dp"
android:viewportHeight="148"
android:viewportWidth="148">
<group>
<clip-path android:pathData="M74 0C114.869 0 148 33.1309 148 74C148 114.869 114.869 148 74 148C33.1309 148 0 114.869 0 74C0 33.1309 33.1309 0 74 0Z" />
<path
android:fillColor="#E0E994"
android:pathData="M0 0V148H148V0" />
</group>
</vector>

View File

@@ -0,0 +1,17 @@
<?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="oval">
<solid android:color="@color/gesture_home_tutorial_background" />
</shape>

View File

@@ -0,0 +1,244 @@
<!--
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.quickstep.interaction.RootSandboxLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<RelativeLayout
android:id="@+id/gesture_tutorial_fake_launcher_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/gesture_tutorial_fake_hotseat_view"
android:layout_width="@dimen/gesture_tutorial_hotseat_width"
android:layout_height="@dimen/gesture_tutorial_hotseat_height" />
</RelativeLayout>
<com.android.launcher3.views.ClipIconView
android:id="@+id/gesture_tutorial_fake_icon_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:visibility="invisible" />
<com.android.quickstep.interaction.AnimatedTaskView
android:id="@+id/gesture_tutorial_fake_previous_task_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleX="0.98"
android:scaleY="0.98"
android:visibility="invisible">
<View
android:id="@+id/full_task_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
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: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" />
<androidx.cardview.widget.CardView
android:id="@+id/bottom_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
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"
app:layout_constraintTop_toBottomOf="@id/top_task_view" />
</com.android.quickstep.interaction.AnimatedTaskView>
<FrameLayout
android:id="@+id/gesture_tutorial_fake_task_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/gesture_tutorial_ripple_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
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"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" />
<ImageView
android:id="@+id/gesture_tutorial_edge_gesture_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:scaleType="fitXY"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/full_gesture_demonstration"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/gesture_demonstration_animations"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:scaleType="centerCrop"
app:lottie_loop="true" />
</RelativeLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/gesture_tutorial_fragment_feedback_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="@android:color/transparent"
android:paddingEnd="24dp"
android:paddingStart="24dp"
android:paddingTop="24dp">
<TextView
android:id="@+id/gesture_tutorial_fragment_feedback_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="104dp"
android:accessibilityHeading="true"
android:gravity="top"
android:lineSpacingExtra="-1sp"
android:textAppearance="@style/TextAppearance.GestureTutorial.MainTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/gesture_tutorial_fragment_feedback_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="1dp"
android:layout_marginTop="24dp"
android:lineSpacingExtra="4sp"
android:textAppearance="@style/TextAppearance.GestureTutorial.MainSubtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_title" />
<com.android.quickstep.interaction.TutorialStepIndicator
android:id="@+id/gesture_tutorial_fragment_feedback_tutorial_step"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/gesture_tutorial_fragment_action_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/gesture_tutorial_fragment_close_button"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:paddingBottom="16dp"
android:paddingTop="16dp"
android:text="@string/gesture_tutorial_action_button_label_skip"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle" />
<ImageView
android:id="@+id/gesture_tutorial_checkbox_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:layout_marginTop="100dp"
android:background="@drawable/gesture_tutorial_complete_checkmark_bg"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/gesture_tutorial_fragment_action_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle" />
<ImageView
android:id="@+id/gesture_tutorial_checkbox"
android:layout_width="124dp"
android:layout_height="124dp"
android:background="@drawable/gesture_tutorial_complete_checkmark"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/gesture_tutorial_checkbox_bg"
app:layout_constraintEnd_toEndOf="@id/gesture_tutorial_checkbox_bg"
app:layout_constraintStart_toStartOf="@id/gesture_tutorial_checkbox_bg"
app:layout_constraintTop_toTopOf="@id/gesture_tutorial_checkbox_bg" />
<Button
android:id="@+id/gesture_tutorial_fragment_action_button"
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:background="@drawable/gesture_tutorial_action_button_background"
android:stateListAnimator="@null"
android:text="@string/gesture_tutorial_action_button_label"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_checkbox_bg" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/gesture_tutorial_finger_dot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/gesture_tutorial_finger_dot"
android:visibility="gone" />
</com.android.quickstep.interaction.RootSandboxLayout>

View File

@@ -0,0 +1,92 @@
<?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.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="70dp"
android:paddingStart="26dp"
android:paddingEnd="26dp"
android:background="@color/gesture_home_tutorial_swipe_up_rect">
<androidx.cardview.widget.CardView
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
app: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
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
app: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
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
app: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
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
app: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
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
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" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,19 @@
<?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.
-->
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swipe_up_gesture_tutorial_shape"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gesture_home_tutorial_background" />

File diff suppressed because one or more lines are too long

View File

@@ -42,6 +42,13 @@
<color name="gesture_tutorial_fake_previous_task_view_color">#3C4043</color> <!-- Gray -->
<color name="gesture_tutorial_taskbar_color">#E8EAED</color>
<!-- Redesigned gesture navigation tutorial -->
<color name="gesture_home_tutorial_background">#FFB399</color>
<color name="gesture_home_tutorial_swipe_up_rect">#3857C7</color>
<color name="gesture_back_tutorial_background">#F3A5B9</color>
<color name="gesture_back_tutorial_swipe_rect">#217500</color>
<color name="gesture_overview_tutorial_swipe_rect">#7E44AD</color>
<!-- Mock hotseat -->
<color name="mock_app_icon">#BDC1C6</color>
<color name="mock_search_bar">#3C4043</color>

View File

@@ -133,6 +133,10 @@
<string name="home_gesture_intro_subtitle">Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.</string>
<!-- Introduction subtitle for the Home gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
<string name="home_gesture_spoken_intro_subtitle">Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen.</string>
<!-- Title of the gesture tutorial section educating users on how to go to the home screen. [CHAR LIMIT=100] -->
<string name="home_gesture_tutorial_title">Go home</string>
<!-- Subtitle of the gesture tutorial section educating users on how to go to the home screen [CHAR LIMIT=100] -->
<string name="home_gesture_tutorial_subtitle">To go to your home screen at any time, swipe up from the bottom of your screen</string>
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
<string name="overview_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>

View File

@@ -124,6 +124,31 @@
<item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.GestureTutorial.MainTitle"
parent="TextAppearance.GestureTutorial">
<item name="android:textSize">36sp</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:fontFamily">google-sans</item>
</style>
<style name="TextAppearance.GestureTutorial.MainSubtitle"
parent="TextAppearance.GestureTutorial.Subtitle">
<item name="android:textSize">16sp</item>
<item name="android:letterSpacing">0.02</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:fontFamily">google-sans-text</item>
</style>
<style name="TextAppearance.GestureTutorial.SuccessTitle"
parent="TextAppearance.GestureTutorial.MainTitle">
<item name="android:textColor">@android:color/white</item>
</style>
<style name="TextAppearance.GestureTutorial.SuccessSubtitle"
parent="TextAppearance.GestureTutorial.MainSubtitle">
<item name="android:textColor">@android:color/white</item>
</style>
<style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>

View File

@@ -59,6 +59,12 @@ final class BackGestureTutorialController extends TutorialController {
return getMockAppTaskCurrentPageLayoutResId();
}
@Override
protected int getGestureLottieAnimationId() {
// TODO(b/253521922): Change to correct LottieAnimationView
return R.raw.home_gesture_tutorial_animation;
}
@LayoutRes
int getMockAppTaskCurrentPageLayoutResId() {
return mTutorialFragment.isLargeScreen()
@@ -73,6 +79,11 @@ final class BackGestureTutorialController extends TutorialController {
: R.layout.gesture_tutorial_mock_conversation_list;
}
@Override
protected int getSwipeActionColorResId() {
return R.color.gesture_back_tutorial_swipe_rect;
}
@Override
public void onBackGestureAttempted(BackGestureResult result) {
if (isGestureCompleted()) {

View File

@@ -15,6 +15,8 @@
*/
package com.android.quickstep.interaction;
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.annotation.TargetApi;
import android.graphics.PointF;
import android.os.Build;
@@ -33,12 +35,16 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
@Override
public int getIntroductionTitle() {
return R.string.home_gesture_intro_title;
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.string.home_gesture_tutorial_title
: R.string.home_gesture_intro_title;
}
@Override
public int getIntroductionSubtitle() {
return R.string.home_gesture_intro_subtitle;
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.string.home_gesture_tutorial_subtitle
: R.string.home_gesture_intro_subtitle;
}
@Override
@@ -57,7 +63,19 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
: ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.layout.swipe_up_gesture_tutorial_shape
: R.layout.gesture_tutorial_mock_webpage;
}
@Override
protected int getGestureLottieAnimationId() {
return R.raw.home_gesture_tutorial_animation;
}
@Override
protected int getSwipeActionColorResId() {
return R.color.gesture_home_tutorial_swipe_up_rect;
}
@Override

View File

@@ -70,6 +70,17 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
: R.layout.gesture_tutorial_mock_conversation_list;
}
@Override
protected int getGestureLottieAnimationId() {
// TODO(b/253521660): Change to correct LottieAnimationView
return R.raw.home_gesture_tutorial_animation;
}
@Override
protected int getSwipeActionColorResId() {
return R.color.gesture_overview_tutorial_swipe_rect;
}
@Override
public void onBackGestureAttempted(BackGestureResult result) {
if (isGestureCompleted()) {

View File

@@ -19,12 +19,15 @@ import static android.view.View.GONE;
import static android.view.View.NO_ID;
import static android.view.View.inflate;
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.ColorRes;
import android.annotation.RawRes;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -57,6 +60,8 @@ import com.android.launcher3.views.ClipIconView;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
import com.airbnb.lottie.LottieAnimationView;
import java.util.ArrayList;
abstract class TutorialController implements BackGestureAttemptCallback,
@@ -85,6 +90,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
final Button mDoneButton;
final ViewGroup mFeedbackView;
final TextView mFeedbackTitleView;
final TextView mFeedbackSubtitleView;
final ImageView mEdgeGestureVideoView;
final RelativeLayout mFakeLauncherView;
final FrameLayout mFakeHotseatView;
@@ -100,6 +106,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
private final AlertDialog mSkipTutorialDialog;
private boolean mGestureCompleted = false;
private LottieAnimationView mAnimatedGestureDemonstration;
private RelativeLayout mFullGestureDemonstration;
// These runnables should be used when posting callbacks to their views and cleared from their
// views before posting new callbacks.
@@ -120,6 +128,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
mFeedbackTitleView = mFeedbackView.findViewById(
R.id.gesture_tutorial_fragment_feedback_title);
mFeedbackSubtitleView = mFeedbackView.findViewById(
R.id.gesture_tutorial_fragment_feedback_subtitle);
mEdgeGestureVideoView = rootView.findViewById(R.id.gesture_tutorial_edge_gesture_video);
mFakeLauncherView = rootView.findViewById(R.id.gesture_tutorial_fake_launcher_view);
mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
@@ -136,6 +146,17 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mFingerDotView = rootView.findViewById(R.id.gesture_tutorial_finger_dot);
mSkipTutorialDialog = createSkipTutorialDialog();
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mAnimatedGestureDemonstration = mTutorialFragment.getRootView().findViewById(
R.id.gesture_demonstration_animations);
mFullGestureDemonstration = mTutorialFragment.getRootView().findViewById(
R.id.full_gesture_demonstration);
mFeedbackTitleView.setText(getIntroductionTitle());
mFeedbackSubtitleView.setText(getIntroductionSubtitle());
mSkipButton.setVisibility(GONE);
}
mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_FOCUSED);
mShowFeedbackRunnable = () -> {
@@ -189,12 +210,19 @@ abstract class TutorialController implements BackGestureAttemptCallback,
? (mTutorialFragment.isFoldable()
? R.layout.gesture_tutorial_foldable_mock_hotseat
: R.layout.gesture_tutorial_tablet_mock_hotseat)
: R.layout.gesture_tutorial_mock_hotseat;
: (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.layout.redesigned_gesture_tutorial_mock_hotseat
: R.layout.gesture_tutorial_mock_hotseat);
}
@LayoutRes
protected int getMockAppTaskLayoutResId() {
return View.NO_ID;
return NO_ID;
}
@RawRes
protected int getGestureLottieAnimationId() {
return NO_ID;
}
@ColorRes
@@ -202,9 +230,16 @@ abstract class TutorialController implements BackGestureAttemptCallback,
return R.color.gesture_tutorial_fake_previous_task_view_color;
}
@ColorRes
protected int getSwipeActionColorResId() {
return NO_ID;
}
@DrawableRes
public int getMockAppIconResId() {
return R.drawable.default_sandbox_app_icon;
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.drawable.redesigned_default_sandbox_app_icon
: R.drawable.default_sandbox_app_icon;
}
@DrawableRes
@@ -301,9 +336,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
}
mFeedbackTitleView.setText(titleResId);
TextView subtitle =
mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
subtitle.setText(spokenSubtitleResId == NO_ID
mFeedbackSubtitleView.setText(spokenSubtitleResId == NO_ID
? mContext.getText(subtitleResId)
: Utilities.wrapForTts(
mContext.getText(subtitleResId), mContext.getString(spokenSubtitleResId)));
@@ -316,6 +349,10 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mFakeTaskView.removeCallbacks(mFakeTaskViewCallback);
mFakeTaskViewCallback = null;
}
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
showSuccessPage();
}
}
mGestureCompleted = isGestureSuccessful;
@@ -336,6 +373,16 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mFeedbackView.post(mFeedbackViewCallback);
}
private void showSuccessPage() {
mFeedbackView.findViewById(
R.id.gesture_tutorial_checkbox_bg).setVisibility(View.VISIBLE);
mFeedbackView.findViewById(
R.id.gesture_tutorial_checkbox).setVisibility(View.VISIBLE);
mFeedbackTitleView.setTextAppearance(R.style.TextAppearance_GestureTutorial_SuccessTitle);
mFeedbackSubtitleView.setTextAppearance(
R.style.TextAppearance_GestureTutorial_SuccessSubtitle);
}
public boolean isGestureCompleted() {
return mGestureCompleted;
}
@@ -371,6 +418,14 @@ abstract class TutorialController implements BackGestureAttemptCallback,
@NonNull Runnable onStartRunnable,
boolean useGestureAnimationDelay) {
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mFeedbackView.setVisibility(View.VISIBLE);
mAnimatedGestureDemonstration.setVisibility(View.VISIBLE);
mFullGestureDemonstration.setVisibility(View.VISIBLE);
mAnimatedGestureDemonstration.playAnimation();
return;
}
if (gestureAnimation.isRunning()) {
gestureAnimation.cancel();
}
@@ -436,19 +491,29 @@ abstract class TutorialController implements BackGestureAttemptCallback,
@CallSuper
void transitToController() {
hideFeedback();
hideActionButton();
updateCloseButton();
updateSubtext();
updateDrawables();
updateLayout();
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
startGestureAnimation();
} else {
hideFeedback();
hideActionButton();
}
mGestureCompleted = false;
if (mFakeHotseatView != null) {
mFakeHotseatView.setVisibility(View.INVISIBLE);
}
}
private void startGestureAnimation() {
mAnimatedGestureDemonstration.setAnimation(getGestureLottieAnimationId());
mAnimatedGestureDemonstration.playAnimation();
}
void updateCloseButton() {
mSkipButton.setTextAppearance(Utilities.isDarkTheme(mContext)
? R.style.TextAppearance_GestureTutorial_Feedback_Subtext
@@ -512,8 +577,10 @@ abstract class TutorialController implements BackGestureAttemptCallback,
}
private void updateSubtext() {
mTutorialStepView.setTutorialProgress(
mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mTutorialStepView.setTutorialProgress(
mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
}
}
private void updateDrawables() {
@@ -532,6 +599,11 @@ abstract class TutorialController implements BackGestureAttemptCallback,
getMockPreviousAppTaskThumbnailColorResId()));
mFakeIconView.setBackground(AppCompatResources.getDrawable(
mContext, getMockAppIconResId()));
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mFakeLauncherView.setBackgroundColor(
mContext.getColor(getSwipeActionColorResId()));
}
}
}
@@ -686,6 +758,12 @@ abstract class TutorialController implements BackGestureAttemptCallback,
return ValueAnimator.ofFloat(0f, 1f).setDuration(GESTURE_ANIMATION_PAUSE_DURATION_MILLIS);
}
void pauseAndHideLottieAnimation() {
mAnimatedGestureDemonstration.pauseAnimation();
mAnimatedGestureDemonstration.setVisibility(View.INVISIBLE);
mFullGestureDemonstration.setVisibility(View.INVISIBLE);
}
/** Denotes the type of the tutorial. */
enum TutorialType {
BACK_NAVIGATION,

View File

@@ -17,6 +17,8 @@ package com.android.quickstep.interaction;
import static android.view.View.NO_ID;
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
@@ -184,7 +186,12 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
super.onCreateView(inflater, container, savedInstanceState);
mRootView = (RootSandboxLayout) inflater.inflate(
R.layout.gesture_tutorial_fragment, container, false);
ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
? R.layout.redesigned_gesture_tutorial_fragment
: R.layout.gesture_tutorial_fragment,
container,
false);
mRootView.setOnApplyWindowInsetsListener((view, insets) -> {
Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());
mEdgeBackGestureHandler.setInsets(systemInsets.left, systemInsets.right);
@@ -333,6 +340,11 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
if (mTutorialController != null && !isGestureComplete()) {
mTutorialController.hideFeedback();
}
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
mTutorialController.pauseAndHideLottieAnimation();
}
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
| mNavBarGestureHandler.onTouch(view, motionEvent);