Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a68dd515 authored by Ameer Armaly's avatar Ameer Armaly Committed by Automerger Merge Worker
Browse files

Merge "Do not transition from gesture detection state after gesture cancelation." am: 31012130

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12901727

Change-Id: I4bc5b67d2832f05f168dc8719b3eb31d4088c8c9
parents cf32a1da 31012130
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -111,9 +111,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
    // Shared state information.
    private TouchState mState;

    GestureManifold(Context context, Listener listener, TouchState state) {
    GestureManifold(Context context, Listener listener, TouchState state, Handler handler) {
        mContext = context;
        mHandler = new Handler(context.getMainLooper());
        mHandler = handler;
        mListener = listener;
        mState = state;
        mMultiFingerGesturesEnabled = false;
+11 −3
Original line number Diff line number Diff line
@@ -199,7 +199,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
                new SendAccessibilityEventDelayed(
                        TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout);
        if (detector == null) {
            mGestureDetector = new GestureManifold(context, this, mState);
            mGestureDetector = new GestureManifold(context, this, mState, mHandler);
        } else {
            mGestureDetector = detector;
        }
@@ -391,7 +391,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
    public boolean onGestureStarted() {
        // We have to perform gesture detection, so
        // clear the current state and try to detect.
        mState.startGestureDetecting();
        mSendHoverEnterAndMoveDelayed.cancel();
        mSendHoverExitDelayed.cancel();
        mExitGestureDetectionModeDelayed.post();
@@ -1195,7 +1194,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
    }

    private boolean shouldPerformGestureDetection(MotionEvent event) {
        if (mState.isDelegating()) {
        if (mState.isDelegating() || mState.isDragging()) {
            return false;
        }
        if (event.getActionMasked() == ACTION_DOWN) {
@@ -1288,6 +1287,15 @@ public class TouchExplorer extends BaseEventStreamTransformation
        }

        public void run() {
            if (mReceivedPointerTracker.getReceivedPointerDownCount() > 1) {
                // Multi-finger touch exploration doesn't make sense.
                Slog.e(
                        LOG_TAG,
                        "Attempted touch exploration with "
                                + mReceivedPointerTracker.getReceivedPointerDownCount()
                                + " pointers down.");
                return;
            }
            // Send an accessibility event to announce the touch exploration start.
            mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
            if (isSendMotionEventsEnabled()) {
+0 −3
Original line number Diff line number Diff line
@@ -207,9 +207,6 @@ public class TouchState {
            case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
                startGestureDetecting();
                break;
            case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
                startTouchInteracting();
                break;
            default:
                break;
        }
+3 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.accessibilityservice.AccessibilityService;
import android.content.Context;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Handler;
import android.view.MotionEvent;

import androidx.test.InstrumentationRegistry;
@@ -56,7 +57,8 @@ public class GestureManifoldTest {
        // Construct a testable GestureManifold.
        mResultListener = mock(GestureManifold.Listener.class);
        mState = new TouchState();
        mManifold = new GestureManifold(context, mResultListener, mState);
        Handler handler = new Handler(context.getMainLooper());
        mManifold = new GestureManifold(context, mResultListener, mState, handler);
        // Play the role of touch explorer in updating the shared state.
        when(mResultListener.onGestureStarted()).thenReturn(onGestureStarted());

+43 −9
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_E

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;

import android.content.Context;
import android.graphics.PointF;
@@ -129,10 +128,9 @@ public class TouchExplorerTest {
        mContext = InstrumentationRegistry.getContext();
        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
        AccessibilityManagerService ams = new AccessibilityManagerService(mContext);
        GestureManifold detector = mock(GestureManifold.class);
        mCaptor = new EventCaptor();
        mHandler = new TestHandler();
        mTouchExplorer = new TouchExplorer(mContext, ams, detector, mHandler);
        mTouchExplorer = new TouchExplorer(mContext, ams, null, mHandler);
        mTouchExplorer.setNext(mCaptor);
    }

@@ -272,8 +270,8 @@ public class TouchExplorerTest {
        // Wait for the views responding to hover enter/move events.
        mHandler.fastForward(oneThirdUserIntentTimeout);
        // Simulate receiving the a11y exit event sent by the first view.
        AccessibilityEvent a11yExitEvent = AccessibilityEvent.obtain(
                AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
        AccessibilityEvent a11yExitEvent =
                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
        mTouchExplorer.onAccessibilityEvent(a11yExitEvent);

        // Wait for running the hover exit event runnable. After it, touch-exploration end event
@@ -364,6 +362,39 @@ public class TouchExplorerTest {
        assertCapturedEventsNoHistory();
    }

    @Test
    public void testCanceledGesture_shouldDoNothing() {
        mTouchExplorer.setMultiFingerGesturesEnabled(true);
        mTouchExplorer.setTwoFingerPassthroughEnabled(true);
        // Start a three-finger swipe.
        send(downEvent());
        send(pointerDownEvent());
        send(thirdPointerDownEvent());
        moveEachPointers(mLastEvent, p(0, 200), p(0, 200), p(0, 200));
        send(mLastEvent);
        assertState(STATE_GESTURE_DETECTING);
        mHandler.fastForward(2 * (int) Swipe.MAX_TIME_TO_CONTINUE_SWIPE_MS);
        // Lift the third finger but keep the other two going.
        send(thirdPointerUpEvent());
        // Manually construct the next move event. Using moveEachPointers() will batch the move
        // event onto the pointer up event which will mean that the move event still has a pointer
        // count of 3.
        // Todo: refactor to avoid using batching as there is no special reason to do it that way.
        float[] x = new float[2];
        float[] y = new float[2];
        x[0] = mLastEvent.getX(0) + 100;
        x[1] = mLastEvent.getX(1) + 100;
        y[0] = mLastEvent.getY(0) + 100;
        y[1] = mLastEvent.getY(1) + 100;
        send(manyPointerEvent(ACTION_MOVE, x, y));
        // Ensure that no two-finger passthrough is being executed.
        assertState(STATE_GESTURE_DETECTING);
        assertNoCapturedEvents();
        send(pointerUpEvent());
        send(upEvent());
        mTouchExplorer.setMultiFingerGesturesEnabled(false);
    }

    private static MotionEvent fromTouchscreen(MotionEvent ev) {
        ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
        return ev;
@@ -414,8 +445,7 @@ public class TouchExplorerTest {
                    throw new IllegalArgumentException("Illegal state: " + state);
            }
        } catch (Throwable t) {
            throw new RuntimeException(
                    "Failed to go to state " + stateToString(state), t);
            throw new RuntimeException("Failed to go to state " + stateToString(state), t);
        }
    }

@@ -465,6 +495,10 @@ public class TouchExplorerTest {
                TouchState.getStateSymbolicName(mTouchExplorer.getState().getState()));
    }

    private void assertNoCapturedEvents() {
        assertEquals(0, getCapturedEvents().size());
    }

    private void assertCapturedEvents(int... actionsInOrder) {
        final int eventCount = actionsInOrder.length;
        assertEquals(eventCount, getCapturedEvents().size());
@@ -623,8 +657,8 @@ public class TouchExplorerTest {
    }

    /**
     * A {@link android.os.Handler} that doesn't process messages until {@link
     * #fastForward(int)} is invoked.
     * A {@link android.os.Handler} that doesn't process messages until {@link #fastForward(int)} is
     * invoked.
     *
     * @see com.android.server.testutils.TestHandler
     */