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 Original line Diff line number Diff line
@@ -29,8 +29,6 @@ import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.R;
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import com.android.quickstep.interaction.TutorialController.TutorialType;


import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.List;


/** Shows the gesture interactive sandbox in full screen mode. */
/** 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 LOG_TAG = "GestureSandboxActivity";


    private static final String KEY_TUTORIAL_STEPS = "tutorial_steps";
    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 TutorialType mCurrentTutorialStep;
    private TutorialFragment mFragment;
    private TutorialFragment mFragment;


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


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


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


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


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


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


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


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


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


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


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


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

        return tutorialSteps;
        return tutorialSteps;
    }
    }


+50 −18
Original line number Original line 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 FEEDBACK_ANIMATION_MS = 250;
    private static final int RIPPLE_VISIBLE_MS = 300;
    private static final int RIPPLE_VISIBLE_MS = 300;
    private static final int GESTURE_ANIMATION_DELAY_MS = 1500;


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


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


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

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


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


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


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


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


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


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


            @Override
            @Override
            public void onAnimationEnd(Drawable drawable) {
            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();
                tutorialAnimation.start();
            };

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


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


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


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