Adds Assistant Sandbox tutorial.
Demo: https://drive.google.com/open?id=1onivF9qKdgJeUG2ROkQBxcgi-l0VfC4f
Fixes: 157824552
Change-Id: Ia0e5f46b39e3f06feed2f7e175ab7861e9d51a96
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 77345a0..39a2a32 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -132,6 +132,17 @@
<!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
<string name="overview_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up and pause</string>
+ <!-- Title shown during interactive part of Assistant gesture tutorial. [CHAR LIMIT=30] -->
+ <string name="assistant_gesture_tutorial_playground_title" translatable="false">Tutorial: Assistant</string>
+ <!-- Subtitle shown during interactive parts of Assistant gesture tutorial. [CHAR LIMIT=60] -->
+ <string name="assistant_gesture_tutorial_playground_subtitle" translatable="false">Try swiping diagonally from a bottom corner of the screen</string>
+ <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture is started too far from the corner. [CHAR LIMIT=100] -->
+ <string name="assistant_gesture_feedback_swipe_too_far_from_corner" translatable="false">Make sure you swipe from a bottom corner of the screen</string>
+ <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go diagonally enough. [CHAR LIMIT=100] -->
+ <string name="assistant_gesture_feedback_swipe_not_diagonal" translatable="false">Make sure you swipe diagonally</string>
+ <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
+ <string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
+
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
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 0000000..6862f07
--- /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 0000000..70181fb
--- /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<? extends TutorialController> 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 1f398fc..921e568 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -21,8 +21,6 @@
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 @@
}
}
}
-
- @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 4069c09..0e2312b 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.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 @@
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 @@
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 @@
@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 @@
@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 @@
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 @@
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 511c8b6..c1918c2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -202,7 +202,8 @@
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 @@
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 da6815d..9a8264d 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -71,6 +71,9 @@
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());
}