Loading services/java/com/android/server/accessibility/TouchExplorer.java +103 −78 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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; Loading Loading @@ -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. Loading @@ -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 = Loading @@ -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; Loading @@ -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(); Loading @@ -301,6 +303,7 @@ class TouchExplorer implements EventStreamTransformation { if (mNext != null) { mNext.clear(); } mTouchExplorationInProgress = false; } @Override Loading Loading @@ -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); } Loading Loading @@ -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 Loading @@ -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(); Loading @@ -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 */ Loading Loading @@ -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); } Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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; } Loading Loading @@ -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; } } } Loading Loading @@ -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); } Loading @@ -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); } } Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -1493,7 +1526,6 @@ class TouchExplorer implements EventStreamTransformation { mPrototype = null; mPointerIdBits = -1; mPolicyFlags = 0; mTouchExplorationInProgress = false; } public void forceSendAndRemove() { Loading @@ -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); Loading @@ -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() { Loading @@ -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); } } Loading Loading
services/java/com/android/server/accessibility/TouchExplorer.java +103 −78 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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; Loading Loading @@ -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. Loading @@ -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 = Loading @@ -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; Loading @@ -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(); Loading @@ -301,6 +303,7 @@ class TouchExplorer implements EventStreamTransformation { if (mNext != null) { mNext.clear(); } mTouchExplorationInProgress = false; } @Override Loading Loading @@ -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); } Loading Loading @@ -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 Loading @@ -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(); Loading @@ -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 */ Loading Loading @@ -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); } Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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; } Loading Loading @@ -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; } } } Loading Loading @@ -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); } Loading @@ -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); } } Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -1493,7 +1526,6 @@ class TouchExplorer implements EventStreamTransformation { mPrototype = null; mPointerIdBits = -1; mPolicyFlags = 0; mTouchExplorationInProgress = false; } public void forceSendAndRemove() { Loading @@ -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); Loading @@ -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() { Loading @@ -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); } } Loading