mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 03:08:19 +00:00
Merge "Polish the gesture navigation tutorial sandbox" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
cfa0baeca6
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +280,9 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
gestureAnimation.stop();
|
||||
}
|
||||
|
||||
onStartRunnable.run();
|
||||
if (!useGestureAnimationDelay) {
|
||||
onStartRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,8 +296,28 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
}
|
||||
});
|
||||
|
||||
tutorialAnimation.start();
|
||||
mFeedbackVideoView.setVisibility(View.VISIBLE);
|
||||
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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user