diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2019-04-23 14:12:32 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2019-04-29 14:40:41 -0700 |
commit | 4580149897947b46d31d4d1e01deaee40e52b552 (patch) | |
tree | abc591a6ce1076e0a885c18b29f7fc5f328161c5 | |
parent | 34c630bf14828934732e9a3a69e32a615eb02e1d (diff) | |
download | android_packages_apps_Trebuchet-4580149897947b46d31d4d1e01deaee40e52b552.tar.gz android_packages_apps_Trebuchet-4580149897947b46d31d4d1e01deaee40e52b552.tar.bz2 android_packages_apps_Trebuchet-4580149897947b46d31d4d1e01deaee40e52b552.zip |
Adding support for accessibiliy gesture
Bug: 130905838
Change-Id: If796b6e6036c2f216abf87386d8eebcaa6368d02
9 files changed, 307 insertions, 90 deletions
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml index f99143581..61c576e82 100644 --- a/quickstep/recents_ui_overrides/res/values/dimens.xml +++ b/quickstep/recents_ui_overrides/res/values/dimens.xml @@ -21,4 +21,6 @@ <!-- The size of corner radius of the arrow in the arrow toast. --> <dimen name="arrow_toast_corner_radius">2dp</dimen> + <!-- Minimum distance to swipe to trigger accessibility gesture --> + <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen> </resources>
\ No newline at end of file diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AccessibilityInputConsumer.java new file mode 100644 index 000000000..8f8cd18fe --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AccessibilityInputConsumer.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2019 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; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_POINTER_DOWN; +import static android.view.MotionEvent.ACTION_POINTER_UP; +import static android.view.MotionEvent.ACTION_UP; + +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; +import android.view.Display; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +import com.android.launcher3.R; +import com.android.quickstep.util.MotionPauseDetector; +import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.systemui.shared.system.InputMonitorCompat; + +/** + * Touch consumer for two finger swipe actions for accessibility actions + */ +public class AccessibilityInputConsumer extends DelegateInputConsumer { + + private static final String TAG = "A11yInputConsumer"; + + private final ISystemUiProxy mSystemUiProxy; + private final VelocityTracker mVelocityTracker; + private final MotionPauseDetector mMotionPauseDetector; + private final boolean mAllowLongClick; + + private final float mMinGestureDistance; + private final float mMinFlingVelocity; + + private int mActivePointerId = -1; + private float mDownY; + private float mTotalY; + + public AccessibilityInputConsumer(Context context, ISystemUiProxy systemUiProxy, + boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor) { + super(delegate, inputMonitor); + mSystemUiProxy = systemUiProxy; + mVelocityTracker = VelocityTracker.obtain(); + mMinGestureDistance = context.getResources() + .getDimension(R.dimen.accessibility_gesture_min_swipe_distance); + mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity(); + + mMotionPauseDetector = new MotionPauseDetector(context); + mAllowLongClick = allowLongClick; + } + + @Override + public int getType() { + return TYPE_ACCESSIBILITY | mDelegate.getType(); + } + + @Override + public void onMotionEvent(MotionEvent ev) { + if (mState != STATE_DELEGATE_ACTIVE) { + mVelocityTracker.addMovement(ev); + } + + switch (ev.getActionMasked()) { + case ACTION_DOWN: { + break; + } + case ACTION_POINTER_UP: { + if (mState == STATE_ACTIVE) { + int pointerIndex = ev.getActionIndex(); + int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + final int newPointerIdx = pointerIndex == 0 ? 1 : 0; + + mTotalY += (ev.getY(pointerIndex) - mDownY); + mDownY = ev.getY(newPointerIdx); + mActivePointerId = ev.getPointerId(newPointerIdx); + } + } + break; + } + case ACTION_POINTER_DOWN: { + if (mState == STATE_INACTIVE) { + if (mDelegate.allowInterceptByParent()) { + setActive(ev); + + int pointerIndex = ev.getActionIndex(); + mActivePointerId = ev.getPointerId(pointerIndex); + mDownY = ev.getY(pointerIndex); + } else { + mState = STATE_DELEGATE_ACTIVE; + } + } + break; + } + case ACTION_MOVE: { + if (mState == STATE_ACTIVE && mAllowLongClick) { + int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == -1) { + break; + } + + mMotionPauseDetector.addPosition(ev.getY(pointerIndex) - mDownY, + ev.getEventTime()); + } + break; + } + case ACTION_UP: + if (mState == STATE_ACTIVE) { + try { + if (mAllowLongClick && mMotionPauseDetector.isPaused()) { + mSystemUiProxy.notifyAccessibilityButtonLongClicked(); + } else { + mTotalY += (ev.getY() - mDownY); + mVelocityTracker.computeCurrentVelocity(1000); + + if ((-mTotalY) > mMinGestureDistance + || (-mVelocityTracker.getYVelocity()) > mMinFlingVelocity) { + mSystemUiProxy.notifyAccessibilityButtonClicked( + Display.DEFAULT_DISPLAY); + } + } + } catch (RemoteException e) { + Log.e(TAG, "Unable to notify accessibility event", e); + } + } + // Follow through + case ACTION_CANCEL: { + mVelocityTracker.recycle(); + mMotionPauseDetector.clear(); + break; + } + } + + if (mState != STATE_ACTIVE) { + mDelegate.onMotionEvent(ev); + } + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java index 5e7faf727..829e4783d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java @@ -50,20 +50,10 @@ import com.android.systemui.shared.system.QuickStepContract; /** * Touch consumer for handling events to launch assistant from launcher */ -public class AssistantTouchConsumer implements InputConsumer { +public class AssistantTouchConsumer extends DelegateInputConsumer { private static final String TAG = "AssistantTouchConsumer"; private static final long RETRACT_ANIMATION_DURATION_MS = 300; - /* The assistant touch consume competes with quick switch InputConsumer gesture. The delegate - * can be chosen to run if the angle passing the slop is lower than the threshold angle. When - * this occurs, the state changes to {@link #STATE_DELEGATE_ACTIVE} where the next incoming - * motion events are handled by the delegate instead of the assistant touch consumer. If the - * angle is higher than the threshold, the state will change to {@link #STATE_ASSISTANT_ACTIVE}. - */ - private static final int STATE_INACTIVE = 0; - private static final int STATE_ASSISTANT_ACTIVE = 1; - private static final int STATE_DELEGATE_ACTIVE = 2; - private static final String INVOCATION_TYPE_KEY = "invocation_type"; private static final int INVOCATION_TYPE_GESTURE = 1; @@ -78,7 +68,6 @@ public class AssistantTouchConsumer implements InputConsumer { private float mTimeFraction; private long mDragTime; private float mLastProgress; - private int mState; private int mDirection; private ActivityControlHelper mActivityControlHelper; @@ -87,46 +76,25 @@ public class AssistantTouchConsumer implements InputConsumer { private final int mAngleThreshold; private final float mSlop; private final ISystemUiProxy mSysUiProxy; - private final InputConsumer mConsumerDelegate; private final Context mContext; - private final InputMonitorCompat mInputMonitorCompat; - - public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy, - InputConsumer delegate, InputMonitorCompat inputMonitorCompat, - ActivityControlHelper activityControlHelper) { + ActivityControlHelper activityControlHelper, InputConsumer delegate, + InputMonitorCompat inputMonitor) { + super(delegate, inputMonitor); final Resources res = context.getResources(); mContext = context; mSysUiProxy = systemUiProxy; - mConsumerDelegate = delegate; mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold); mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold); mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold); mSlop = QuickStepContract.getQuickStepDragSlopPx(); - mInputMonitorCompat = inputMonitorCompat; mActivityControlHelper = activityControlHelper; - mState = STATE_INACTIVE; } @Override public int getType() { - return TYPE_ASSISTANT; - } - - @Override - public boolean useSharedSwipeState() { - if (mConsumerDelegate != null) { - return mConsumerDelegate.useSharedSwipeState(); - } - return false; - } - - @Override - public void onConsumerAboutToBeSwitched() { - if (mConsumerDelegate != null) { - mConsumerDelegate.onConsumerAboutToBeSwitched(); - } + return TYPE_ASSISTANT | mDelegate.getType(); } @Override @@ -158,6 +126,10 @@ public class AssistantTouchConsumer implements InputConsumer { if (mState == STATE_DELEGATE_ACTIVE) { break; } + if (!mDelegate.allowInterceptByParent()) { + mState = STATE_DELEGATE_ACTIVE; + break; + } int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == -1) { break; @@ -168,9 +140,6 @@ public class AssistantTouchConsumer implements InputConsumer { // Normal gesture, ensure we pass the slop before we start tracking the gesture if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) > mSlop) { - // Cancel touches to other windows (intercept) - mInputMonitorCompat.pilferPointers(); - mPassedSlop = true; mStartDragPos.set(mLastPos.x, mLastPos.y); mDragTime = SystemClock.uptimeMillis(); @@ -182,15 +151,7 @@ public class AssistantTouchConsumer implements InputConsumer { angle = angle > 90 ? 180 - angle : angle; if (angle > mAngleThreshold && angle < 90) { - mState = STATE_ASSISTANT_ACTIVE; - - if (mConsumerDelegate != null) { - // Send cancel event - MotionEvent event = MotionEvent.obtain(ev); - event.setAction(MotionEvent.ACTION_CANCEL); - mConsumerDelegate.onMotionEvent(event); - event.recycle(); - } + setActive(ev); } else { mState = STATE_DELEGATE_ACTIVE; } @@ -232,8 +193,8 @@ public class AssistantTouchConsumer implements InputConsumer { break; } - if (mState != STATE_ASSISTANT_ACTIVE && mConsumerDelegate != null) { - mConsumerDelegate.onMotionEvent(ev); + if (mState != STATE_ACTIVE) { + mDelegate.onMotionEvent(ev); } } @@ -249,7 +210,8 @@ public class AssistantTouchConsumer implements InputConsumer { Bundle args = new Bundle(); args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); - BaseDraggingActivity launcherActivity = mActivityControlHelper.getCreatedActivity(); + BaseDraggingActivity launcherActivity = + mActivityControlHelper.getCreatedActivity(); if (launcherActivity != null) { launcherActivity.getRootView(). performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/DelegateInputConsumer.java new file mode 100644 index 000000000..d36162f8b --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/DelegateInputConsumer.java @@ -0,0 +1,49 @@ +package com.android.quickstep; + +import android.view.MotionEvent; + +import com.android.systemui.shared.system.InputMonitorCompat; + +public abstract class DelegateInputConsumer implements InputConsumer { + + protected static final int STATE_INACTIVE = 0; + protected static final int STATE_ACTIVE = 1; + protected static final int STATE_DELEGATE_ACTIVE = 2; + + protected final InputConsumer mDelegate; + protected final InputMonitorCompat mInputMonitor; + + protected int mState; + + public DelegateInputConsumer(InputConsumer delegate, InputMonitorCompat inputMonitor) { + mDelegate = delegate; + mInputMonitor = inputMonitor; + mState = STATE_INACTIVE; + } + + @Override + public boolean useSharedSwipeState() { + return mDelegate.useSharedSwipeState(); + } + + @Override + public boolean allowInterceptByParent() { + return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE; + } + + @Override + public void onConsumerAboutToBeSwitched() { + mDelegate.onConsumerAboutToBeSwitched(); + } + + protected void setActive(MotionEvent ev) { + mState = STATE_ACTIVE; + mInputMonitor.pilferPointers(); + + // Send cancel event + MotionEvent event = MotionEvent.obtain(ev); + event.setAction(MotionEvent.ACTION_CANCEL); + mDelegate.onMotionEvent(event); + event.recycle(); + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java index e3f9e02a0..37b728871 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/InputConsumer.java @@ -24,11 +24,12 @@ import android.view.MotionEvent; @TargetApi(Build.VERSION_CODES.O) public interface InputConsumer { - int TYPE_NO_OP = 0; - int TYPE_OVERVIEW = 1; - int TYPE_OTHER_ACTIVITY = 2; - int TYPE_ASSISTANT = 3; - int TYPE_DEVICE_LOCKED = 4; + int TYPE_NO_OP = 1 << 0; + int TYPE_OVERVIEW = 1 << 1; + int TYPE_OTHER_ACTIVITY = 1 << 2; + int TYPE_ASSISTANT = 1 << 3; + int TYPE_DEVICE_LOCKED = 1 << 4; + int TYPE_ACCESSIBILITY = 1 << 5; InputConsumer NO_OP = () -> TYPE_NO_OP; @@ -39,6 +40,13 @@ public interface InputConsumer { } /** + * Returns true if the user has crossed the threshold for it to be an explicit action. + */ + default boolean allowInterceptByParent() { + return true; + } + + /** * Called by the event queue when the consumer is about to be switched to a new consumer. */ default void onConsumerAboutToBeSwitched() { } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java index 5dc641fbe..507535ef9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java @@ -21,6 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.INVALID_POINTER_ID; + import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; @@ -345,18 +346,21 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC */ private void finishTouchTracking(MotionEvent ev) { if (mPassedDragSlop && mInteractionHandler != null) { - - mVelocityTracker.computeCurrentVelocity(1000, - ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); - float velocityX = mVelocityTracker.getXVelocity(mActivePointerId); - float velocityY = mVelocityTracker.getYVelocity(mActivePointerId); - float velocity = isNavBarOnRight() ? velocityX - : isNavBarOnLeft() ? -velocityX - : velocityY; - - mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); - mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY), - mDownPos); + if (ev.getActionMasked() == ACTION_CANCEL) { + mInteractionHandler.onGestureCancelled(); + } else { + mVelocityTracker.computeCurrentVelocity(1000, + ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); + float velocityX = mVelocityTracker.getXVelocity(mActivePointerId); + float velocityY = mVelocityTracker.getYVelocity(mActivePointerId); + float velocity = isNavBarOnRight() ? velocityX + : isNavBarOnLeft() ? -velocityX + : velocityY; + + mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); + mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY), + mDownPos); + } } else { // Since we start touch tracking on DOWN, we may reach this state without actually // starting the gesture. In that case, just cleanup immediately. @@ -387,7 +391,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mSwipeSharedState.canGestureBeContinued = endTarget != null && endTarget.canBeContinued; mSwipeSharedState.goingToLauncher = endTarget != null && endTarget.isLauncher; if (mSwipeSharedState.canGestureBeContinued) { - mInteractionHandler.cancel(); + mInteractionHandler.cancelCurrentAnimation(); } else { mInteractionHandler.reset(); } @@ -425,4 +429,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public boolean useSharedSwipeState() { return mInteractionHandler != null; } + + @Override + public boolean allowInterceptByParent() { + return !mPassedTouchSlop; + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java index 32e0e48a4..b48e3de85 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java @@ -65,6 +65,11 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity> } @Override + public boolean allowInterceptByParent() { + return !mTargetHandledTouch; + } + + @Override public void onMotionEvent(MotionEvent ev) { if (!mProxyTouch) { return; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index b62bac66d..c91bb1b4d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -20,6 +20,8 @@ import static android.view.MotionEvent.ACTION_DOWN; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; @@ -67,9 +69,8 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; - -import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -456,25 +457,32 @@ public class TouchInteractionService extends Service implements final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); + InputConsumer base; if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) { - return InputConsumer.NO_OP; - } else if (mAssistantAvailable - && SysUINavigationMode.INSTANCE.get(this).getMode() == Mode.NO_BUTTON - && AssistantTouchConsumer.withinTouchRegion(this, event)) { - - boolean addDelegate = !activityControl.isResumed(); - return new AssistantTouchConsumer(this, mISystemUiProxy, addDelegate ? - createOtherActivityInputConsumer(event, runningTaskInfo) : null, - mInputMonitorCompat, activityControl); - + base = InputConsumer.NO_OP; } else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) { - return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); + base = OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) { - return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); + base = OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); } else { - return createOtherActivityInputConsumer(event, runningTaskInfo); + base = createOtherActivityInputConsumer(event, runningTaskInfo); } + + if (mMode == Mode.NO_BUTTON) { + if (mAssistantAvailable && AssistantTouchConsumer.withinTouchRegion(this, event)) { + base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base, + mInputMonitorCompat); + } + + if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) { + base = new AccessibilityInputConsumer(this, mISystemUiProxy, + (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, + mInputMonitorCompat); + } + } + + return base; } private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 4df1b151a..6cf3dc12e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -769,6 +769,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> } /** + * Called as a result on ACTION_CANCEL to return the UI to the start state. + */ + @UiThread + public void onGestureCancelled() { + updateDisplacement(0); + setStateOnUiThread(STATE_GESTURE_COMPLETED); + mLogAction = Touch.SWIPE_NOOP; + handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */); + } + + /** * @param endVelocity The velocity in the direction of the nav bar to the middle of the screen. * @param velocity The x and y components of the velocity when the gesture ends. * @param downPos The x and y value of where the gesture started. @@ -788,7 +799,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT; } mDownPos = downPos; - handleNormalGestureEnd(endVelocity, isFling, velocity); + handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */); } @UiThread @@ -806,7 +817,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> } @UiThread - private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity) { + private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity, + boolean isCancel) { PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000); long duration = MAX_SWIPE_DURATION; float currentShift = mCurrentShift.value; @@ -824,7 +836,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> } final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW; if (!isFling) { - if (mMode == Mode.NO_BUTTON) { + if (isCancel) { + endTarget = LAST_TASK; + } else if (mMode == Mode.NO_BUTTON) { if (mIsShelfPeeking) { endTarget = RECENTS; } else if (goingToNewTask) { @@ -907,7 +921,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> private void doLogGesture(GestureEndTarget endTarget) { DeviceProfile dp = mDp; - if (dp == null) { + if (dp == null || mDownPos == null) { // We probably never received an animation controller, skip logging. return; } @@ -1106,7 +1120,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> setStateOnUiThread(STATE_HANDLER_INVALIDATED); } - public void cancel() { + /** + * Cancels any running animation so that the active target can be overriden by a new swipe + * handle (in case of quick switch). + */ + public void cancelCurrentAnimation() { mCurrentShift.cancelAnimation(); if (mLauncherTransitionController != null && mLauncherTransitionController .getAnimationPlayer().isStarted()) { |