From 1a5795d1fe435c4fe58ff8a3e25be1437e53d404 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Fri, 29 May 2020 14:00:39 -0700 Subject: [PATCH] Adds Assistant Sandbox tutorial. Demo: https://drive.google.com/open?id=1onivF9qKdgJeUG2ROkQBxcgi-l0VfC4f Fixes: 157824552 Change-Id: Ia0e5f46b39e3f06feed2f7e175ab7861e9d51a96 --- quickstep/res/values/strings.xml | 11 + .../AssistantGestureTutorialController.java | 129 ++++++++++ .../AssistantGestureTutorialFragment.java | 48 ++++ .../BackGestureTutorialController.java | 5 - .../interaction/NavBarGestureHandler.java | 224 ++++++++++++++++-- .../interaction/TutorialController.java | 7 +- .../interaction/TutorialFragment.java | 3 + .../settings/DeveloperOptionsFragment.java | 9 + 8 files changed, 403 insertions(+), 33 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java create mode 100644 quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index 77345a0468..39a2a32043 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -132,6 +132,17 @@ Make sure you swipe straight up and pause + + Tutorial: Assistant + + Try swiping diagonally from a bottom corner of the screen + + Make sure you swipe from a bottom corner of the screen + + Make sure you swipe diagonally + + Try swiping further + All set diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java new file mode 100644 index 0000000000..6862f071bc --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.interaction; + +import static com.android.quickstep.interaction.TutorialController.TutorialType.ASSISTANT_COMPLETE; + +import android.graphics.PointF; +import android.view.View; + +import com.android.launcher3.R; +import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; +import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; + +/** A {@link TutorialController} for the Assistant tutorial. */ +final class AssistantGestureTutorialController extends TutorialController { + + AssistantGestureTutorialController(AssistantGestureTutorialFragment fragment, + TutorialType tutorialType) { + super(fragment, tutorialType); + } + + @Override + Integer getTitleStringId() { + switch (mTutorialType) { + case ASSISTANT: + return R.string.assistant_gesture_tutorial_playground_title; + case ASSISTANT_COMPLETE: + return R.string.gesture_tutorial_confirm_title; + } + return null; + } + + @Override + Integer getSubtitleStringId() { + if (mTutorialType == TutorialType.ASSISTANT) { + return R.string.assistant_gesture_tutorial_playground_subtitle; + } + return null; + } + + @Override + Integer getActionButtonStringId() { + if (mTutorialType == ASSISTANT_COMPLETE) { + return R.string.gesture_tutorial_action_button_label_done; + } + return null; + } + + @Override + void onActionButtonClicked(View button) { + mTutorialFragment.closeTutorial(); + } + + @Override + public void onBackGestureAttempted(BackGestureResult result) { + switch (mTutorialType) { + case ASSISTANT: + switch (result) { + case BACK_COMPLETED_FROM_LEFT: + case BACK_COMPLETED_FROM_RIGHT: + case BACK_CANCELLED_FROM_LEFT: + case BACK_CANCELLED_FROM_RIGHT: + showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner); + break; + } + break; + case ASSISTANT_COMPLETE: + if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT + || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) { + mTutorialFragment.closeTutorial(); + } + break; + } + } + + + @Override + public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) { + switch (mTutorialType) { + case ASSISTANT: + switch (result) { + case HOME_GESTURE_COMPLETED: + case OVERVIEW_GESTURE_COMPLETED: + case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE: + case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE: + case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: + case HOME_OR_OVERVIEW_CANCELLED: + showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner); + break; + case ASSISTANT_COMPLETED: + hideFeedback(); + hideHandCoachingAnimation(); + showRippleEffect( + () -> mTutorialFragment.changeController(ASSISTANT_COMPLETE)); + break; + case ASSISTANT_NOT_STARTED_BAD_ANGLE: + showFeedback(R.string.assistant_gesture_feedback_swipe_not_diagonal); + break; + case ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT: + showFeedback(R.string.assistant_gesture_feedback_swipe_not_long_enough); + break; + } + break; + case ASSISTANT_COMPLETE: + if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) { + mTutorialFragment.closeTutorial(); + } + break; + } + } + + @Override + public void setAssistantProgress(float progress) { + // TODO: Create an animation. + } +} diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java new file mode 100644 index 0000000000..70181fb9ca --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.interaction; + +import android.view.MotionEvent; +import android.view.View; + +import com.android.launcher3.R; +import com.android.quickstep.interaction.TutorialController.TutorialType; + +/** Shows the Home gesture interactive tutorial. */ +public class AssistantGestureTutorialFragment extends TutorialFragment { + @Override + int getHandAnimationResId() { + return R.drawable.assistant_gesture; + } + + @Override + TutorialController createController(TutorialType type) { + return new AssistantGestureTutorialController(this, type); + } + + @Override + Class getControllerClass() { + return AssistantGestureTutorialController.class; + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) { + mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY()); + } + return super.onTouch(view, motionEvent); + } +} diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java index 1f398fc5ea..921e5681c6 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java @@ -21,8 +21,6 @@ import static com.android.quickstep.interaction.TutorialController.TutorialType. import android.graphics.PointF; import android.view.View; -import androidx.annotation.Nullable; - import com.android.launcher3.R; import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; @@ -156,7 +154,4 @@ final class BackGestureTutorialController extends TutorialController { } } } - - @Override - public void setNavBarGestureProgress(@Nullable Float displacement) {} } diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java index 4069c09a28..0e2312bddf 100644 --- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java @@ -15,6 +15,10 @@ */ package com.android.quickstep.interaction; +import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_COMPLETED; +import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_BAD_ANGLE; +import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_GESTURE_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_NOT_STARTED_TOO_FAR_FROM_EDGE; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_CANCELLED; @@ -22,38 +26,69 @@ import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestu import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; +import android.graphics.RectF; +import android.os.SystemClock; import android.view.Display; +import android.view.GestureDetector; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.View.OnTouchListener; +import android.view.ViewConfiguration; import androidx.annotation.Nullable; +import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.TriggerSwipeUpTouchTracker; +import com.android.systemui.shared.system.QuickStepContract; -/** Utility class to handle home gestures. */ +/** Utility class to handle Home and Assistant gestures. */ public class NavBarGestureHandler implements OnTouchListener, TriggerSwipeUpTouchTracker.OnSwipeUpListener { private static final String LOG_TAG = "NavBarGestureHandler"; + private static final long RETRACT_GESTURE_ANIMATION_DURATION_MS = 300; + private final Context mContext; private final Point mDisplaySize = new Point(); private final TriggerSwipeUpTouchTracker mSwipeUpTouchTracker; - private int mBottomGestureHeight; + private final int mBottomGestureHeight; + private final GestureDetector mAssistantGestureDetector; + private final int mAssistantAngleThreshold; + private final RectF mAssistantLeftRegion = new RectF(); + private final RectF mAssistantRightRegion = new RectF(); + private final float mAssistantDragDistThreshold; + private final float mAssistantFlingDistThreshold; + private final long mAssistantTimeThreshold; + private final float mAssistantSquaredSlop; + private final PointF mAssistantStartDragPos = new PointF(); + private final PointF mDownPos = new PointF(); + private final PointF mLastPos = new PointF(); + private boolean mTouchCameFromAssistantCorner; private boolean mTouchCameFromNavBar; - private float mDownY; + private boolean mPassedAssistantSlop; + private boolean mAssistantGestureActive; + private boolean mLaunchedAssistant; + private long mAssistantDragStartTime; + private float mAssistantDistance; + private float mAssistantTimeFraction; + private float mAssistantLastProgress; + @Nullable private NavBarGestureAttemptCallback mGestureCallback; NavBarGestureHandler(Context context) { - final Display display = context.getDisplay(); + mContext = context; + final Display display = mContext.getDisplay(); final int displayRotation; if (display == null) { displayRotation = Surface.ROTATION_0; @@ -61,7 +96,6 @@ public class NavBarGestureHandler implements OnTouchListener, displayRotation = display.getRotation(); display.getRealSize(mDisplaySize); } - mDownY = mDisplaySize.y; mSwipeUpTouchTracker = new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/, new NavBarPosition(Mode.NO_BUTTON, displayRotation), @@ -70,6 +104,27 @@ public class NavBarGestureHandler implements OnTouchListener, final Resources resources = context.getResources(); mBottomGestureHeight = ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, resources); + mAssistantDragDistThreshold = + resources.getDimension(R.dimen.gestures_assistant_drag_threshold); + mAssistantFlingDistThreshold = + resources.getDimension(R.dimen.gestures_assistant_fling_threshold); + mAssistantTimeThreshold = + resources.getInteger(R.integer.assistant_gesture_min_time_threshold); + mAssistantAngleThreshold = + resources.getInteger(R.integer.assistant_gesture_corner_deg_threshold); + + mAssistantGestureDetector = new GestureDetector(context, new AssistantGestureListener()); + int assistantWidth = resources.getDimensionPixelSize(R.dimen.gestures_assistant_width); + final float assistantHeight = Math.max(mBottomGestureHeight, + QuickStepContract.getWindowCornerRadius(resources)); + mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mDisplaySize.y; + mAssistantLeftRegion.top = mAssistantRightRegion.top = mDisplaySize.y - assistantHeight; + mAssistantLeftRegion.left = 0; + mAssistantLeftRegion.right = assistantWidth; + mAssistantRightRegion.right = mDisplaySize.x; + mAssistantRightRegion.left = mDisplaySize.x - assistantWidth; + float slop = ViewConfiguration.get(context).getScaledTouchSlop(); + mAssistantSquaredSlop = slop * slop; } void registerNavBarGestureAttemptCallback(NavBarGestureAttemptCallback callback) { @@ -82,7 +137,7 @@ public class NavBarGestureHandler implements OnTouchListener, @Override public void onSwipeUp(boolean wasFling, PointF finalVelocity) { - if (mGestureCallback == null) { + if (mGestureCallback == null || mAssistantGestureActive) { return; } finalVelocity.set(finalVelocity.x / 1000, finalVelocity.y / 1000); @@ -98,36 +153,128 @@ public class NavBarGestureHandler implements OnTouchListener, @Override public void onSwipeUpCancelled() { - if (mGestureCallback != null) { + if (mGestureCallback != null && !mAssistantGestureActive) { mGestureCallback.onNavBarGestureAttempted(HOME_OR_OVERVIEW_CANCELLED, new PointF()); } } @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - int action = motionEvent.getAction(); + public boolean onTouch(View view, MotionEvent event) { + int action = event.getAction(); boolean intercepted = mSwipeUpTouchTracker.interceptedTouch(); - if (action == MotionEvent.ACTION_DOWN) { - mDownY = motionEvent.getY(); - mTouchCameFromNavBar = mDownY >= mDisplaySize.y - mBottomGestureHeight; - if (!mTouchCameFromNavBar) { - mGestureCallback.setNavBarGestureProgress(null); - } - mSwipeUpTouchTracker.init(); - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) { - mGestureCallback.onNavBarGestureAttempted( - HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF()); - intercepted = true; - } + switch (action) { + case MotionEvent.ACTION_DOWN: + mDownPos.set(event.getX(), event.getY()); + mLastPos.set(mDownPos); + mTouchCameFromAssistantCorner = + mAssistantLeftRegion.contains(event.getX(), event.getY()) + || mAssistantRightRegion.contains(event.getX(), event.getY()); + mAssistantGestureActive = mTouchCameFromAssistantCorner; + mTouchCameFromNavBar = !mTouchCameFromAssistantCorner + && mDownPos.y >= mDisplaySize.y - mBottomGestureHeight; + if (!mTouchCameFromNavBar && mGestureCallback != null) { + mGestureCallback.setNavBarGestureProgress(null); + } + mLaunchedAssistant = false; + mSwipeUpTouchTracker.init(); + break; + case MotionEvent.ACTION_MOVE: + if (!mAssistantGestureActive) { + break; + } + mLastPos.set(event.getX(), event.getY()); + + if (!mPassedAssistantSlop) { + // Normal gesture, ensure we pass the slop before we start tracking the gesture + if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) + > mAssistantSquaredSlop) { + + mPassedAssistantSlop = true; + mAssistantStartDragPos.set(mLastPos.x, mLastPos.y); + mAssistantDragStartTime = SystemClock.uptimeMillis(); + + mAssistantGestureActive = isValidAssistantGestureAngle( + mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y); + if (!mAssistantGestureActive && mGestureCallback != null) { + mGestureCallback.onNavBarGestureAttempted( + ASSISTANT_NOT_STARTED_BAD_ANGLE, new PointF()); + } + } + } else { + // Movement + mAssistantDistance = (float) Math.hypot(mLastPos.x - mAssistantStartDragPos.x, + mLastPos.y - mAssistantStartDragPos.y); + if (mAssistantDistance >= 0) { + final long diff = SystemClock.uptimeMillis() - mAssistantDragStartTime; + mAssistantTimeFraction = Math.min(diff * 1f / mAssistantTimeThreshold, 1); + updateAssistantProgress(); + } + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) { + mGestureCallback.onNavBarGestureAttempted( + HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF()); + intercepted = true; + break; + } + if (mAssistantGestureActive && !mLaunchedAssistant && mGestureCallback != null) { + mGestureCallback.onNavBarGestureAttempted( + ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT, new PointF()); + ValueAnimator animator = ValueAnimator.ofFloat(mAssistantLastProgress, 0) + .setDuration(RETRACT_GESTURE_ANIMATION_DURATION_MS); + animator.addUpdateListener(valueAnimator -> { + float progress = (float) valueAnimator.getAnimatedValue(); + mGestureCallback.setAssistantProgress(progress); + }); + animator.setInterpolator(Interpolators.DEACCEL_2); + animator.start(); + } + mPassedAssistantSlop = false; + break; } if (mTouchCameFromNavBar && mGestureCallback != null) { - mGestureCallback.setNavBarGestureProgress(motionEvent.getY() - mDownY); + mGestureCallback.setNavBarGestureProgress(event.getY() - mDownPos.y); } - mSwipeUpTouchTracker.onMotionEvent(motionEvent); + mSwipeUpTouchTracker.onMotionEvent(event); + mAssistantGestureDetector.onTouchEvent(event); return intercepted; } + /** + * Determine if angle is larger than threshold for assistant detection + */ + private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) { + float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX)); + + // normalize so that angle is measured clockwise from horizontal in the bottom right corner + // and counterclockwise from horizontal in the bottom left corner + angle = angle > 90 ? 180 - angle : angle; + return (angle > mAssistantAngleThreshold && angle < 90); + } + + private void updateAssistantProgress() { + if (!mLaunchedAssistant) { + mAssistantLastProgress = + Math.min(mAssistantDistance * 1f / mAssistantDragDistThreshold, 1) + * mAssistantTimeFraction; + if (mAssistantDistance >= mAssistantDragDistThreshold && mAssistantTimeFraction >= 1) { + startAssistant(new PointF()); + } else if (mGestureCallback != null) { + mGestureCallback.setAssistantProgress(mAssistantLastProgress); + } + } + } + + private void startAssistant(PointF velocity) { + if (mGestureCallback != null) { + mGestureCallback.onNavBarGestureAttempted(ASSISTANT_COMPLETED, velocity); + } + VibratorWrapper.INSTANCE.get(mContext).vibrate(VibratorWrapper.EFFECT_CLICK); + mLaunchedAssistant = true; + } + enum NavBarGestureResult { UNKNOWN, HOME_GESTURE_COMPLETED, @@ -135,7 +282,10 @@ public class NavBarGestureHandler implements OnTouchListener, HOME_NOT_STARTED_TOO_FAR_FROM_EDGE, OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE, HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, // Side swipe on nav bar. - HOME_OR_OVERVIEW_CANCELLED + HOME_OR_OVERVIEW_CANCELLED, + ASSISTANT_COMPLETED, + ASSISTANT_NOT_STARTED_BAD_ANGLE, + ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT, } /** Callback to let the UI react to attempted nav bar gestures. */ @@ -144,6 +294,28 @@ public class NavBarGestureHandler implements OnTouchListener, void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity); /** Indicates how far a touch originating in the nav bar has moved from the nav bar. */ - void setNavBarGestureProgress(@Nullable Float displacement); + default void setNavBarGestureProgress(@Nullable Float displacement) {} + + /** Indicates the progress of an Assistant gesture. */ + default void setAssistantProgress(float progress) {} + } + + private class AssistantGestureListener extends GestureDetector.SimpleOnGestureListener { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (!mLaunchedAssistant && mTouchCameFromAssistantCorner) { + PointF velocity = new PointF(velocityX, velocityY); + if (!isValidAssistantGestureAngle(velocityX, -velocityY)) { + if (mGestureCallback != null) { + mGestureCallback.onNavBarGestureAttempted(ASSISTANT_NOT_STARTED_BAD_ANGLE, + velocity); + } + } else if (mAssistantDistance >= mAssistantFlingDistThreshold) { + mAssistantLastProgress = 1; + startAssistant(velocity); + } + } + return true; + } } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 511c8b6dc6..c1918c2326 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -202,7 +202,8 @@ abstract class TutorialController implements BackGestureAttemptCallback, private boolean isComplete() { return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE || mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE - || mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE; + || mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE + || mTutorialType == TutorialType.ASSISTANT_COMPLETE; } /** Denotes the type of the tutorial. */ @@ -213,6 +214,8 @@ abstract class TutorialController implements BackGestureAttemptCallback, HOME_NAVIGATION, HOME_NAVIGATION_COMPLETE, OVERVIEW_NAVIGATION, - OVERVIEW_NAVIGATION_COMPLETE + OVERVIEW_NAVIGATION_COMPLETE, + ASSISTANT, + ASSISTANT_COMPLETE } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index da6815d776..9a8264d098 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -71,6 +71,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { case OVERVIEW_NAVIGATION: case OVERVIEW_NAVIGATION_COMPLETE: return new OverviewGestureTutorialFragment(); + case ASSISTANT: + case ASSISTANT_COMPLETE: + return new AssistantGestureTutorialFragment(); default: Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name()); } diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java index e80ee2cfe9..b12d04f610 100644 --- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java +++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java @@ -246,6 +246,15 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { return true; }); sandboxCategory.addPreference(launchOverviewTutorialPreference); + Preference launchAssistantTutorialPreference = new Preference(context); + launchAssistantTutorialPreference.setKey("launchAssistantTutorial"); + launchAssistantTutorialPreference.setTitle("Launch Assistant Tutorial"); + launchAssistantTutorialPreference.setSummary("Learn how to use the Assistant gesture"); + launchAssistantTutorialPreference.setOnPreferenceClickListener(preference -> { + startActivity(launchSandboxIntent.putExtra("tutorial_type", "ASSISTANT")); + return true; + }); + sandboxCategory.addPreference(launchAssistantTutorialPreference); } private String toName(String action) {