resolve merge conflicts of 694b667138085cc07e8c6cc50167e34788a0ba90 to sc-mainline-prod

Test: manual
Bug: none

Change-Id: Id03c870b62f6a6a73ddc7669a1ec2eef6ba07460
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 3f75d32..281f735 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -95,16 +95,14 @@
     <string name="back_gesture_feedback_swipe_too_far_from_left_edge">Make sure you swipe from the far-left edge.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_cancelled_left_edge">Make sure you swipe from the left edge to the middle of the screen and let go.</string>
-    <!-- Feedback title shown after completing the left back gesture before continuing on to the right edge. [CHAR LIMIT=60] -->
-    <string name="back_gesture_feedback_title_complete_left_edge">Nice! Now swipe from the right to go back</string>
-    <!-- Feedback subtitle shown after completing the left back gesture before continuing on to the right edge. [CHAR LIMIT=200] -->
-    <string name="back_gesture_feedback_subtitle_complete_left_edge">You can also go back to the last screen by swiping from the right edge to the middle of the screen.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_swipe_too_far_from_right_edge">Make sure you swipe from the far-right edge.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is cancelled. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_cancelled_right_edge">Make sure you swipe from the right edge to the middle of the screen and let go.</string>
     <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
-    <string name="back_gesture_feedback_complete_with_follow_up">You completed the go back gesture. Next up, learn how to switch apps.</string>
+    <string name="back_gesture_feedback_complete_with_back_right_follow_up">You learned how to swipe from the left to go back.</string>
+    <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
+    <string name="back_gesture_feedback_complete_with_overview_follow_up">You learned how to swipe from the right to go back. Next up, learn how to switch apps.</string>
     <!-- Feedback shown after completing the back gesture step if the user started this tutorial individually. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_complete_without_follow_up">You completed the go back gesture.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
@@ -112,10 +110,14 @@
     <!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
     <string name="back_gesture_tutorial_confirm_subtitle">To change the sensitivity of the back gesture, go to Settings</string>
     <!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
-    <!-- Introduction title for the Back gesture tutorial. [CHAR LIMIT=100] -->
-    <string name="back_gesture_intro_title">Swipe from the left to go back</string>
-    <!-- Introduction subtitle for the Back gesture tutorial. [CHAR LIMIT=100] -->
-    <string name="back_gesture_intro_subtitle">To go back to the last screen you were on, swipe from the left edge to the middle of the screen.</string>
+    <!-- Introduction title for the left edge Back gesture tutorial. [CHAR LIMIT=100] -->
+    <string name="back_left_gesture_intro_title">Swipe from the left to go back</string>
+    <!-- Introduction title for the right edge Back gesture tutorial. [CHAR LIMIT=100] -->
+    <string name="back_right_gesture_intro_title">Swipe from the right to go back</string>
+    <!-- Introduction subtitle for the Back left gesture tutorial. [CHAR LIMIT=200] -->
+    <string name="back_left_gesture_intro_subtitle">To go back to the last screen you were on, swipe from the left edge to the middle of the screen.</string>
+    <!-- Introduction subtitle for the Back right gesture tutorial. [CHAR LIMIT=100] -->
+    <string name="back_right_gesture_intro_subtitle">You can also go back to the last screen by swiping from the right edge to the middle of the screen. Try it now.</string>
 
     <string name="home_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
     <!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index a0fb51c..ab42a2b 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -37,13 +37,14 @@
     @Override
     public Integer getIntroductionTitle() {
         return mTutorialType == LEFT_EDGE_BACK_NAVIGATION
-                ? R.string.back_gesture_intro_title : null;
+                ? R.string.back_left_gesture_intro_title : R.string.back_right_gesture_intro_title;
     }
 
     @Override
     public Integer getIntroductionSubtitle() {
         return mTutorialType == LEFT_EDGE_BACK_NAVIGATION
-                ? R.string.back_gesture_intro_subtitle : null;
+                ? R.string.back_left_gesture_intro_subtitle
+                : R.string.back_right_gesture_intro_subtitle;
     }
 
     @Override
@@ -53,6 +54,9 @@
 
     @Override
     public void onBackGestureAttempted(BackGestureResult result) {
+        if (mGestureCompleted) {
+            return;
+        }
         switch (mTutorialType) {
             case RIGHT_EDGE_BACK_NAVIGATION:
                 handleAttemptFromRight(result);
@@ -76,9 +80,9 @@
                 hideFeedback(true);
                 mFakeTaskView.setBackground(AppCompatResources.getDrawable(mContext,
                         R.drawable.mock_conversations_list));
-                int subtitleResId = mTutorialFragment.getNumSteps() == 1
+                int subtitleResId = mTutorialFragment.isAtFinalStep()
                         ? R.string.back_gesture_feedback_complete_without_follow_up
-                        : R.string.back_gesture_feedback_complete_with_follow_up;
+                        : R.string.back_gesture_feedback_complete_with_overview_follow_up;
                 showFeedback(subtitleResId, true);
                 break;
             case BACK_CANCELLED_FROM_RIGHT:
@@ -102,10 +106,10 @@
                 hideFeedback(true);
                 mFakeTaskView.setBackground(AppCompatResources.getDrawable(mContext,
                         R.drawable.mock_conversations_list));
-                showFeedback(
-                        R.string.back_gesture_feedback_title_complete_left_edge,
-                        R.string.back_gesture_feedback_subtitle_complete_left_edge,
-                        () -> mTutorialFragment.changeController(RIGHT_EDGE_BACK_NAVIGATION));
+                int subtitleResId = mTutorialFragment.isAtFinalStep()
+                        ? R.string.back_gesture_feedback_complete_without_follow_up
+                        : R.string.back_gesture_feedback_complete_with_back_right_follow_up;
+                showFeedback(subtitleResId, true);
                 break;
             case BACK_CANCELLED_FROM_LEFT:
                 showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
@@ -123,6 +127,9 @@
 
     @Override
     public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+        if (mGestureCompleted) {
+            return;
+        }
         if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
             if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
                 mTutorialFragment.closeTutorial();
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index ff50a0e..deaf586 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -48,6 +48,9 @@
 
     @Override
     public void onBackGestureAttempted(BackGestureResult result) {
+        if (mGestureCompleted) {
+            return;
+        }
         switch (mTutorialType) {
             case HOME_NAVIGATION:
                 switch (result) {
@@ -70,7 +73,7 @@
 
     @Override
     public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
-        if (mHideFeedbackEndAction != null) {
+        if (mGestureCompleted) {
             return;
         }
         switch (mTutorialType) {
@@ -80,7 +83,7 @@
                         mTutorialFragment.releaseGestureVideoView();
                         animateFakeTaskViewHome(finalVelocity, null);
                         showActionButton();
-                        int subtitleResId = mTutorialFragment.getNumSteps() == 1
+                        int subtitleResId = mTutorialFragment.isAtFinalStep()
                                 ? R.string.home_gesture_feedback_complete_without_follow_up
                                 : R.string.home_gesture_feedback_complete_with_follow_up;
                         showFeedback(subtitleResId, true);
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 7b0961e..984d054 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -55,6 +55,9 @@
 
     @Override
     public void onBackGestureAttempted(BackGestureResult result) {
+        if (mGestureCompleted) {
+            return;
+        }
         switch (mTutorialType) {
             case OVERVIEW_NAVIGATION:
                 switch (result) {
@@ -77,7 +80,7 @@
 
     @Override
     public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
-        if (mHideFeedbackEndAction != null) {
+        if (mGestureCompleted) {
             return;
         }
         switch (mTutorialType) {
@@ -103,9 +106,10 @@
                         animset.start();
                         mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
                         onMotionPaused(true /*arbitrary value*/);
-                        int subtitleResId = mTutorialFragment.getNumSteps() == 1
-                                ? R.string.overview_gesture_feedback_complete_without_follow_up
-                                : R.string.overview_gesture_feedback_complete_with_follow_up;
+                        int subtitleResId = mTutorialFragment.getNumSteps() > 1
+                                && mTutorialFragment.isAtFinalStep()
+                                ? R.string.overview_gesture_feedback_complete_with_follow_up
+                                : R.string.overview_gesture_feedback_complete_without_follow_up;
                         showFeedback(subtitleResId, true);
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 66e0400..b06f001 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -214,7 +214,7 @@
 
     @Override
     public void setNavBarGestureProgress(@Nullable Float displacement) {
-        if (mHideFeedbackEndAction != null) {
+        if (mGestureCompleted) {
             return;
         }
         if (displacement != null) {
@@ -238,7 +238,7 @@
 
     @Override
     public void onMotionPaused(boolean unused) {
-        if (mHideFeedbackEndAction != null) {
+        if (mGestureCompleted) {
             return;
         }
         if (mShowTasks) {
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index a03e37e..5e94574 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -27,12 +27,14 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.annotation.CallSuper;
 import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.appcompat.app.AlertDialog;
@@ -53,7 +55,6 @@
     private static final String PIXEL_TIPS_APP_PACKAGE_NAME = "com.google.android.apps.tips";
     private static final CharSequence DEFAULT_PIXEL_TIPS_APP_NAME = "Pixel Tips";
 
-    private static final int FEEDBACK_VISIBLE_MS = 5000;
     private static final int FEEDBACK_ANIMATION_MS = 250;
     private static final int RIPPLE_VISIBLE_MS = 300;
 
@@ -73,10 +74,10 @@
     final RippleDrawable mRippleDrawable;
     final Button mActionButton;
     final TutorialStepIndicator mTutorialStepView;
-    private final Runnable mHideFeedbackRunnable;
-    Runnable mHideFeedbackEndAction;
     private final AlertDialog mSkipTutorialDialog;
 
+    protected boolean mGestureCompleted = false;
+
     TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
         mTutorialFragment = tutorialFragment;
         mTutorialType = tutorialType;
@@ -99,12 +100,6 @@
         mTutorialStepView =
                 rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
         mSkipTutorialDialog = createSkipTutorialDialog();
-
-        mHideFeedbackRunnable =
-                () -> mFeedbackView.animate()
-                        .translationY(-mFeedbackView.getTop() - mFeedbackView.getHeight())
-                        .setDuration(FEEDBACK_ANIMATION_MS)
-                        .withEndAction(this::hideFeedbackEndAction).start();
     }
 
     private void showSkipTutorialDialog() {
@@ -156,6 +151,25 @@
         return null;
     }
 
+    void showFeedback() {
+        if (mGestureCompleted) {
+            mFeedbackView.setTranslationY(0);
+            return;
+        }
+        AnimatedVectorDrawable tutorialAnimation = mTutorialFragment.getTutorialAnimation();
+        AnimatedVectorDrawable gestureAnimation = mTutorialFragment.getGestureAnimation();
+
+        if (tutorialAnimation != null && gestureAnimation != null) {
+            TextView title = mFeedbackView.findViewById(
+                    R.id.gesture_tutorial_fragment_feedback_title);
+
+            playFeedbackVideo(tutorialAnimation, gestureAnimation, () -> {
+                mFeedbackView.setTranslationY(0);
+                title.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+            });
+        }
+    }
+
     /**
      * Show feedback reflecting a failed gesture attempt.
      *
@@ -166,97 +180,49 @@
     }
 
     /**
-     * Show feedback reflecting a failed gesture attempt.
-     *
-     * @param showActionButton Whether the tutorial feedback's action button should be shown.
-     **/
-    void showFeedback(int subtitleResId, boolean showActionButton) {
-        showFeedback(subtitleResId, showActionButton ? () -> {} : null, showActionButton);
-    }
-
-    /**
-     * Show feedback reflecting a failed gesture attempt.
-     **/
-    void showFeedback(int titleResId, int subtitleResId, @Nullable Runnable successEndAction) {
-        showFeedback(titleResId, subtitleResId, successEndAction, false);
-    }
-
-    /**
      * Show feedback reflecting the result of a gesture attempt.
      *
-     * @param successEndAction Non-null iff the gesture was successful; this is run after the
-     *                        feedback is shown (i.e. to go to the next step)
+     * @param isGestureSuccessful Whether the tutorial feedback's action button should be shown.
      **/
-    void showFeedback(
-            int subtitleResId, @Nullable Runnable successEndAction, boolean showActionButton) {
+    void showFeedback(int subtitleResId, boolean isGestureSuccessful) {
         showFeedback(
-                successEndAction == null
-                        ? R.string.gesture_tutorial_try_again
-                        : R.string.gesture_tutorial_nice,
+                isGestureSuccessful
+                        ? R.string.gesture_tutorial_nice : R.string.gesture_tutorial_try_again,
                 subtitleResId,
-                successEndAction,
-                showActionButton);
+                isGestureSuccessful);
     }
+
     void showFeedback(
             int titleResId,
             int subtitleResId,
-            @Nullable Runnable successEndAction,
-            boolean showActionButton) {
-        if (mHideFeedbackEndAction != null) {
-            return;
-        }
+            boolean isGestureSuccessful) {
         TextView title = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_title);
         title.setText(titleResId);
         TextView subtitle =
                 mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
         subtitle.setText(subtitleResId);
-        if (showActionButton) {
+        if (isGestureSuccessful) {
             showActionButton();
         }
-        mHideFeedbackEndAction = successEndAction;
+        mGestureCompleted = isGestureSuccessful;
 
         AnimatedVectorDrawable tutorialAnimation = mTutorialFragment.getTutorialAnimation();
         AnimatedVectorDrawable gestureAnimation = mTutorialFragment.getGestureAnimation();
         if (tutorialAnimation != null && gestureAnimation != null) {
-            if (successEndAction == null) {
-                if (tutorialAnimation.isRunning()) {
-                    tutorialAnimation.reset();
-                }
-                tutorialAnimation.registerAnimationCallback(new Animatable2.AnimationCallback() {
-
-                    @Override
-                    public void onAnimationStart(Drawable drawable) {
-                        super.onAnimationStart(drawable);
-
-                        mGestureVideoView.setVisibility(GONE);
-                        if (gestureAnimation.isRunning()) {
-                            gestureAnimation.stop();
-                        }
-
-                        mFeedbackView.setTranslationY(
-                                -mFeedbackView.getHeight() - mFeedbackView.getTop());
-                        mFeedbackView.setVisibility(View.VISIBLE);
-                        mFeedbackView.animate()
-                                .setDuration(FEEDBACK_ANIMATION_MS)
-                                .translationY(0)
-                                .start();
-                        mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
-                        mFeedbackView.postDelayed(mHideFeedbackRunnable, FEEDBACK_VISIBLE_MS);
-                    }
-
-                    @Override
-                    public void onAnimationEnd(Drawable drawable) {
-                        super.onAnimationEnd(drawable);
-
-                        mGestureVideoView.setVisibility(View.VISIBLE);
-                        gestureAnimation.start();
-
-                        tutorialAnimation.unregisterAnimationCallback(this);
-                    }
+            if (!isGestureSuccessful) {
+                playFeedbackVideo(tutorialAnimation, gestureAnimation, () -> {
+                    mFeedbackView.setTranslationY(
+                            -mFeedbackView.getHeight() - mFeedbackView.getTop());
+                    mFeedbackView.setVisibility(View.VISIBLE);
+                    mFeedbackView.animate()
+                            .setDuration(FEEDBACK_ANIMATION_MS)
+                            .translationY(0)
+                            .start();
+                    title.postDelayed(
+                            () -> title.sendAccessibilityEvent(
+                                    AccessibilityEvent.TYPE_VIEW_FOCUSED),
+                            FEEDBACK_ANIMATION_MS);
                 });
-
-                tutorialAnimation.start();
-                mFeedbackVideoView.setVisibility(View.VISIBLE);
                 return;
             } else {
                 mTutorialFragment.releaseFeedbackVideoView();
@@ -268,15 +234,13 @@
                 .setDuration(FEEDBACK_ANIMATION_MS)
                 .translationY(0)
                 .start();
-        mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
-        if (!showActionButton) {
-            mFeedbackView.postDelayed(mHideFeedbackRunnable, FEEDBACK_VISIBLE_MS);
-        }
+        title.postDelayed(
+                () -> title.sendAccessibilityEvent(
+                        AccessibilityEvent.TYPE_VIEW_FOCUSED),
+                FEEDBACK_ANIMATION_MS);
     }
 
     void hideFeedback(boolean releaseFeedbackVideo) {
-        mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
-        mHideFeedbackEndAction = null;
         mFeedbackView.clearAnimation();
         mFeedbackView.setVisibility(View.INVISIBLE);
         if (releaseFeedbackVideo) {
@@ -284,11 +248,41 @@
         }
     }
 
-    void hideFeedbackEndAction() {
-        if (mHideFeedbackEndAction != null) {
-            mHideFeedbackEndAction.run();
-            mHideFeedbackEndAction = null;
+    private void playFeedbackVideo(
+            @NonNull AnimatedVectorDrawable tutorialAnimation,
+            @NonNull AnimatedVectorDrawable gestureAnimation,
+            @NonNull Runnable onStartRunnable) {
+
+        if (tutorialAnimation.isRunning()) {
+            tutorialAnimation.reset();
         }
+        tutorialAnimation.registerAnimationCallback(new Animatable2.AnimationCallback() {
+
+            @Override
+            public void onAnimationStart(Drawable drawable) {
+                super.onAnimationStart(drawable);
+
+                mGestureVideoView.setVisibility(GONE);
+                if (gestureAnimation.isRunning()) {
+                    gestureAnimation.stop();
+                }
+
+                onStartRunnable.run();
+            }
+
+            @Override
+            public void onAnimationEnd(Drawable drawable) {
+                super.onAnimationEnd(drawable);
+
+                mGestureVideoView.setVisibility(View.VISIBLE);
+                gestureAnimation.start();
+
+                tutorialAnimation.unregisterAnimationCallback(this);
+            }
+        });
+
+        tutorialAnimation.start();
+        mFeedbackVideoView.setVisibility(View.VISIBLE);
     }
 
     void setRippleHotspot(float x, float y) {
@@ -317,6 +311,7 @@
         updateSubtext();
         updateDrawables();
 
+        mGestureCompleted = false;
         if (mFakeLauncherView != null) {
             mFakeLauncherView.setVisibility(View.INVISIBLE);
         }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 0220f2d..55c569d 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -57,6 +57,8 @@
     @Nullable private AnimatedVectorDrawable mGestureAnimation = null;
     private boolean mIntroductionShown = false;
 
+    private boolean mFragmentStopped = false;
+
     public static TutorialFragment newInstance(TutorialType tutorialType) {
         TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
         if (fragment == null) {
@@ -154,6 +156,8 @@
     public void onStop() {
         super.onStop();
         releaseFeedbackVideoView();
+        releaseGestureVideoView();
+        mFragmentStopped = true;
     }
 
     void initializeFeedbackVideoView() {
@@ -165,8 +169,7 @@
             Integer introTileStringResId = mTutorialController.getIntroductionTitle();
             Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
             if (introTileStringResId != null && introSubtitleResId != null) {
-                mTutorialController.showFeedback(introTileStringResId,
-                        introSubtitleResId, null, false);
+                mTutorialController.showFeedback(introTileStringResId, introSubtitleResId, false);
                 mIntroductionShown = true;
             }
         }
@@ -244,7 +247,12 @@
     @Override
     public void onResume() {
         super.onResume();
-        changeController(mTutorialType);
+        if (mFragmentStopped) {
+            mTutorialController.showFeedback();
+            mFragmentStopped = false;
+        } else {
+            changeController(mTutorialType);
+        }
     }
 
     @Override
@@ -326,6 +334,10 @@
         return gestureSandboxActivity == null ? -1 : gestureSandboxActivity.getNumSteps();
     }
 
+    boolean isAtFinalStep() {
+        return getCurrentStep() == getNumSteps();
+    }
+
     @Nullable
     private GestureSandboxActivity getGestureSandboxActivity() {
         Context context = getContext();
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index d0a8c71..c6b0b13 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -279,6 +279,7 @@
                     new String[] {
                             "HOME_NAVIGATION",
                             "LEFT_EDGE_BACK_NAVIGATION",
+                            "RIGHT_EDGE_BACK_NAVIGATION",
                             "OVERVIEW_NAVIGATION"}));
             return true;
         });
@@ -290,7 +291,7 @@
         launchBackTutorialPreference.setOnPreferenceClickListener(preference -> {
             startActivity(launchSandboxIntent.putExtra(
                     "tutorial_steps",
-                    new String[] {"LEFT_EDGE_BACK_NAVIGATION"}));
+                    new String[] {"LEFT_EDGE_BACK_NAVIGATION", "RIGHT_EDGE_BACK_NAVIGATION"}));
             return true;
         });
         sandboxCategory.addPreference(launchBackTutorialPreference);