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

Commit d7d72cf7 authored by Zach Kuznia's avatar Zach Kuznia Committed by Android (Google) Code Review
Browse files

Merge "Use the standard GestureDetector for Double Taps in TouchExplorer"

parents 0b29ba68 c052c635
Loading
Loading
Loading
Loading
+64 −76
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Slog;
import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -114,9 +115,6 @@ class TouchExplorer implements EventStreamTransformation {
    // Timeout within which we try to detect a tap.
    private final int mTapTimeout;

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

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

@@ -230,7 +228,6 @@ class TouchExplorer implements EventStreamTransformation {
        mInjectedPointerTracker = new InjectedPointerTracker();
        mTapTimeout = ViewConfiguration.getTapTimeout();
        mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
        mHandler = new Handler(context.getMainLooper());
@@ -248,7 +245,7 @@ class TouchExplorer implements EventStreamTransformation {
        mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                mDetermineUserIntentTimeout);
        mDoubleTapDetector = new DoubleTapDetector();
        mDoubleTapDetector = new DoubleTapDetector(mContext);
        final float density = context.getResources().getDisplayMetrics().density;
        mScaledMinPointerDistanceToUseMiddleLocation =
            (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
@@ -1109,66 +1106,63 @@ class TouchExplorer implements EventStreamTransformation {
        }
    }

    private class DoubleTapDetector {
        private MotionEvent mDownEvent;
        private MotionEvent mFirstTapEvent;
    private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener {
        private final GestureDetector mGestureDetector;
        private boolean mFirstTapDetected;
        private boolean mDoubleTapDetected;

        DoubleTapDetector(Context context) {
            mGestureDetector = new GestureDetector(context, this);
            mGestureDetector.setOnDoubleTapListener(this);
        }

        public void onMotionEvent(MotionEvent event, int policyFlags) {
            final int actionIndex = event.getActionIndex();
            final int action = event.getActionMasked();
            switch (action) {
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_POINTER_DOWN: {
                    if (mFirstTapEvent != null
                            && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
                        clear();
                    }
                    mDownEvent = MotionEvent.obtain(event);
                } break;
                    mDoubleTapDetected = false;
                    break;

                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP: {
                    if (mDownEvent == null) {
                        return;
                    }
                    if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
                        clear();
                        return;
                    maybeFinishDoubleTap(event, policyFlags);
                    break;
            }
                    if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
                            actionIndex)) {
                        if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
                                event, mDoubleTapTimeout)) {
                            mFirstTapEvent = MotionEvent.obtain(event);
                            mDownEvent.recycle();
                            mDownEvent = null;
                            return;
            mGestureDetector.onTouchEvent(event);
        }
                        if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
                                mDoubleTapSlop, actionIndex)) {
                            onDoubleTap(event, policyFlags);
                            mFirstTapEvent.recycle();
                            mFirstTapEvent = null;
                            mDownEvent.recycle();
                            mDownEvent = null;
                            return;

        @Override
        public boolean onDown(MotionEvent event) {
            return true;
        }
                        mFirstTapEvent.recycle();
                        mFirstTapEvent = null;
                    } else {
                        if (mFirstTapEvent != null) {
                            mFirstTapEvent.recycle();
                            mFirstTapEvent = null;

        @Override
        public boolean onSingleTapUp(MotionEvent event) {
            mFirstTapDetected = true;
            return false;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
            clear();
            return false;
        }
                    mDownEvent.recycle();
                    mDownEvent = null;
                } break;

        @Override
        public boolean onDoubleTap(MotionEvent event) {
            // The processing of the double tap is deferred until the finger is
            // lifted, so that we can detect a long press on the second tap.
            mDoubleTapDetected = true;
            return true;
        }

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

        public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
            clear();

            // This should never be called when more than two pointers are down.
            if (secondTapUp.getPointerCount() > 2) {
            if (event.getPointerCount() > 2) {
                return;
            }

@@ -1184,8 +1178,8 @@ class TouchExplorer implements EventStreamTransformation {
                mSendTouchInteractionEndDelayed.forceSendAndRemove();
            }

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

            Point clickLocation = mTempPoint;
            final int result = computeClickLocation(clickLocation);
@@ -1196,34 +1190,28 @@ class TouchExplorer implements EventStreamTransformation {
            // Do the click.
            PointerProperties[] properties = new PointerProperties[1];
            properties[0] = new PointerProperties();
            secondTapUp.getPointerProperties(pointerIndex, properties[0]);
            event.getPointerProperties(pointerIndex, properties[0]);
            PointerCoords[] coords = new PointerCoords[1];
            coords[0] = new PointerCoords();
            coords[0].x = clickLocation.x;
            coords[0].y = clickLocation.y;
            MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
                    secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
                    coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
                    secondTapUp.getSource(), secondTapUp.getFlags());
            MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
                    event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
                    coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
                    event.getSource(), event.getFlags());
            final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
            sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
            event.recycle();
            sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
            click_event.recycle();
            return;
        }

        public void clear() {
            if (mDownEvent != null) {
                mDownEvent.recycle();
                mDownEvent = null;
            }
            if (mFirstTapEvent != null) {
                mFirstTapEvent.recycle();
                mFirstTapEvent = null;
            }
            mFirstTapDetected = false;
            mDoubleTapDetected = false;
        }

        public boolean firstTapDetected() {
            return mFirstTapEvent != null
                && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
            return mFirstTapDetected;
        }
    }