Merge "Update gesture nav edu motion and colors" into udc-dev am: b4e91b14bd am: 2256dfcec1

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

Change-Id: Ibd7edffcc8e3492497ca06008f4ce5e8bc94c183
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index b13e8dc..225b4cd 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -157,6 +157,7 @@
         android:layout_marginVertical="16dp"
         android:text="@string/gesture_tutorial_action_button_label"
         android:background="@drawable/gesture_tutorial_action_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorPrimary"
         android:stateListAnimator="@null"
 
         app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 3bd0df0..64ad1f7 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -175,6 +175,7 @@
             android:paddingEnd="26dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
+            android:backgroundTint="?android:attr/colorAccent"
             android:stateListAnimator="@null"
             android:visibility="invisible"
 
diff --git a/quickstep/res/layout/gesture_tutorial_mock_task_view.xml b/quickstep/res/layout/gesture_tutorial_mock_task_view.xml
deleted file mode 100644
index 047fdb1..0000000
--- a/quickstep/res/layout/gesture_tutorial_mock_task_view.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/GestureTutorialActivity"
-    android:id="@+id/overview_gesture_tutorial_shape"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_margin="20dp"
-    android:background="?attr/onSurfaceOverview" />
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index 7a302f4..cf78b1b 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -156,6 +156,7 @@
         android:layout_marginVertical="16dp"
         android:text="@string/gesture_tutorial_action_button_label"
         android:background="@drawable/gesture_tutorial_action_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorPrimary"
         android:stateListAnimator="@null"
 
         app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml b/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml
deleted file mode 100644
index d60e84f..0000000
--- a/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/GestureTutorialActivity"
-    android:id="@+id/swipe_up_gesture_tutorial_shape"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="?attr/surfaceHome" />
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 44b3d62..742b0fc 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -15,10 +15,6 @@
  */
 package com.android.quickstep.interaction;
 
-import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_OUT_DURATION;
-import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
 
 import android.animation.Animator;
@@ -28,30 +24,19 @@
 import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.content.Context;
-import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Display;
-import android.view.RoundedCorner;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-import android.widget.ViewAnimator;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.util.MultiValueUpdateListener;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 
 /**
  * Helper View for the gesture tutorial mock previous app task view.
@@ -61,8 +46,6 @@
  */
 public class AnimatedTaskView extends ConstraintLayout {
 
-    private static final long ANIMATE_TO_FULL_SCREEN_DURATION = 300;
-
     private View mFullTaskView;
     private View mTopTaskView;
     private View mBottomTaskView;
@@ -72,17 +55,16 @@
     private float mTaskViewAnimatedRadius;
 
     public AnimatedTaskView(@NonNull Context context) {
-        super(context);
+        this(context, null);
     }
 
-    public AnimatedTaskView(@NonNull Context context,
-            @Nullable AttributeSet attrs) {
-        super(context, attrs);
+    public AnimatedTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
     }
 
     public AnimatedTaskView(
             @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
+        this(context, attrs, defStyleAttr, 0);
     }
 
     public AnimatedTaskView(
@@ -104,97 +86,6 @@
         setToSingleRowLayout(false);
     }
 
-    void animateToFillScreen(@Nullable Runnable onAnimationEndCallback) {
-        if (mTaskViewOutlineProvider == null) {
-            // This is an illegal state.
-            return;
-        }
-        // calculate start and end corner radius
-        Outline startOutline = new Outline();
-        mTaskViewOutlineProvider.getOutline(this, startOutline);
-        Rect outlineStartRect = new Rect();
-        startOutline.getRect(outlineStartRect);
-        float outlineStartRadius = startOutline.getRadius();
-
-        final Display display = mContext.getDisplay();;
-        RoundedCorner corner = display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT);
-        float outlineEndRadius = corner.getRadius();
-
-        // create animation
-        AnimatorSet set = new AnimatorSet();
-        ArrayList<Animator> animations = new ArrayList<>();
-
-        // center view
-        animations.add(ObjectAnimator.ofFloat(this, TRANSLATION_X, 0));
-
-        // retrieve start animation matrix to scale off of
-        Matrix matrix = getAnimationMatrix();
-        if (matrix == null) {
-            // This is an illegal state.
-            return;
-        }
-
-        float[] matrixValues = new float[9];
-        matrix.getValues(matrixValues);
-        float[] newValues = matrixValues.clone();
-
-        ValueAnimator transformAnimation = ValueAnimator.ofFloat(0, 1);
-
-        MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            Matrix currentMatrix = new Matrix();
-
-            FloatProp mOutlineRadius = new FloatProp(outlineStartRadius, outlineEndRadius, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mTransX = new FloatProp(matrixValues[Matrix.MTRANS_X], 0f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mTransY = new FloatProp(matrixValues[Matrix.MTRANS_Y], 0f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mScaleX = new FloatProp(matrixValues[Matrix.MSCALE_X], 1f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mScaleY = new FloatProp(matrixValues[Matrix.MSCALE_Y], 1f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-
-            @Override
-            public void onUpdate(float percent, boolean initOnly) {
-                // scale corner radius to match display radius
-                mTaskViewAnimatedRadius = mOutlineRadius.value;
-                mFullTaskView.invalidateOutline();
-
-                // translate to center, ends at translation x:0, y:0
-                newValues[Matrix.MTRANS_X] = mTransX.value;
-                newValues[Matrix.MTRANS_Y] = mTransY.value;
-
-                // scale to full size, ends at scale 1
-                newValues[Matrix.MSCALE_X] = mScaleX.value;
-                newValues[Matrix.MSCALE_Y] = mScaleY.value;
-
-                // create and set new animation matrix
-                currentMatrix.setValues(newValues);
-                setAnimationMatrix(currentMatrix);
-            }
-        };
-
-        transformAnimation.addUpdateListener(listener);
-        animations.add(transformAnimation);
-        set.playSequentially(animations);
-        set.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                super.onAnimationStart(animation);
-                addAnimatedOutlineProvider(mFullTaskView, outlineStartRect, outlineStartRadius);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (onAnimationEndCallback != null) {
-                    onAnimationEndCallback.run();
-                }
-            }
-        });
-        set.start();
-    }
-
     AnimatorSet createAnimationToMultiRowLayout() {
         if (mTaskViewOutlineProvider == null) {
             // This is an illegal state.
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 17e57bf..54c441b 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -136,7 +136,7 @@
     }
 
     @Override
-    protected int getSwipeActionColor() {
+    protected int getFakeLauncherColor() {
         return mTutorialFragment.mRootView.mColorSurfaceContainer;
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 0012d47..891f20e 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -104,11 +104,9 @@
 
     @Override
     protected int getMockAppTaskLayoutResId() {
-        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;
+        return mTutorialFragment.isLargeScreen()
+                ? R.layout.gesture_tutorial_tablet_mock_webpage
+                : R.layout.gesture_tutorial_mock_webpage;
     }
 
     @Override
@@ -121,7 +119,12 @@
     }
 
     @Override
-    protected int getSwipeActionColor() {
+    protected int getFakeTaskViewColor() {
+        return isGestureCompleted() ? getFakeLauncherColor() : getExitingAppColor();
+    }
+
+    @Override
+    protected int getFakeLauncherColor() {
         return mTutorialFragment.mRootView.mColorSurfaceContainer;
     }
 
@@ -148,7 +151,7 @@
                     case BACK_CANCELLED_FROM_LEFT:
                     case BACK_CANCELLED_FROM_RIGHT:
                     case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
                         break;
                 }
@@ -178,18 +181,18 @@
                     }
                     case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
                     case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
                         break;
                     case OVERVIEW_GESTURE_COMPLETED:
-                        fadeOutFakeTaskView(true, true, () -> {
+                        fadeOutFakeTaskView(true, () -> {
                             showFeedback(R.string.home_gesture_feedback_overview_detected);
                             showFakeTaskbar(/* animateFromHotseat= */ false);
                         });
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
                     case HOME_OR_OVERVIEW_CANCELLED:
-                        fadeOutFakeTaskView(false, true, null);
+                        fadeOutFakeTaskView(false, null);
                         showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
                         break;
                 }
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 593e6d9..667fe4d 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -25,7 +25,9 @@
 import android.graphics.PointF;
 import android.os.Build;
 import android.os.Handler;
-import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -43,6 +45,8 @@
 @TargetApi(Build.VERSION_CODES.R)
 final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
 
+    private static final float LAUNCHER_COLOR_BLENDING_RATIO = 0.4f;
+
     OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
             TutorialType tutorialType) {
         super(fragment, tutorialType);
@@ -112,11 +116,9 @@
 
     @Override
     protected int getMockAppTaskLayoutResId() {
-        return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                ? R.layout.gesture_tutorial_mock_task_view
-                : mTutorialFragment.isLargeScreen()
-                        ? R.layout.gesture_tutorial_tablet_mock_conversation_list
-                        : R.layout.gesture_tutorial_mock_conversation_list;
+        return mTutorialFragment.isLargeScreen()
+                ? R.layout.gesture_tutorial_tablet_mock_conversation_list
+                : R.layout.gesture_tutorial_mock_conversation_list;
     }
 
     @Override
@@ -128,11 +130,31 @@
                 : R.raw.overview_gesture_tutorial_animation;
     }
 
-    @Override
-    protected int getSwipeActionColor() {
+    @ColorInt
+    private int getFakeTaskViewStartColor() {
         return mTutorialFragment.mRootView.mColorSurfaceOverview;
     }
 
+    @ColorInt
+    private int getFakeTaskViewEndColor() {
+        return getMockPreviousAppTaskThumbnailColor();
+    }
+
+    @Override
+    protected int getFakeTaskViewColor() {
+        return isGestureCompleted()
+                ? getFakeTaskViewEndColor()
+                : getFakeTaskViewStartColor();
+    }
+
+    @Override
+    protected int getFakeLauncherColor() {
+        return ColorUtils.blendARGB(
+                mTutorialFragment.mRootView.mColorSurfaceContainer,
+                mTutorialFragment.mRootView.mColorOnSurfaceOverview,
+                LAUNCHER_COLOR_BLENDING_RATIO);
+    }
+
     @Override
     protected int getHotseatIconColor() {
         return mTutorialFragment.mRootView.mColorOnSurfaceOverview;
@@ -159,7 +181,7 @@
                     case BACK_CANCELLED_FROM_LEFT:
                     case BACK_CANCELLED_FROM_RIGHT:
                     case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
                         break;
                 }
@@ -190,7 +212,7 @@
                     }
                     case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
                     case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
                         break;
                     case OVERVIEW_GESTURE_COMPLETED:
@@ -204,7 +226,7 @@
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
                     case HOME_OR_OVERVIEW_CANCELLED:
-                        fadeOutFakeTaskView(false, true, null);
+                        fadeOutFakeTaskView(false, null);
                         showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
                         break;
                 }
@@ -229,15 +251,21 @@
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animator) {
-                    new Handler().postDelayed(() -> {
-                        mFakeTaskView.setVisibility(View.INVISIBLE);
-                        if (!mTutorialFragment.isLargeScreen()) {
-                            mFakePreviousTaskView.animateToFillScreen(
-                                    () -> onSuccessAnimationComplete());
-                        } else {
-                            onSuccessAnimationComplete();
-                        }
-                    }, TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
+                    new Handler().postDelayed(
+                            () -> fadeOutFakeTaskView(
+                                    /* toOverviewFirst= */ true,
+                                    /* animatePreviousTask= */ false,
+                                    /* resetViews= */ false,
+                                    /* updateListener= */ v -> mFakeTaskView.setBackgroundColor(
+                                            ColorUtils.blendARGB(
+                                                    getFakeTaskViewStartColor(),
+                                                    getFakeTaskViewEndColor(),
+                                                    v.getAnimatedFraction())),
+                                    /* onEndRunnable= */ () -> {
+                                        showSuccessFeedback();
+                                        resetTaskViews();
+                                    }),
+                            TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
                 }
             });
         }
@@ -259,9 +287,4 @@
         animset.start();
         mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
     }
-
-    private void onSuccessAnimationComplete() {
-        mFakeLauncherView.setBackgroundColor(getMockPreviousAppTaskThumbnailColor());
-        showSuccessFeedback();
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 66c659a..0bbf373 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -78,7 +78,7 @@
     private final AnimatorListenerAdapter mResetTaskView = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            resetTaskView();
+            resetTaskViews();
         }
     };
 
@@ -122,7 +122,7 @@
         mRunningWindowAnim = null;
     }
 
-    void resetTaskView() {
+    void resetTaskViews() {
         mFakeHotseatView.setVisibility(View.INVISIBLE);
         mFakeIconView.setVisibility(View.INVISIBLE);
         if (mTutorialFragment.getActivity() != null) {
@@ -141,10 +141,21 @@
         mShowPreviousTasks = false;
         mRunningWindowAnim = null;
     }
+    void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
+        fadeOutFakeTaskView(
+                toOverviewFirst,
+                /* animatePreviousTask= */ true,
+                /* resetViews= */ true,
+                /* updateListener= */ null,
+                onEndRunnable);
+    }
 
     /** Fades the task view, optionally after animating to a fake Overview. */
-    void fadeOutFakeTaskView(boolean toOverviewFirst, boolean reset,
-                             @Nullable Runnable onEndRunnable) {
+    void fadeOutFakeTaskView(boolean toOverviewFirst,
+            boolean animatePreviousTask,
+            boolean resetViews,
+            @Nullable ValueAnimator.AnimatorUpdateListener updateListener,
+            @Nullable Runnable onEndRunnable) {
         cancelRunningAnimation();
         PendingAnimation anim = new PendingAnimation(300);
         if (toOverviewFirst) {
@@ -155,20 +166,20 @@
                 public void onAnimationEnd(Animator animation, boolean isReverse) {
                     PendingAnimation fadeAnim =
                             new PendingAnimation(TASK_VIEW_END_ANIMATION_DURATION_MILLIS);
-                    if (reset) {
-                        fadeAnim.setFloat(mTaskViewSwipeUpAnimation
-                                .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+                    fadeAnim.setFloat(mTaskViewSwipeUpAnimation
+                            .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+                    if (resetViews) {
                         fadeAnim.addListener(mResetTaskView);
-                    } else {
-                        fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-                        fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
                     }
                     if (onEndRunnable != null) {
                         fadeAnim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
                     }
+                    if (updateListener != null) {
+                        fadeAnim.addOnFrameListener(updateListener);
+                    }
                     AnimatorSet animset = fadeAnim.buildAnim();
 
-                    if (reset && mTutorialFragment.isLargeScreen()) {
+                    if (animatePreviousTask && mTutorialFragment.isLargeScreen()) {
                         animset.addListener(new AnimatorListenerAdapter() {
                             @Override
                             public void onAnimationStart(Animator animation) {
@@ -190,13 +201,10 @@
                 }
             });
         } else {
-            if (reset) {
-                anim.setFloat(mTaskViewSwipeUpAnimation
-                        .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+            anim.setFloat(mTaskViewSwipeUpAnimation
+                    .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+            if (resetViews) {
                 anim.addListener(mResetTaskView);
-            } else {
-                anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-                anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
             }
             if (onEndRunnable != null) {
                 anim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 36655d2..084f8c1 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -268,7 +268,12 @@
     }
 
     @ColorInt
-    protected abstract int getSwipeActionColor();
+    protected int getFakeTaskViewColor() {
+        return Color.TRANSPARENT;
+    }
+
+    @ColorInt
+    protected abstract int getFakeLauncherColor();
 
     @ColorInt
     protected int getExitingAppColor() {
@@ -445,6 +450,7 @@
     }
 
     private void showSuccessPage() {
+        pauseAndHideLottieAnimation();
         mCheckmarkAnimation.setVisibility(View.VISIBLE);
         mCheckmarkAnimation.playAnimation();
         mFeedbackTitleView.setTextAppearance(mContext, getSuccessTitleTextAppearance());
@@ -591,7 +597,7 @@
 
     protected void resetViewsForBackGesture() {
         mFakeTaskView.setVisibility(View.VISIBLE);
-        mFakeTaskView.setBackgroundColor(getSwipeActionColor());
+        mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
         mExitingAppView.setVisibility(View.VISIBLE);
 
         // reset the exiting app's dimensions
@@ -690,11 +696,10 @@
                     mContext, getMockWallpaperResId()));
             mTutorialFragment.updateFeedbackAnimation();
             mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                    ? getSwipeActionColor()
+                    ? getFakeLauncherColor()
                     : mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color));
             updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId());
             mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1);
-            updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
             mFakeTaskView.animate().alpha(1).setListener(
                     AnimatorListeners.forSuccessCallback(() -> mFakeTaskView.animate().cancel()));
             mFakePreviousTaskView.setFakeTaskViewFillColor(getMockPreviousAppTaskThumbnailColor());
@@ -703,12 +708,15 @@
 
             if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
                 mExitingAppView.setBackgroundColor(getExitingAppColor());
+                mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
                 updateHotseatChildViewColor(mFakeIconView);
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
+            } else {
+                updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 9f15e19..bfad643 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -143,6 +143,7 @@
         return null;
     }
 
+    @NonNull
     abstract TutorialController createController(TutorialType type);
 
     abstract Class<? extends TutorialController> getControllerClass();
@@ -374,9 +375,15 @@
     void changeController(TutorialType tutorialType) {
         if (getControllerClass().isInstance(mTutorialController)) {
             mTutorialController.setTutorialType(tutorialType);
+            if (isGestureComplete()) {
+                mTutorialController.setGestureCompleted();
+            }
             mTutorialController.fadeTaskViewAndRun(mTutorialController::transitToController);
         } else {
             mTutorialController = createController(tutorialType);
+            if (isGestureComplete()) {
+                mTutorialController.setGestureCompleted();
+            }
             mTutorialController.transitToController();
         }
         mEdgeBackGestureHandler.registerBackGestureAttemptCallback(mTutorialController);