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

Commit c78d6413 authored by Zachary Kuznia's avatar Zachary Kuznia
Browse files

Use the standard GestureDetector to handle double tap and hold in TouchExplorer.

b/24407329

Change-Id: I1cbd1a232bd642eb9bf87548b1a3d1afe48a9bed
parent 024ce628
Loading
Loading
Loading
Loading
+42 −114
Original line number Diff line number Diff line
@@ -112,12 +112,6 @@ class TouchExplorer implements EventStreamTransformation {
    // Timeout before trying to decide what the user is trying to do.
    private final int mDetermineUserIntentTimeout;

    // Timeout within which we try to detect a tap.
    private final int mTapTimeout;

    // Slop between the down and up tap to be a tap.
    private final int mTouchSlop;

    // Slop between the first and second tap to be a double tap.
    private final int mDoubleTapSlop;

@@ -142,9 +136,6 @@ class TouchExplorer implements EventStreamTransformation {
    // Command for delayed sending of touch interaction end events.
    private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;

    // Command for delayed sending of a long press.
    private final PerformLongPressDelayed mPerformLongPressDelayed;

    // Command for exiting gesture detection mode after a timeout.
    private final ExitGestureDetectionModeDelayed mExitGestureDetectionModeDelayed;

@@ -173,9 +164,6 @@ class TouchExplorer implements EventStreamTransformation {
    // Handle to the accessibility manager service.
    private final AccessibilityManagerService mAms;

    // Temporary rectangle to avoid instantiation.
    private final Rect mTempRect = new Rect();

    // Temporary point to avoid instantiation.
    private final Point mTempPoint = new Point();

@@ -226,12 +214,9 @@ class TouchExplorer implements EventStreamTransformation {
        mAms = service;
        mReceivedPointerTracker = new ReceivedPointerTracker();
        mInjectedPointerTracker = new InjectedPointerTracker();
        mTapTimeout = ViewConfiguration.getTapTimeout();
        mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
        mHandler = new Handler(context.getMainLooper());
        mPerformLongPressDelayed = new PerformLongPressDelayed();
        mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed();
        mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
        mGestureLibrary.setOrientationStyle(8);
@@ -299,7 +284,6 @@ class TouchExplorer implements EventStreamTransformation {
        // Remove all pending callbacks.
        mSendHoverEnterAndMoveDelayed.cancel();
        mSendHoverExitDelayed.cancel();
        mPerformLongPressDelayed.cancel();
        mExitGestureDetectionModeDelayed.cancel();
        mSendTouchExplorationEndDelayed.cancel();
        mSendTouchInteractionEndDelayed.cancel();
@@ -437,7 +421,6 @@ class TouchExplorer implements EventStreamTransformation {
                // we resent the delayed callback and wait again.
                mSendHoverEnterAndMoveDelayed.cancel();
                mSendHoverExitDelayed.cancel();
                mPerformLongPressDelayed.cancel();

                if (mSendTouchExplorationEndDelayed.isPending()) {
                    mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -447,18 +430,7 @@ class TouchExplorer implements EventStreamTransformation {
                    mSendTouchInteractionEndDelayed.forceSendAndRemove();
                }

                // If we have the first tap, schedule a long press and break
                // since we do not want to schedule hover enter because
                // the delayed callback will kick in before the long click.
                // This would lead to a state transition resulting in long
                // pressing the item below the double taped area which is
                // not necessary where accessibility focus is.
                if (mDoubleTapDetector.firstTapDetected()) {
                    // We got a tap now post a long press action.
                    mPerformLongPressDelayed.post(event, policyFlags);
                    break;
                }
                if (!mTouchExplorationInProgress) {
                if (!mDoubleTapDetector.firstTapDetected() && !mTouchExplorationInProgress) {
                    if (!mSendHoverEnterAndMoveDelayed.isPending()) {
                        // Deliver hover enter with a delay to have a chance
                        // to detect what the user is trying to do.
@@ -478,7 +450,6 @@ class TouchExplorer implements EventStreamTransformation {
                // decide what we will actually do next.
                mSendHoverEnterAndMoveDelayed.cancel();
                mSendHoverExitDelayed.cancel();
                mPerformLongPressDelayed.cancel();
            } break;
            case MotionEvent.ACTION_MOVE: {
                final int pointerId = receivedTracker.getPrimaryPointerId();
@@ -521,7 +492,6 @@ class TouchExplorer implements EventStreamTransformation {
                                    mVelocityTracker.clear();
                                    mSendHoverEnterAndMoveDelayed.cancel();
                                    mSendHoverExitDelayed.cancel();
                                    mPerformLongPressDelayed.cancel();
                                    mExitGestureDetectionModeDelayed.post();
                                    // Send accessibility event to announce the start
                                    // of gesture recognition.
@@ -532,28 +502,12 @@ class TouchExplorer implements EventStreamTransformation {
                                    // exploring so start sending events.
                                    mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
                                    mSendHoverExitDelayed.cancel();
                                    mPerformLongPressDelayed.cancel();
                                    sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                            pointerIdBits, policyFlags);
                                }
                                break;
                            }
                        } else {
                            // Cancel the long press if pending and the user
                            // moved more than the slop.
                            if (mPerformLongPressDelayed.isPending()) {
                                final float deltaX =
                                        receivedTracker.getReceivedPointerDownX(pointerId)
                                        - rawEvent.getX(pointerIndex);
                                final float deltaY =
                                        receivedTracker.getReceivedPointerDownY(pointerId)
                                        - rawEvent.getY(pointerIndex);
                                final double moveDelta = Math.hypot(deltaX, deltaY);
                                // The user has moved enough for us to decide.
                                if (moveDelta > mTouchSlop) {
                                    mPerformLongPressDelayed.cancel();
                                }
                            }
                            if (mTouchExplorationInProgress) {
                                sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                                sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
@@ -569,9 +523,7 @@ class TouchExplorer implements EventStreamTransformation {
                            // scheduled sending events.
                            mSendHoverEnterAndMoveDelayed.cancel();
                            mSendHoverExitDelayed.cancel();
                            mPerformLongPressDelayed.cancel();
                        } else {
                            mPerformLongPressDelayed.cancel();
                            if (mTouchExplorationInProgress) {
                                // If the user is touch exploring the second pointer may be
                                // performing a double tap to activate an item without need
@@ -620,9 +572,7 @@ class TouchExplorer implements EventStreamTransformation {
                            // scheduled sending events.
                            mSendHoverEnterAndMoveDelayed.cancel();
                            mSendHoverExitDelayed.cancel();
                            mPerformLongPressDelayed.cancel();
                        } else {
                            mPerformLongPressDelayed.cancel();
                            // We are sending events so send exit and gesture
                            // end since we transition to another state.
                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -643,7 +593,6 @@ class TouchExplorer implements EventStreamTransformation {
                final int pointerId = event.getPointerId(event.getActionIndex());
                final int pointerIdBits = (1 << pointerId);

                mPerformLongPressDelayed.cancel();
                mVelocityTracker.clear();

                if (mSendHoverEnterAndMoveDelayed.isPending()) {
@@ -1110,6 +1059,7 @@ class TouchExplorer implements EventStreamTransformation {
        private final GestureDetector mGestureDetector;
        private boolean mFirstTapDetected;
        private boolean mDoubleTapDetected;
        private int mPolicyFlags;

        DoubleTapDetector(Context context) {
            mGestureDetector = new GestureDetector(context, this);
@@ -1117,6 +1067,7 @@ class TouchExplorer implements EventStreamTransformation {
        }

        public void onMotionEvent(MotionEvent event, int policyFlags) {
            mPolicyFlags = policyFlags;
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    mDoubleTapDetected = false;
@@ -1134,6 +1085,11 @@ class TouchExplorer implements EventStreamTransformation {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            maybeSendLongPress(e, mPolicyFlags);
        }

        @Override
        public boolean onSingleTapUp(MotionEvent event) {
            mFirstTapDetected = true;
@@ -1154,6 +1110,38 @@ class TouchExplorer implements EventStreamTransformation {
            return true;
        }

        private void maybeSendLongPress(MotionEvent event, int policyFlags) {
            if (!mDoubleTapDetected) {
                return;
            }

            clear();

            // Pointers should not be zero when running this command.
            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
                return;
            }

            final int pointerIndex = event.getActionIndex();
            final int pointerId = event.getPointerId(pointerIndex);

            Point clickLocation = mTempPoint;
            final int result = computeClickLocation(clickLocation);

            if (result == CLICK_LOCATION_NONE) {
                return;
            }

            mLongPressingPointerId = pointerId;
            mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
            mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;

            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);

            mCurrentState = STATE_DELEGATING;
            sendDownForAllNotInjectedPointers(event, policyFlags);
        }

        private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
            if (!mDoubleTapDetected) {
                return;
@@ -1169,7 +1157,6 @@ class TouchExplorer implements EventStreamTransformation {
            // Remove pending event deliveries.
            mSendHoverEnterAndMoveDelayed.cancel();
            mSendHoverExitDelayed.cancel();
            mPerformLongPressDelayed.cancel();

            if (mSendTouchExplorationEndDelayed.isPending()) {
                mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -1178,8 +1165,8 @@ class TouchExplorer implements EventStreamTransformation {
                mSendTouchInteractionEndDelayed.forceSendAndRemove();
            }

            final int pointerId = event.getPointerId(event.getActionIndex());
            final int pointerIndex = event.findPointerIndex(pointerId);
            final int pointerIndex = event.getActionIndex();
            final int pointerId = event.getPointerId(pointerIndex);

            Point clickLocation = mTempPoint;
            final int result = computeClickLocation(clickLocation);
@@ -1305,65 +1292,6 @@ class TouchExplorer implements EventStreamTransformation {
        }
    }

    /**
     * Class for delayed sending of long press.
     */
    private final class PerformLongPressDelayed implements Runnable {
        private MotionEvent mEvent;
        private int mPolicyFlags;

        public void post(MotionEvent prototype, int policyFlags) {
            mEvent = MotionEvent.obtain(prototype);
            mPolicyFlags = policyFlags;
            mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
        }

        public void cancel() {
            if (mEvent != null) {
                mHandler.removeCallbacks(this);
                clear();
            }
        }

        private boolean isPending() {
            return mHandler.hasCallbacks(this);
        }

        @Override
        public void run() {
            // Pointers should not be zero when running this command.
            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
                return;
            }

            final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
            final int pointerIndex = mEvent.findPointerIndex(pointerId);

            Point clickLocation = mTempPoint;
            final int result = computeClickLocation(clickLocation);

            if (result == CLICK_LOCATION_NONE) {
                return;
            }

            mLongPressingPointerId = pointerId;
            mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocation.x;
            mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocation.y;

            sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);

            mCurrentState = STATE_DELEGATING;
            sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags);
            clear();
        }

        private void clear() {
            mEvent.recycle();
            mEvent = null;
            mPolicyFlags = 0;
        }
    }

    /**
     * Class for delayed sending of hover enter and move events.
     */