From 0232d29e7bfad353330f3ce9e935f6cb019dce96 Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Tue, 22 Jan 2019 14:40:48 +0800 Subject: [PATCH] Fix delay when multi-tap out of distance slop. Triple tap gesture didn't consider the case when user tap quickly and out of distance slop. Just send out all delay motion events if we detect a tap with out of the distance slop. Bug: 122623669 Test: atest MagnificationGestureHandlerTest Change-Id: Iadd05441e10f720f57297b6091f4acff5d198b7c --- .../MagnificationGestureHandler.java | 29 ++++++++++++++ .../MagnificationGestureHandlerTest.java | 39 +++++++++++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java index 80049e80e1a98..b42ae50db2d07 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java @@ -667,6 +667,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { // 3tap and hold afterLongTapTimeoutTransitionToDraggingState(event); + } else if (isTapOutOfDistanceSlop()) { + + transitionToDelegatingStateAndClear(); + } else if (mDetectTripleTap // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay // to ensure reachability of @@ -906,6 +910,31 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { mShortcutTriggered = state; mMagnificationController.setForceShowMagnifiableBounds(state); } + + /** + * Detects if last action down is out of distance slop between with previous + * one, when triple tap is enabled. + * + * @return true if tap is out of distance slop + */ + boolean isTapOutOfDistanceSlop() { + if (!mDetectTripleTap) return false; + if (mPreLastDown == null || mLastDown == null) { + return false; + } + final boolean outOfDistanceSlop = + GestureUtils.distance(mPreLastDown, mLastDown) > mMultiTapMaxDistance; + if (tapCount() > 0) { + return outOfDistanceSlop; + } + // There's no tap in the queue here. We still need to check if this is the case that + // user tap screen quickly and out of distance slop. + if (outOfDistanceSlop + && !GestureUtils.isTimedOut(mPreLastDown, mLastDown, mMultiTapMaxDelay)) { + return true; + } + return false; + } } private void zoomOn(float centerX, float centerY) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java index 032074a7e398d..da1ff048e4d27 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java @@ -302,6 +302,24 @@ public class MagnificationGestureHandlerTest { assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED); } + @Test + public void testMultiTap_outOfDistanceSlop_shouldInIdle() { + // All delay motion events should be sent, if multi-tap with out of distance slop. + // STATE_IDLE will check if tapCount() < 2. + allowEventDelegation(); + assertStaysIn(STATE_IDLE, () -> { + tap(); + tap(DEFAULT_X * 2, DEFAULT_Y * 2); + }); + assertStaysIn(STATE_IDLE, () -> { + tap(); + tap(DEFAULT_X * 2, DEFAULT_Y * 2); + tap(); + tap(DEFAULT_X * 2, DEFAULT_Y * 2); + tap(); + }); + } + private void assertZoomsImmediatelyOnSwipeFrom(int state) { goFromStateIdleTo(state); swipeAndHold(); @@ -525,6 +543,11 @@ public class MagnificationGestureHandlerTest { send(upEvent()); } + private void tap(float x, float y) { + send(downEvent(x, y)); + send(upEvent(x, y)); + } + private void swipe() { swipeAndHold(); send(upEvent()); @@ -566,18 +589,26 @@ public class MagnificationGestureHandlerTest { } private MotionEvent downEvent() { + return downEvent(DEFAULT_X, DEFAULT_Y); + } + + private MotionEvent downEvent(float x, float y) { mLastDownTime = mClock.now(); return fromTouchscreen(MotionEvent.obtain(mLastDownTime, mLastDownTime, - ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0)); + ACTION_DOWN, x, y, 0)); } private MotionEvent upEvent() { - return upEvent(mLastDownTime); + return upEvent(DEFAULT_X, DEFAULT_Y, mLastDownTime); } - private MotionEvent upEvent(long downTime) { + private MotionEvent upEvent(float x, float y) { + return upEvent(x, y, mLastDownTime); + } + + private MotionEvent upEvent(float x, float y, long downTime) { return fromTouchscreen(MotionEvent.obtain(downTime, mClock.now(), - MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0)); + MotionEvent.ACTION_UP, x, y, 0)); } private MotionEvent pointerEvent(int action, float x, float y) {