Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfa0baec authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Polish the gesture navigation tutorial sandbox" into sc-dev

parents 2f0c5ac3 7fec8fc1
Loading
Loading
Loading
Loading
+17 −17
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@ 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. */
@@ -39,8 +37,9 @@ public class GestureSandboxActivity extends FragmentActivity {
    private static final String LOG_TAG = "GestureSandboxActivity";

    private static final String KEY_TUTORIAL_STEPS = "tutorial_steps";
    private static final String KEY_CURRENT_STEP = "current_step";

    private Deque<TutorialType> mTutorialSteps;
    private TutorialType[] mTutorialSteps;
    private TutorialType mCurrentTutorialStep;
    private TutorialFragment mFragment;

@@ -55,9 +54,7 @@ public class GestureSandboxActivity extends FragmentActivity {

        Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
        mTutorialSteps = getTutorialSteps(args);
        mCurrentStep = 1;
        mNumSteps = mTutorialSteps.size();
        mCurrentTutorialStep = mTutorialSteps.pop();
        mCurrentTutorialStep = mTutorialSteps[mCurrentStep - 1];
        mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.gesture_tutorial_fragment_container, mFragment)
@@ -88,12 +85,13 @@ public class GestureSandboxActivity extends FragmentActivity {
    @Override
    protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
        savedInstanceState.putStringArray(KEY_TUTORIAL_STEPS, getTutorialStepNames());
        savedInstanceState.putInt(KEY_CURRENT_STEP, mCurrentStep);
        super.onSaveInstanceState(savedInstanceState);
    }

    /** Returns true iff there aren't anymore tutorial types to display to the user. */
    public boolean isTutorialComplete() {
        return mTutorialSteps.isEmpty();
        return mCurrentStep >= mNumSteps;
    }

    public int getCurrentStep() {
@@ -121,7 +119,7 @@ public class GestureSandboxActivity extends FragmentActivity {
            mFragment.closeTutorial();
            return;
        }
        mCurrentTutorialStep = mTutorialSteps.pop();
        mCurrentTutorialStep = mTutorialSteps[mCurrentStep];
        mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
        getSupportFragmentManager().beginTransaction()
            .replace(R.id.gesture_tutorial_fragment_container, mFragment)
@@ -131,10 +129,9 @@ public class GestureSandboxActivity extends FragmentActivity {
    }

    private String[] getTutorialStepNames() {
        String[] tutorialStepNames = new String[mTutorialSteps.size() + 1];
        String[] tutorialStepNames = new String[mTutorialSteps.length];

        int i = 1;
        tutorialStepNames[0] = mCurrentTutorialStep.name();
        int i = 0;
        for (TutorialType tutorialStep : mTutorialSteps) {
            tutorialStepNames[i++] = tutorialStep.name();
        }
@@ -142,25 +139,28 @@ public class GestureSandboxActivity extends FragmentActivity {
        return tutorialStepNames;
    }

    private Deque<TutorialType> getTutorialSteps(Bundle extras) {
        Deque<TutorialType> defaultSteps = new ArrayDeque<>();
        defaultSteps.push(TutorialType.RIGHT_EDGE_BACK_NAVIGATION);
    private TutorialType[] getTutorialSteps(Bundle extras) {
        TutorialType[] defaultSteps = new TutorialType[] {TutorialType.LEFT_EDGE_BACK_NAVIGATION};

        if (extras == null || !extras.containsKey(KEY_TUTORIAL_STEPS)) {
            return defaultSteps;
        }

        String[] tutorialStepNames = extras.getStringArray(KEY_TUTORIAL_STEPS);
        int currentStep = extras.getInt(KEY_CURRENT_STEP, -1);

        if (tutorialStepNames == null) {
            return defaultSteps;
        }

        Deque<TutorialType> tutorialSteps = new ArrayDeque<>();
        for (String tutorialStepName : tutorialStepNames) {
            tutorialSteps.addLast(TutorialType.valueOf(tutorialStepName));
        TutorialType[] tutorialSteps = new TutorialType[tutorialStepNames.length];
        for (int i = 0; i < tutorialStepNames.length; i++) {
            tutorialSteps[i] = TutorialType.valueOf(tutorialStepNames[i]);
        }

        mCurrentStep = Math.max(currentStep, 1);
        mNumSteps = tutorialSteps.length;

        return tutorialSteps;
    }

+50 −18
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,

    private static final int FEEDBACK_ANIMATION_MS = 250;
    private static final int RIPPLE_VISIBLE_MS = 300;
    private static final int GESTURE_ANIMATION_DELAY_MS = 1500;

    final TutorialFragment mTutorialFragment;
    TutorialType mTutorialType;
@@ -65,6 +66,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,

    final TextView mCloseButton;
    final ViewGroup mFeedbackView;
    final TextView mFeedbackTitleView;
    final ImageView mFeedbackVideoView;
    final ImageView mGestureVideoView;
    final RelativeLayout mFakeLauncherView;
@@ -80,6 +82,12 @@ abstract class TutorialController implements BackGestureAttemptCallback,

    protected boolean mGestureCompleted = false;

    // These runnables  should be used when posting callbacks to their views and cleared from their
    // views before posting new callbacks.
    private final Runnable mTitleViewCallback;
    @Nullable private Runnable mFeedbackViewCallback;
    @Nullable private Runnable mFeedbackVideoViewCallback;

    TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
        mTutorialFragment = tutorialFragment;
        mTutorialType = tutorialType;
@@ -89,6 +97,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
        mCloseButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button);
        mCloseButton.setOnClickListener(button -> showSkipTutorialDialog());
        mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
        mFeedbackTitleView = mFeedbackView.findViewById(
                R.id.gesture_tutorial_fragment_feedback_title);
        mFeedbackVideoView = rootView.findViewById(R.id.gesture_tutorial_feedback_video);
        mGestureVideoView = rootView.findViewById(R.id.gesture_tutorial_gesture_video);
        mFakeLauncherView = rootView.findViewById(R.id.gesture_tutorial_fake_launcher_view);
@@ -103,6 +113,9 @@ abstract class TutorialController implements BackGestureAttemptCallback,
        mTutorialStepView =
                rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
        mSkipTutorialDialog = createSkipTutorialDialog();

        mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
                AccessibilityEvent.TYPE_VIEW_FOCUSED);
    }

    private void showSkipTutorialDialog() {
@@ -169,7 +182,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
            playFeedbackVideo(tutorialAnimation, gestureAnimation, () -> {
                mFeedbackView.setTranslationY(0);
                title.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
            });
            }, true);
        }
    }

@@ -192,15 +205,17 @@ abstract class TutorialController implements BackGestureAttemptCallback,
                isGestureSuccessful
                        ? R.string.gesture_tutorial_nice : R.string.gesture_tutorial_try_again,
                subtitleResId,
                isGestureSuccessful);
                isGestureSuccessful,
                false);
    }

    void showFeedback(
            int titleResId,
            int subtitleResId,
            boolean isGestureSuccessful) {
        TextView title = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_title);
        title.setText(titleResId);
            boolean isGestureSuccessful,
            boolean useGestureAnimationDelay) {
        mFeedbackTitleView.setText(titleResId);
        mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
        TextView subtitle =
                mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
        subtitle.setText(subtitleResId);
@@ -221,11 +236,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
                            .setDuration(FEEDBACK_ANIMATION_MS)
                            .translationY(0)
                            .start();
                    title.postDelayed(
                            () -> title.sendAccessibilityEvent(
                                    AccessibilityEvent.TYPE_VIEW_FOCUSED),
                            FEEDBACK_ANIMATION_MS);
                });
                    mFeedbackTitleView.postDelayed(mTitleViewCallback, FEEDBACK_ANIMATION_MS);
                }, useGestureAnimationDelay);
                return;
            } else {
                mTutorialFragment.releaseFeedbackVideoView();
@@ -237,10 +249,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
                .setDuration(FEEDBACK_ANIMATION_MS)
                .translationY(0)
                .start();
        title.postDelayed(
                () -> title.sendAccessibilityEvent(
                        AccessibilityEvent.TYPE_VIEW_FOCUSED),
                FEEDBACK_ANIMATION_MS);
        mFeedbackTitleView.postDelayed(mTitleViewCallback, FEEDBACK_ANIMATION_MS);
    }

    void hideFeedback(boolean releaseFeedbackVideo) {
@@ -254,7 +263,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
    private void playFeedbackVideo(
            @NonNull AnimatedVectorDrawable tutorialAnimation,
            @NonNull AnimatedVectorDrawable gestureAnimation,
            @NonNull Runnable onStartRunnable) {
            @NonNull Runnable onStartRunnable,
            boolean useGestureAnimationDelay) {

        if (tutorialAnimation.isRunning()) {
            tutorialAnimation.reset();
@@ -270,8 +280,10 @@ abstract class TutorialController implements BackGestureAttemptCallback,
                    gestureAnimation.stop();
                }

                if (!useGestureAnimationDelay) {
                    onStartRunnable.run();
                }
            }

            @Override
            public void onAnimationEnd(Drawable drawable) {
@@ -284,8 +296,28 @@ abstract class TutorialController implements BackGestureAttemptCallback,
            }
        });

        if (mFeedbackViewCallback != null) {
            mFeedbackVideoView.removeCallbacks(mFeedbackViewCallback);
            mFeedbackViewCallback = null;
        }
        if (mFeedbackVideoViewCallback != null) {
            mFeedbackVideoView.removeCallbacks(mFeedbackVideoViewCallback);
            mFeedbackVideoViewCallback = null;
        }
        if (useGestureAnimationDelay) {
            mFeedbackViewCallback = onStartRunnable;
            mFeedbackVideoViewCallback = () -> {
                mFeedbackVideoView.setVisibility(View.VISIBLE);
                tutorialAnimation.start();
            };

            mFeedbackVideoView.setVisibility(View.GONE);
            mFeedbackView.post(mFeedbackViewCallback);
            mFeedbackVideoView.postDelayed(mFeedbackVideoViewCallback, GESTURE_ANIMATION_DELAY_MS);
        } else {
            mFeedbackVideoView.setVisibility(View.VISIBLE);
            tutorialAnimation.start();
        }
    }

    void setRippleHotspot(float x, float y) {
+3 −2
Original line number Diff line number Diff line
@@ -170,7 +170,8 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
            Integer introTileStringResId = mTutorialController.getIntroductionTitle();
            Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
            if (introTileStringResId != null && introSubtitleResId != null) {
                mTutorialController.showFeedback(introTileStringResId, introSubtitleResId, false);
                mTutorialController.showFeedback(
                        introTileStringResId, introSubtitleResId, false, true);
                mIntroductionShown = true;
            }
        }
@@ -252,7 +253,7 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
    @Override
    public void onResume() {
        super.onResume();
        if (mFragmentStopped) {
        if (mFragmentStopped && mTutorialController != null) {
            mTutorialController.showFeedback();
            mFragmentStopped = false;
        } else {
+5 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.graphics.ColorUtils;

import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -86,6 +87,8 @@ public class TutorialStepIndicator extends LinearLayout {
        for (int i = mTotalSteps; i < getChildCount(); i++) {
            removeViewAt(i);
        }
        int stepIndicatorColor = GraphicsUtils.getAttrColor(
                getContext(), android.R.attr.textColorPrimary);
        for (int i = 0; i < mTotalSteps; i++) {
            Drawable pageIndicatorPillDrawable = AppCompatResources.getDrawable(
                    getContext(), R.drawable.tutorial_step_indicator_pill);
@@ -104,13 +107,10 @@ public class TutorialStepIndicator extends LinearLayout {
            }
            if (pageIndicatorPillDrawable != null) {
                if (i < mCurrentStep) {
                    pageIndicatorPillDrawable.setTint(
                            GraphicsUtils.getAttrColor(getContext(),
                                    android.R.attr.textColorPrimary));
                    pageIndicatorPillDrawable.setTint(stepIndicatorColor);
                } else {
                    pageIndicatorPillDrawable.setTint(
                            GraphicsUtils.getAttrColor(getContext(),
                                    android.R.attr.textColorPrimaryInverse));
                            ColorUtils.setAlphaComponent(stepIndicatorColor, 0x22));
                }
            }
        }