@@ -102,10 +102,6 @@ class TouchExplorer implements EventStreamTransformation {
102102 // The timeout after which we are no longer trying to detect a gesture.
103103 private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000 ;
104104
105- // The timeout to send interaction end events in case we did not
106- // receive the expected hover exit event due to a misbehaving app.
107- private static final int SEND_INTERACTION_END_EVENTS_TIMEOUT = 200 ;
108-
109105 // Temporary array for storing pointer IDs.
110106 private final int [] mTempPointerIds = new int [MAX_POINTER_COUNT ];
111107
@@ -139,8 +135,11 @@ class TouchExplorer implements EventStreamTransformation {
139135 // Command for delayed sending of a hover exit event.
140136 private final SendHoverDelayed mSendHoverExitDelayed ;
141137
142- // Command for delayed sending of interaction ending events.
143- private final SendInteractionEndEventsDelayed mSendInteractionEndEventsDelayed ;
138+ // Command for delayed sending of touch exploration end events.
139+ private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed ;
140+
141+ // Command for delayed sending of touch interaction end events.
142+ private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed ;
144143
145144 // Command for delayed sending of a long press.
146145 private final PerformLongPressDelayed mPerformLongPressDelayed ;
@@ -209,11 +208,8 @@ class TouchExplorer implements EventStreamTransformation {
209208 // The id of the last touch explored window.
210209 private int mLastTouchedWindowId ;
211210
212- // Whether touch exploration gesture has ended.
213- private boolean mTouchExplorationGestureEnded ;
214-
215- // Whether touch interaction has ended.
216- private boolean mTouchInteractionEnded ;
211+ // Whether touch exploration is in progress.
212+ private boolean mTouchExplorationInProgress ;
217213
218214 /**
219215 * Creates a new instance.
@@ -240,7 +236,12 @@ public TouchExplorer(Context context, AccessibilityManagerService service) {
240236 mGestureLibrary .load ();
241237 mSendHoverEnterDelayed = new SendHoverDelayed (MotionEvent .ACTION_HOVER_ENTER , true );
242238 mSendHoverExitDelayed = new SendHoverDelayed (MotionEvent .ACTION_HOVER_EXIT , false );
243- mSendInteractionEndEventsDelayed = new SendInteractionEndEventsDelayed ();
239+ mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed (
240+ AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END ,
241+ mDetermineUserIntentTimeout );
242+ mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed (
243+ AccessibilityEvent .TYPE_TOUCH_INTERACTION_END ,
244+ mDetermineUserIntentTimeout );
244245 mDoubleTapDetector = new DoubleTapDetector ();
245246 final float density = context .getResources ().getDisplayMetrics ().density ;
246247 mScaledMinPointerDistanceToUseMiddleLocation =
@@ -265,7 +266,7 @@ private void clear(MotionEvent event, int policyFlags) {
265266 switch (mCurrentState ) {
266267 case STATE_TOUCH_EXPLORING : {
267268 // If a touch exploration gesture is in progress send events for its end.
268- sendExitEventsIfNeeded (policyFlags );
269+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (policyFlags );
269270 } break ;
270271 case STATE_DRAGGING : {
271272 mDraggingPointerId = INVALID_POINTER_ID ;
@@ -286,7 +287,8 @@ private void clear(MotionEvent event, int policyFlags) {
286287 mSendHoverExitDelayed .remove ();
287288 mPerformLongPressDelayed .remove ();
288289 mExitGestureDetectionModeDelayed .remove ();
289- mSendInteractionEndEventsDelayed .remove ();
290+ mSendTouchExplorationEndDelayed .remove ();
291+ mSendTouchInteractionEndDelayed .remove ();
290292 // Reset the pointer trackers.
291293 mReceivedPointerTracker .clear ();
292294 mInjectedPointerTracker .clear ();
@@ -301,6 +303,7 @@ private void clear(MotionEvent event, int policyFlags) {
301303 if (mNext != null ) {
302304 mNext .clear ();
303305 }
306+ mTouchExplorationInProgress = false ;
304307 }
305308
306309 @ Override
@@ -341,19 +344,17 @@ public void onAccessibilityEvent(AccessibilityEvent event) {
341344
342345 // The event for gesture end should be strictly after the
343346 // last hover exit event.
344- if (mTouchExplorationGestureEnded
347+ if (mSendTouchExplorationEndDelayed . isPending ()
345348 && eventType == AccessibilityEvent .TYPE_VIEW_HOVER_EXIT ) {
346- mSendInteractionEndEventsDelayed .remove ();
347- mTouchExplorationGestureEnded = false ;
349+ mSendTouchExplorationEndDelayed .remove ();
348350 sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END );
349351 }
350352
351353 // The event for touch interaction end should be strictly after the
352354 // last hover exit and the touch exploration gesture end events.
353- if (mTouchInteractionEnded
355+ if (mSendTouchInteractionEndDelayed . isPending ()
354356 && eventType == AccessibilityEvent .TYPE_VIEW_HOVER_EXIT ) {
355- mSendInteractionEndEventsDelayed .remove ();
356- mTouchInteractionEnded = false ;
357+ mSendTouchInteractionEndDelayed .remove ();
357358 sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
358359 }
359360
@@ -396,15 +397,6 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
396397
397398 switch (event .getActionMasked ()) {
398399 case MotionEvent .ACTION_DOWN :
399- // The delayed enter not delivered implies that we have delivered
400- // TYPE_TOUCH_INTERACTION_START and not TYPE_TOUCH_INTERACTION_END,
401- // therefore we need to deliver the interaction end event here.
402- if (mSendHoverEnterDelayed .isPending ()) {
403- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
404- }
405- // Announce the start of a new touch interaction.
406- sendAccessibilityEvent (
407- AccessibilityEvent .TYPE_TOUCH_INTERACTION_START );
408400 // Pre-feed the motion events to the gesture detector since we
409401 // have a distance slop before getting into gesture detection
410402 // mode and not using the points within this slop significantly
@@ -426,8 +418,20 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
426418 mSendHoverExitDelayed .remove ();
427419 }
428420
429- if (mSendInteractionEndEventsDelayed .isPending ()) {
430- mSendInteractionEndEventsDelayed .forceSendAndRemove ();
421+ if (mSendTouchExplorationEndDelayed .isPending ()) {
422+ mSendTouchExplorationEndDelayed .forceSendAndRemove ();
423+ }
424+
425+ if (mSendTouchInteractionEndDelayed .isPending ()) {
426+ mSendTouchInteractionEndDelayed .forceSendAndRemove ();
427+ }
428+
429+ // Every pointer that goes down is active until it moves or
430+ // another one goes down. Hence, having more than one pointer
431+ // down we have already send the interaction start event.
432+ if (event .getPointerCount () == 1 ) {
433+ sendAccessibilityEvent (
434+ AccessibilityEvent .TYPE_TOUCH_INTERACTION_START );
431435 }
432436
433437 mPerformLongPressDelayed .remove ();
@@ -443,11 +447,13 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
443447 mPerformLongPressDelayed .post (event , policyFlags );
444448 break ;
445449 }
446- // Deliver hover enter with a delay to have a chance
447- // to detect what the user is trying to do.
448- final int pointerId = receivedTracker .getPrimaryActivePointerId ();
449- final int pointerIdBits = (1 << pointerId );
450- mSendHoverEnterDelayed .post (event , true , pointerIdBits , policyFlags );
450+ if (!mTouchExplorationInProgress ) {
451+ // Deliver hover enter with a delay to have a chance
452+ // to detect what the user is trying to do.
453+ final int pointerId = receivedTracker .getPrimaryActivePointerId ();
454+ final int pointerIdBits = (1 << pointerId );
455+ mSendHoverEnterDelayed .post (event , true , pointerIdBits , policyFlags );
456+ }
451457 } break ;
452458 default : {
453459 /* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -512,12 +518,27 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
512518 break ;
513519 }
514520 } else {
521+ // Cancel the long press if pending and the user
522+ // moved more than the slop.
523+ if (mPerformLongPressDelayed .isPending ()) {
524+ final float deltaX =
525+ receivedTracker .getReceivedPointerDownX (pointerId )
526+ - rawEvent .getX (pointerIndex );
527+ final float deltaY =
528+ receivedTracker .getReceivedPointerDownY (pointerId )
529+ - rawEvent .getY (pointerIndex );
530+ final double moveDelta = Math .hypot (deltaX , deltaY );
531+ // The user has moved enough for us to decide.
532+ if (moveDelta > mTouchSlop ) {
533+ mPerformLongPressDelayed .remove ();
534+ }
535+ }
515536 // The user is wither double tapping or performing long
516537 // press so do not send move events yet.
517538 if (mDoubleTapDetector .firstTapDetected ()) {
518539 break ;
519540 }
520- sendEnterEventsIfNeeded (policyFlags );
541+ sendTouchExplorationGestureStartAndHoverEnterIfNeeded (policyFlags );
521542 sendMotionEvent (event , MotionEvent .ACTION_HOVER_MOVE , pointerIdBits ,
522543 policyFlags );
523544 }
@@ -548,7 +569,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
548569 }
549570 // We are sending events so send exit and gesture
550571 // end since we transition to another state.
551- sendExitEventsIfNeeded (policyFlags );
572+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (policyFlags );
552573 }
553574
554575 // We know that a new state transition is to happen and the
@@ -583,7 +604,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
583604 mPerformLongPressDelayed .remove ();
584605 // We are sending events so send exit and gesture
585606 // end since we transition to another state.
586- sendExitEventsIfNeeded (policyFlags );
607+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (policyFlags );
587608 }
588609
589610 // More than two pointers are delegated to the view hierarchy.
@@ -612,11 +633,14 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent
612633
613634 // If we have not delivered the enter schedule exit.
614635 if (mSendHoverEnterDelayed .isPending ()) {
615- mSendHoverEnterDelayed .mTouchExplorationInProgress = false ;
616636 mSendHoverExitDelayed .post (event , false , pointerIdBits , policyFlags );
617637 } else {
618638 // The user is touch exploring so we send events for end.
619- sendExitEventsIfNeeded (policyFlags );
639+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (policyFlags );
640+ }
641+
642+ if (!mSendTouchInteractionEndDelayed .isPending ()) {
643+ mSendTouchInteractionEndDelayed .post ();
620644 }
621645 } break ;
622646 }
@@ -844,6 +868,14 @@ private void sendAccessibilityEvent(int type) {
844868 if (accessibilityManager .isEnabled ()) {
845869 AccessibilityEvent event = AccessibilityEvent .obtain (type );
846870 accessibilityManager .sendAccessibilityEvent (event );
871+ switch (type ) {
872+ case AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START : {
873+ mTouchExplorationInProgress = true ;
874+ } break ;
875+ case AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END : {
876+ mTouchExplorationInProgress = false ;
877+ } break ;
878+ }
847879 }
848880 }
849881
@@ -891,14 +923,12 @@ private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int
891923 *
892924 * @param policyFlags The policy flags associated with the event.
893925 */
894- private void sendExitEventsIfNeeded (int policyFlags ) {
926+ private void sendHoverExitAndTouchExplorationGestureEndIfNeeded (int policyFlags ) {
895927 MotionEvent event = mInjectedPointerTracker .getLastInjectedHoverEvent ();
896928 if (event != null && event .getActionMasked () != MotionEvent .ACTION_HOVER_EXIT ) {
897929 final int pointerIdBits = event .getPointerIdBits ();
898- mTouchExplorationGestureEnded = true ;
899- mTouchInteractionEnded = true ;
900- if (!mSendInteractionEndEventsDelayed .isPending ()) {
901- mSendInteractionEndEventsDelayed .post ();
930+ if (!mSendTouchExplorationEndDelayed .isPending ()) {
931+ mSendTouchExplorationEndDelayed .post ();
902932 }
903933 sendMotionEvent (event , MotionEvent .ACTION_HOVER_EXIT , pointerIdBits , policyFlags );
904934 }
@@ -910,10 +940,11 @@ private void sendExitEventsIfNeeded(int policyFlags) {
910940 *
911941 * @param policyFlags The policy flags associated with the event.
912942 */
913- private void sendEnterEventsIfNeeded (int policyFlags ) {
943+ private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded (int policyFlags ) {
914944 MotionEvent event = mInjectedPointerTracker .getLastInjectedHoverEvent ();
915945 if (event != null && event .getActionMasked () == MotionEvent .ACTION_HOVER_EXIT ) {
916946 final int pointerIdBits = event .getPointerIdBits ();
947+ sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
917948 sendMotionEvent (event , MotionEvent .ACTION_HOVER_ENTER , pointerIdBits , policyFlags );
918949 }
919950 }
@@ -1179,8 +1210,12 @@ public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
11791210 mSendHoverExitDelayed .remove ();
11801211 mPerformLongPressDelayed .remove ();
11811212
1182- // The touch interaction has ended since we will send a click.
1183- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
1213+ if (mSendTouchExplorationEndDelayed .isPending ()) {
1214+ mSendTouchExplorationEndDelayed .forceSendAndRemove ();
1215+ }
1216+ if (mSendTouchInteractionEndDelayed .isPending ()) {
1217+ mSendTouchInteractionEndDelayed .forceSendAndRemove ();
1218+ }
11841219
11851220 int clickLocationX ;
11861221 int clickLocationY ;
@@ -1414,7 +1449,7 @@ public void run() {
14141449 mLongPressingPointerDeltaX = (int ) mEvent .getX (pointerIndex ) - clickLocationX ;
14151450 mLongPressingPointerDeltaY = (int ) mEvent .getY (pointerIndex ) - clickLocationY ;
14161451
1417- sendExitEventsIfNeeded (mPolicyFlags );
1452+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (mPolicyFlags );
14181453
14191454 mCurrentState = STATE_DELEGATING ;
14201455 sendDownForAllActiveNotInjectedPointers (mEvent , mPolicyFlags );
@@ -1443,7 +1478,6 @@ class SendHoverDelayed implements Runnable {
14431478 private MotionEvent mPrototype ;
14441479 private int mPointerIdBits ;
14451480 private int mPolicyFlags ;
1446- private boolean mTouchExplorationInProgress ;
14471481
14481482 public SendHoverDelayed (int hoverAction , boolean gestureStarted ) {
14491483 mHoverAction = hoverAction ;
@@ -1454,7 +1488,6 @@ public void post(MotionEvent prototype, boolean touchExplorationInProgress,
14541488 int pointerIdBits , int policyFlags ) {
14551489 remove ();
14561490 mPrototype = MotionEvent .obtain (prototype );
1457- mTouchExplorationInProgress = touchExplorationInProgress ;
14581491 mPointerIdBits = pointerIdBits ;
14591492 mPolicyFlags = policyFlags ;
14601493 mHandler .postDelayed (this , mDetermineUserIntentTimeout );
@@ -1491,7 +1524,6 @@ private void clear() {
14911524 mPrototype = null ;
14921525 mPointerIdBits = -1 ;
14931526 mPolicyFlags = 0 ;
1494- mTouchExplorationInProgress = false ;
14951527 }
14961528
14971529 public void forceSendAndRemove () {
@@ -1508,37 +1540,37 @@ public void run() {
15081540 Slog .d (LOG_TAG_SEND_HOVER_DELAYED , mGestureStarted ?
15091541 "touchExplorationGestureStarted" : "touchExplorationGestureEnded" );
15101542 }
1511- if (mTouchExplorationInProgress ) {
1512- if (mGestureStarted ) {
1513- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
1514- } else {
1515- mTouchExplorationGestureEnded = true ;
1516- mTouchInteractionEnded = true ;
1517- if (!mSendInteractionEndEventsDelayed .isPending ()) {
1518- mSendInteractionEndEventsDelayed .post ();
1519- }
1520- }
1543+ if (mGestureStarted ) {
1544+ sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
15211545 } else {
1522- if (!mGestureStarted ) {
1523- mTouchInteractionEnded = true ;
1524- if (!mSendInteractionEndEventsDelayed .isPending ()) {
1525- mSendInteractionEndEventsDelayed .post ();
1526- }
1546+ if (!mSendTouchExplorationEndDelayed .isPending ()) {
1547+ mSendTouchExplorationEndDelayed .post ();
1548+ }
1549+ if (mSendTouchInteractionEndDelayed .isPending ()) {
1550+ mSendTouchInteractionEndDelayed .remove ();
1551+ mSendTouchInteractionEndDelayed .post ();
15271552 }
15281553 }
15291554 sendMotionEvent (mPrototype , mHoverAction , mPointerIdBits , mPolicyFlags );
15301555 clear ();
15311556 }
15321557 }
15331558
1534- private class SendInteractionEndEventsDelayed implements Runnable {
1559+ private class SendAccessibilityEventDelayed implements Runnable {
1560+ private final int mEventType ;
1561+ private final int mDelay ;
1562+
1563+ public SendAccessibilityEventDelayed (int eventType , int delay ) {
1564+ mEventType = eventType ;
1565+ mDelay = delay ;
1566+ }
15351567
15361568 public void remove () {
15371569 mHandler .removeCallbacks (this );
15381570 }
15391571
15401572 public void post () {
1541- mHandler .postDelayed (this , SEND_INTERACTION_END_EVENTS_TIMEOUT );
1573+ mHandler .postDelayed (this , mDelay );
15421574 }
15431575
15441576 public boolean isPending () {
@@ -1554,14 +1586,7 @@ public void forceSendAndRemove() {
15541586
15551587 @ Override
15561588 public void run () {
1557- if (mTouchExplorationGestureEnded ) {
1558- mTouchExplorationGestureEnded = false ;
1559- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END );
1560- }
1561- if (mTouchInteractionEnded ) {
1562- mTouchInteractionEnded = false ;
1563- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
1564- }
1589+ sendAccessibilityEvent (mEventType );
15651590 }
15661591 }
15671592
0 commit comments