diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java index 6862f071bc..5c81e5f37b 100644 --- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java @@ -104,7 +104,13 @@ final class AssistantGestureTutorialController extends TutorialController { hideFeedback(); hideHandCoachingAnimation(); showRippleEffect( - () -> mTutorialFragment.changeController(ASSISTANT_COMPLETE)); + () -> { + if (mTutorialFragment.isTutorialComplete()) { + mTutorialFragment.changeController(ASSISTANT_COMPLETE); + } else { + mTutorialFragment.continueTutorial(); + } + }); break; case ASSISTANT_NOT_STARTED_BAD_ANGLE: showFeedback(R.string.assistant_gesture_feedback_swipe_not_diagonal); diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java index 921e5681c6..161e015481 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java @@ -130,7 +130,13 @@ final class BackGestureTutorialController extends TutorialController { hideFeedback(); hideHandCoachingAnimation(); showRippleEffect( - () -> mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE)); + () -> { + if (mTutorialFragment.isTutorialComplete()) { + mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE); + } else { + mTutorialFragment.continueTutorial(); + } + }); break; case BACK_CANCELLED_FROM_LEFT: showFeedback(R.string.back_gesture_feedback_cancelled_left_edge); diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java index f8d9d8d502..8b6777b6ac 100644 --- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java @@ -15,8 +15,6 @@ */ package com.android.quickstep.interaction; -import static com.android.quickstep.interaction.TutorialFragment.KEY_TUTORIAL_TYPE; - import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; @@ -25,11 +23,14 @@ import android.view.Display; import android.view.View; import android.view.Window; +import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import com.android.launcher3.R; import com.android.quickstep.interaction.TutorialController.TutorialType; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.List; /** Shows the gesture interactive sandbox in full screen mode. */ @@ -37,6 +38,9 @@ public class GestureSandboxActivity extends FragmentActivity { private static final String LOG_TAG = "GestureSandboxActivity"; + private static final String KEY_TUTORIAL_STEPS = "tutorial_steps"; + + private Deque mTutorialSteps; private TutorialFragment mFragment; @Override @@ -45,7 +49,9 @@ public class GestureSandboxActivity extends FragmentActivity { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.gesture_tutorial_activity); - mFragment = TutorialFragment.newInstance(getTutorialType(getIntent().getExtras())); + Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState; + mTutorialSteps = getTutorialSteps(args); + mFragment = TutorialFragment.newInstance(mTutorialSteps.pop()); getSupportFragmentManager().beginTransaction() .add(R.id.gesture_tutorial_fragment_container, mFragment) .commit(); @@ -72,17 +78,65 @@ public class GestureSandboxActivity extends FragmentActivity { } } - private TutorialType getTutorialType(Bundle extras) { - TutorialType defaultType = TutorialType.RIGHT_EDGE_BACK_NAVIGATION; + @Override + protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) { + savedInstanceState.putStringArray(KEY_TUTORIAL_STEPS, getTutorialStepNames()); + super.onSaveInstanceState(savedInstanceState); + } - if (extras == null || !extras.containsKey(KEY_TUTORIAL_TYPE)) { - return defaultType; + /** Returns true iff there aren't anymore tutorial types to display to the user. */ + public boolean isTutorialComplete() { + return mTutorialSteps.isEmpty(); + } + + /** + * Replaces the current TutorialFragment, continuing to the next tutorial step if there is one. + * + * If there is no following step, the tutorial is closed. + */ + public void continueTutorial() { + if (isTutorialComplete()) { + mFragment.closeTutorial(); + return; } - try { - return TutorialType.valueOf(extras.getString(KEY_TUTORIAL_TYPE, "")); - } catch (IllegalArgumentException e) { - return defaultType; + mFragment = TutorialFragment.newInstance(mTutorialSteps.pop()); + getSupportFragmentManager().beginTransaction() + .replace(R.id.gesture_tutorial_fragment_container, mFragment) + .runOnCommit(() -> mFragment.onAttachedToWindow()) + .commit(); + } + + private String[] getTutorialStepNames() { + String[] tutorialStepNames = new String[mTutorialSteps.size()]; + + int i = 0; + for (TutorialType tutorialStep : mTutorialSteps) { + tutorialStepNames[i++] = tutorialStep.name(); } + + return tutorialStepNames; + } + + private Deque getTutorialSteps(Bundle extras) { + Deque defaultSteps = new ArrayDeque<>(); + defaultSteps.push(TutorialType.RIGHT_EDGE_BACK_NAVIGATION); + + if (extras == null || !extras.containsKey(KEY_TUTORIAL_STEPS)) { + return defaultSteps; + } + + String[] tutorialStepNames = extras.getStringArray(KEY_TUTORIAL_STEPS); + + if (tutorialStepNames == null) { + return defaultSteps; + } + + Deque tutorialSteps = new ArrayDeque<>(); + for (String tutorialStepName : tutorialStepNames) { + tutorialSteps.addLast(TutorialType.valueOf(tutorialStepName)); + } + + return tutorialSteps; } private void hideSystemUI() { diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java index 0edabd45c5..95352d1a23 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java @@ -94,8 +94,13 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll case HOME_NAVIGATION: switch (result) { case HOME_GESTURE_COMPLETED: { - animateFakeTaskViewHome(finalVelocity, () -> - mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE)); + animateFakeTaskViewHome(finalVelocity, () -> { + if (mTutorialFragment.isTutorialComplete()) { + mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE); + } else { + mTutorialFragment.continueTutorial(); + } + }); break; } case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE: diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java index c636ebaea9..45cbd0b571 100644 --- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java @@ -104,8 +104,13 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge); break; case OVERVIEW_GESTURE_COMPLETED: - fadeOutFakeTaskView(true, () -> - mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE)); + fadeOutFakeTaskView(true, () -> { + if (mTutorialFragment.isTutorialComplete()) { + mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE); + } else { + mTutorialFragment.continueTutorial(); + } + }); break; case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: case HOME_OR_OVERVIEW_CANCELLED: diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index f297d5a835..608fe72ff9 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -54,6 +54,7 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { fragment = new BackGestureTutorialFragment(); tutorialType = TutorialType.RIGHT_EDGE_BACK_NAVIGATION; } + Bundle args = new Bundle(); args.putSerializable(KEY_TUTORIAL_TYPE, tutorialType); fragment.setArguments(args); @@ -197,6 +198,20 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { return mHandCoachingAnimation; } + void continueTutorial() { + if (!(getContext() instanceof GestureSandboxActivity)) { + closeTutorial(); + return; + } + GestureSandboxActivity gestureSandboxActivity = (GestureSandboxActivity) getContext(); + + if (gestureSandboxActivity == null) { + closeTutorial(); + return; + } + gestureSandboxActivity.continueTutorial(); + } + void closeTutorial() { FragmentActivity activity = getActivity(); if (activity != null) { @@ -207,4 +222,13 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { void startSystemNavigationSetting() { startActivity(new Intent("com.android.settings.GESTURE_NAVIGATION_SETTINGS")); } + + boolean isTutorialComplete() { + if (!(getContext() instanceof GestureSandboxActivity)) { + return true; + } + GestureSandboxActivity gestureSandboxActivity = (GestureSandboxActivity) getContext(); + + return gestureSandboxActivity == null || gestureSandboxActivity.isTutorialComplete(); + } } diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java index f4b059d8d8..47d214d0a8 100644 --- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java +++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java @@ -275,7 +275,8 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { launchBackTutorialPreference.setSummary("Learn how to use the Back gesture"); launchBackTutorialPreference.setOnPreferenceClickListener(preference -> { startActivity(launchSandboxIntent.putExtra( - "tutorial_type", "RIGHT_EDGE_BACK_NAVIGATION")); + "tutorial_steps", + new String[] {"RIGHT_EDGE_BACK_NAVIGATION"})); return true; }); sandboxCategory.addPreference(launchBackTutorialPreference); @@ -284,7 +285,9 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { launchHomeTutorialPreference.setTitle("Launch Home Tutorial"); launchHomeTutorialPreference.setSummary("Learn how to use the Home gesture"); launchHomeTutorialPreference.setOnPreferenceClickListener(preference -> { - startActivity(launchSandboxIntent.putExtra("tutorial_type", "HOME_NAVIGATION")); + startActivity(launchSandboxIntent.putExtra( + "tutorial_steps", + new String[] {"HOME_NAVIGATION"})); return true; }); sandboxCategory.addPreference(launchHomeTutorialPreference); @@ -293,7 +296,9 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial"); launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture"); launchOverviewTutorialPreference.setOnPreferenceClickListener(preference -> { - startActivity(launchSandboxIntent.putExtra("tutorial_type", "OVERVIEW_NAVIGATION")); + startActivity(launchSandboxIntent.putExtra( + "tutorial_steps", + new String[] {"OVERVIEW_NAVIGATION"})); return true; }); sandboxCategory.addPreference(launchOverviewTutorialPreference); @@ -302,7 +307,9 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { launchAssistantTutorialPreference.setTitle("Launch Assistant Tutorial"); launchAssistantTutorialPreference.setSummary("Learn how to use the Assistant gesture"); launchAssistantTutorialPreference.setOnPreferenceClickListener(preference -> { - startActivity(launchSandboxIntent.putExtra("tutorial_type", "ASSISTANT")); + startActivity(launchSandboxIntent.putExtra( + "tutorial_steps", + new String[] {"ASSISTANT"})); return true; }); sandboxCategory.addPreference(launchAssistantTutorialPreference); @@ -311,7 +318,9 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { launchSandboxModeTutorialPreference.setTitle("Launch Sandbox Mode"); launchSandboxModeTutorialPreference.setSummary("Practice navigation gestures"); launchSandboxModeTutorialPreference.setOnPreferenceClickListener(preference -> { - startActivity(launchSandboxIntent.putExtra("tutorial_type", "SANDBOX_MODE")); + startActivity(launchSandboxIntent.putExtra( + "tutorial_steps", + new String[] {"SANDBOX_MODE"})); return true; }); sandboxCategory.addPreference(launchSandboxModeTutorialPreference);