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

Commit c37dc69c authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android Git Automerger
Browse files

am d367b70c: Merge "Accessibility HOVER_ENTER / EXIT without enclosing...

am d367b70c: Merge "Accessibility HOVER_ENTER / EXIT without enclosing EXPLORATION_GESTURE_START / END" into jb-mr1-dev

* commit 'd367b70c':
  Accessibility HOVER_ENTER / EXIT without enclosing EXPLORATION_GESTURE_START / END
parents cbf64feb d367b70c
Loading
Loading
Loading
Loading
+103 −78
Original line number Diff line number Diff line
@@ -102,10 +102,6 @@ class TouchExplorer implements EventStreamTransformation {
    // The timeout after which we are no longer trying to detect a gesture.
    private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;

    // The timeout to send interaction end events in case we did not
    // receive the expected hover exit event due to a misbehaving app.
    private static final int SEND_INTERACTION_END_EVENTS_TIMEOUT = 200;

    // Temporary array for storing pointer IDs.
    private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];

@@ -139,8 +135,11 @@ class TouchExplorer implements EventStreamTransformation {
    // Command for delayed sending of a hover exit event.
    private final SendHoverDelayed mSendHoverExitDelayed;

    // Command for delayed sending of interaction ending events.
    private final SendInteractionEndEventsDelayed mSendInteractionEndEventsDelayed;
    // Command for delayed sending of touch exploration end events.
    private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;

    // 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;
@@ -209,11 +208,8 @@ class TouchExplorer implements EventStreamTransformation {
    // The id of the last touch explored window.
    private int mLastTouchedWindowId;

    // Whether touch exploration gesture has ended.
    private boolean mTouchExplorationGestureEnded;

    // Whether touch interaction has ended.
    private boolean mTouchInteractionEnded;
    // Whether touch exploration is in progress.
    private boolean mTouchExplorationInProgress;

    /**
     * Creates a new instance.
@@ -240,7 +236,12 @@ class TouchExplorer implements EventStreamTransformation {
        mGestureLibrary.load();
        mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
        mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
        mSendInteractionEndEventsDelayed = new SendInteractionEndEventsDelayed();
        mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
                AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
                mDetermineUserIntentTimeout);
        mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                mDetermineUserIntentTimeout);
        mDoubleTapDetector = new DoubleTapDetector();
        final float density = context.getResources().getDisplayMetrics().density;
        mScaledMinPointerDistanceToUseMiddleLocation =
@@ -265,7 +266,7 @@ class TouchExplorer implements EventStreamTransformation {
        switch (mCurrentState) {
            case STATE_TOUCH_EXPLORING: {
                // If a touch exploration gesture is in progress send events for its end.
                sendExitEventsIfNeeded(policyFlags);
                sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
            } break;
            case STATE_DRAGGING: {
                mDraggingPointerId = INVALID_POINTER_ID;
@@ -286,7 +287,8 @@ class TouchExplorer implements EventStreamTransformation {
        mSendHoverExitDelayed.remove();
        mPerformLongPressDelayed.remove();
        mExitGestureDetectionModeDelayed.remove();
        mSendInteractionEndEventsDelayed.remove();
        mSendTouchExplorationEndDelayed.remove();
        mSendTouchInteractionEndDelayed.remove();
        // Reset the pointer trackers.
        mReceivedPointerTracker.clear();
        mInjectedPointerTracker.clear();
@@ -301,6 +303,7 @@ class TouchExplorer implements EventStreamTransformation {
        if (mNext != null) {
            mNext.clear();
        }
        mTouchExplorationInProgress = false;
    }

    @Override
@@ -341,19 +344,17 @@ class TouchExplorer implements EventStreamTransformation {

        // The event for gesture end should be strictly after the
        // last hover exit event.
        if (mTouchExplorationGestureEnded
        if (mSendTouchExplorationEndDelayed.isPending()
                && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
            mSendInteractionEndEventsDelayed.remove();
            mTouchExplorationGestureEnded = false;
                    mSendTouchExplorationEndDelayed.remove();
            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
        }

        // The event for touch interaction end should be strictly after the
        // last hover exit and the touch exploration gesture end events.
        if (mTouchInteractionEnded
        if (mSendTouchInteractionEndDelayed.isPending()
                && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
            mSendInteractionEndEventsDelayed.remove();
            mTouchInteractionEnded = false;
            mSendTouchInteractionEndDelayed.remove();
            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
        }

@@ -396,15 +397,6 @@ class TouchExplorer implements EventStreamTransformation {

        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // The delayed enter not delivered implies that we have delivered
                // TYPE_TOUCH_INTERACTION_START and not TYPE_TOUCH_INTERACTION_END,
                // therefore we need to deliver the interaction end event here.
                if (mSendHoverEnterDelayed.isPending()) {
                    sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
                }
                // Announce the start of a new touch interaction.
                sendAccessibilityEvent(
                        AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
                // Pre-feed the motion events to the gesture detector since we
                // have a distance slop before getting into gesture detection
                // mode and not using the points within this slop significantly
@@ -426,8 +418,20 @@ class TouchExplorer implements EventStreamTransformation {
                            mSendHoverExitDelayed.remove();
                        }

                        if (mSendInteractionEndEventsDelayed.isPending()) {
                            mSendInteractionEndEventsDelayed.forceSendAndRemove();
                        if (mSendTouchExplorationEndDelayed.isPending()) {
                            mSendTouchExplorationEndDelayed.forceSendAndRemove();
                        }

                        if (mSendTouchInteractionEndDelayed.isPending()) {
                            mSendTouchInteractionEndDelayed.forceSendAndRemove();
                        }

                        // Every pointer that goes down is active until it moves or
                        // another one goes down. Hence, having more than one pointer
                        // down we have already send the interaction start event.
                        if (event.getPointerCount() == 1) {
                            sendAccessibilityEvent(
                                    AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
                        }

                        mPerformLongPressDelayed.remove();
@@ -443,11 +447,13 @@ class TouchExplorer implements EventStreamTransformation {
                            mPerformLongPressDelayed.post(event, policyFlags);
                            break;
                        }
                        if (!mTouchExplorationInProgress) {
                            // Deliver hover enter with a delay to have a chance
                            // to detect what the user is trying to do.
                            final int pointerId = receivedTracker.getPrimaryActivePointerId();
                            final int pointerIdBits = (1 << pointerId);
                            mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
                        }
                    } break;
                    default: {
                        /* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -512,12 +518,27 @@ class TouchExplorer implements EventStreamTransformation {
                                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.remove();
                                }
                            }
                            // The user is wither double tapping or performing long
                            // press so do not send move events yet.
                            if (mDoubleTapDetector.firstTapDetected()) {
                                break;
                            }
                            sendEnterEventsIfNeeded(policyFlags);
                            sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                            sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
                                    policyFlags);
                        }
@@ -548,7 +569,7 @@ class TouchExplorer implements EventStreamTransformation {
                            }
                            // We are sending events so send exit and gesture
                            // end since we transition to another state.
                            sendExitEventsIfNeeded(policyFlags);
                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
                        }

                        // We know that a new state transition is to happen and the
@@ -583,7 +604,7 @@ class TouchExplorer implements EventStreamTransformation {
                            mPerformLongPressDelayed.remove();
                            // We are sending events so send exit and gesture
                            // end since we transition to another state.
                            sendExitEventsIfNeeded(policyFlags);
                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
                        }

                        // More than two pointers are delegated to the view hierarchy.
@@ -612,11 +633,14 @@ class TouchExplorer implements EventStreamTransformation {

                        // If we have not delivered the enter schedule exit.
                        if (mSendHoverEnterDelayed.isPending()) {
                            mSendHoverEnterDelayed.mTouchExplorationInProgress = false;
                            mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
                        } else {
                            // The user is touch exploring so we send events for end.
                            sendExitEventsIfNeeded(policyFlags);
                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
                        }

                        if (!mSendTouchInteractionEndDelayed.isPending()) {
                            mSendTouchInteractionEndDelayed.post();
                        }
                    } break;
                }
@@ -846,6 +870,14 @@ class TouchExplorer implements EventStreamTransformation {
        if (accessibilityManager.isEnabled()) {
            AccessibilityEvent event = AccessibilityEvent.obtain(type);
            accessibilityManager.sendAccessibilityEvent(event);
            switch (type) {
                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: {
                    mTouchExplorationInProgress = true;
                } break;
                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
                    mTouchExplorationInProgress = false;
                } break;
            }
        }
    }

@@ -893,14 +925,12 @@ class TouchExplorer implements EventStreamTransformation {
     *
     * @param policyFlags The policy flags associated with the event.
     */
    private void sendExitEventsIfNeeded(int policyFlags) {
    private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) {
        MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
        if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
            final int pointerIdBits = event.getPointerIdBits();
            mTouchExplorationGestureEnded = true;
            mTouchInteractionEnded = true;
            if (!mSendInteractionEndEventsDelayed.isPending()) {
                mSendInteractionEndEventsDelayed.post();
            if (!mSendTouchExplorationEndDelayed.isPending()) {
                mSendTouchExplorationEndDelayed.post();
            }
            sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
        }
@@ -912,10 +942,11 @@ class TouchExplorer implements EventStreamTransformation {
     *
     * @param policyFlags The policy flags associated with the event.
     */
    private void sendEnterEventsIfNeeded(int policyFlags) {
    private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
        MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
        if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
            final int pointerIdBits = event.getPointerIdBits();
            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
            sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
        }
    }
@@ -1181,8 +1212,12 @@ class TouchExplorer implements EventStreamTransformation {
            mSendHoverExitDelayed.remove();
            mPerformLongPressDelayed.remove();

            // The touch interaction has ended since we will send a click.
            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
            if (mSendTouchExplorationEndDelayed.isPending()) {
                mSendTouchExplorationEndDelayed.forceSendAndRemove();
            }
            if (mSendTouchInteractionEndDelayed.isPending()) {
                mSendTouchInteractionEndDelayed.forceSendAndRemove();
            }

            int clickLocationX;
            int clickLocationY;
@@ -1416,7 +1451,7 @@ class TouchExplorer implements EventStreamTransformation {
            mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX;
            mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY;

            sendExitEventsIfNeeded(mPolicyFlags);
            sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);

            mCurrentState = STATE_DELEGATING;
            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
@@ -1445,7 +1480,6 @@ class TouchExplorer implements EventStreamTransformation {
        private MotionEvent mPrototype;
        private int mPointerIdBits;
        private int mPolicyFlags;
        private boolean mTouchExplorationInProgress;

        public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
            mHoverAction = hoverAction;
@@ -1456,7 +1490,6 @@ class TouchExplorer implements EventStreamTransformation {
                int pointerIdBits, int policyFlags) {
            remove();
            mPrototype = MotionEvent.obtain(prototype);
            mTouchExplorationInProgress = touchExplorationInProgress;
            mPointerIdBits = pointerIdBits;
            mPolicyFlags = policyFlags;
            mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -1493,7 +1526,6 @@ class TouchExplorer implements EventStreamTransformation {
            mPrototype = null;
            mPointerIdBits = -1;
            mPolicyFlags = 0;
            mTouchExplorationInProgress = false;
        }

        public void forceSendAndRemove() {
@@ -1510,22 +1542,15 @@ class TouchExplorer implements EventStreamTransformation {
                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
                        "touchExplorationGestureStarted" : "touchExplorationGestureEnded");
            }
            if (mTouchExplorationInProgress) {
            if (mGestureStarted) {
                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
            } else {
                    mTouchExplorationGestureEnded = true;
                    mTouchInteractionEnded = true;
                    if (!mSendInteractionEndEventsDelayed.isPending()) {
                        mSendInteractionEndEventsDelayed.post();
                    }
                }
            } else {
                if (!mGestureStarted) {
                    mTouchInteractionEnded = true;
                    if (!mSendInteractionEndEventsDelayed.isPending()) {
                        mSendInteractionEndEventsDelayed.post();
                if (!mSendTouchExplorationEndDelayed.isPending()) {
                    mSendTouchExplorationEndDelayed.post();
                }
                if (mSendTouchInteractionEndDelayed.isPending()) {
                    mSendTouchInteractionEndDelayed.remove();
                    mSendTouchInteractionEndDelayed.post();
                }
            }
            sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
@@ -1533,14 +1558,21 @@ class TouchExplorer implements EventStreamTransformation {
        }
    }

    private class SendInteractionEndEventsDelayed implements Runnable {
    private class SendAccessibilityEventDelayed implements Runnable {
        private final int mEventType;
        private final int mDelay;

        public SendAccessibilityEventDelayed(int eventType, int delay) {
            mEventType = eventType;
            mDelay = delay;
        }

        public void remove() {
            mHandler.removeCallbacks(this);
        }

        public void post() {
            mHandler.postDelayed(this, SEND_INTERACTION_END_EVENTS_TIMEOUT);
            mHandler.postDelayed(this, mDelay);
        }

        public boolean isPending() {
@@ -1556,14 +1588,7 @@ class TouchExplorer implements EventStreamTransformation {

        @Override
        public void run() {
            if (mTouchExplorationGestureEnded) {
                mTouchExplorationGestureEnded = false;
                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
            }
            if (mTouchInteractionEnded) {
                mTouchInteractionEnded = false;
                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
            }
            sendAccessibilityEvent(mEventType);
        }
    }