@@ -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 }
@@ -846,6 +870,14 @@ private void sendAccessibilityEvent(int type) {
846870 if (accessibilityManager .isEnabled ()) {
847871 AccessibilityEvent event = AccessibilityEvent .obtain (type );
848872 accessibilityManager .sendAccessibilityEvent (event );
873+ switch (type ) {
874+ case AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START : {
875+ mTouchExplorationInProgress = true ;
876+ } break ;
877+ case AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END : {
878+ mTouchExplorationInProgress = false ;
879+ } break ;
880+ }
849881 }
850882 }
851883
@@ -893,14 +925,12 @@ private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int
893925 *
894926 * @param policyFlags The policy flags associated with the event.
895927 */
896- private void sendExitEventsIfNeeded (int policyFlags ) {
928+ private void sendHoverExitAndTouchExplorationGestureEndIfNeeded (int policyFlags ) {
897929 MotionEvent event = mInjectedPointerTracker .getLastInjectedHoverEvent ();
898930 if (event != null && event .getActionMasked () != MotionEvent .ACTION_HOVER_EXIT ) {
899931 final int pointerIdBits = event .getPointerIdBits ();
900- mTouchExplorationGestureEnded = true ;
901- mTouchInteractionEnded = true ;
902- if (!mSendInteractionEndEventsDelayed .isPending ()) {
903- mSendInteractionEndEventsDelayed .post ();
932+ if (!mSendTouchExplorationEndDelayed .isPending ()) {
933+ mSendTouchExplorationEndDelayed .post ();
904934 }
905935 sendMotionEvent (event , MotionEvent .ACTION_HOVER_EXIT , pointerIdBits , policyFlags );
906936 }
@@ -912,10 +942,11 @@ private void sendExitEventsIfNeeded(int policyFlags) {
912942 *
913943 * @param policyFlags The policy flags associated with the event.
914944 */
915- private void sendEnterEventsIfNeeded (int policyFlags ) {
945+ private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded (int policyFlags ) {
916946 MotionEvent event = mInjectedPointerTracker .getLastInjectedHoverEvent ();
917947 if (event != null && event .getActionMasked () == MotionEvent .ACTION_HOVER_EXIT ) {
918948 final int pointerIdBits = event .getPointerIdBits ();
949+ sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
919950 sendMotionEvent (event , MotionEvent .ACTION_HOVER_ENTER , pointerIdBits , policyFlags );
920951 }
921952 }
@@ -1181,8 +1212,12 @@ public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
11811212 mSendHoverExitDelayed .remove ();
11821213 mPerformLongPressDelayed .remove ();
11831214
1184- // The touch interaction has ended since we will send a click.
1185- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
1215+ if (mSendTouchExplorationEndDelayed .isPending ()) {
1216+ mSendTouchExplorationEndDelayed .forceSendAndRemove ();
1217+ }
1218+ if (mSendTouchInteractionEndDelayed .isPending ()) {
1219+ mSendTouchInteractionEndDelayed .forceSendAndRemove ();
1220+ }
11861221
11871222 int clickLocationX ;
11881223 int clickLocationY ;
@@ -1416,7 +1451,7 @@ public void run() {
14161451 mLongPressingPointerDeltaX = (int ) mEvent .getX (pointerIndex ) - clickLocationX ;
14171452 mLongPressingPointerDeltaY = (int ) mEvent .getY (pointerIndex ) - clickLocationY ;
14181453
1419- sendExitEventsIfNeeded (mPolicyFlags );
1454+ sendHoverExitAndTouchExplorationGestureEndIfNeeded (mPolicyFlags );
14201455
14211456 mCurrentState = STATE_DELEGATING ;
14221457 sendDownForAllActiveNotInjectedPointers (mEvent , mPolicyFlags );
@@ -1445,7 +1480,6 @@ class SendHoverDelayed implements Runnable {
14451480 private MotionEvent mPrototype ;
14461481 private int mPointerIdBits ;
14471482 private int mPolicyFlags ;
1448- private boolean mTouchExplorationInProgress ;
14491483
14501484 public SendHoverDelayed (int hoverAction , boolean gestureStarted ) {
14511485 mHoverAction = hoverAction ;
@@ -1456,7 +1490,6 @@ public void post(MotionEvent prototype, boolean touchExplorationInProgress,
14561490 int pointerIdBits , int policyFlags ) {
14571491 remove ();
14581492 mPrototype = MotionEvent .obtain (prototype );
1459- mTouchExplorationInProgress = touchExplorationInProgress ;
14601493 mPointerIdBits = pointerIdBits ;
14611494 mPolicyFlags = policyFlags ;
14621495 mHandler .postDelayed (this , mDetermineUserIntentTimeout );
@@ -1493,7 +1526,6 @@ private void clear() {
14931526 mPrototype = null ;
14941527 mPointerIdBits = -1 ;
14951528 mPolicyFlags = 0 ;
1496- mTouchExplorationInProgress = false ;
14971529 }
14981530
14991531 public void forceSendAndRemove () {
@@ -1510,37 +1542,37 @@ public void run() {
15101542 Slog .d (LOG_TAG_SEND_HOVER_DELAYED , mGestureStarted ?
15111543 "touchExplorationGestureStarted" : "touchExplorationGestureEnded" );
15121544 }
1513- if (mTouchExplorationInProgress ) {
1514- if (mGestureStarted ) {
1515- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
1516- } else {
1517- mTouchExplorationGestureEnded = true ;
1518- mTouchInteractionEnded = true ;
1519- if (!mSendInteractionEndEventsDelayed .isPending ()) {
1520- mSendInteractionEndEventsDelayed .post ();
1521- }
1522- }
1545+ if (mGestureStarted ) {
1546+ sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_START );
15231547 } else {
1524- if (!mGestureStarted ) {
1525- mTouchInteractionEnded = true ;
1526- if (!mSendInteractionEndEventsDelayed .isPending ()) {
1527- mSendInteractionEndEventsDelayed .post ();
1528- }
1548+ if (!mSendTouchExplorationEndDelayed .isPending ()) {
1549+ mSendTouchExplorationEndDelayed .post ();
1550+ }
1551+ if (mSendTouchInteractionEndDelayed .isPending ()) {
1552+ mSendTouchInteractionEndDelayed .remove ();
1553+ mSendTouchInteractionEndDelayed .post ();
15291554 }
15301555 }
15311556 sendMotionEvent (mPrototype , mHoverAction , mPointerIdBits , mPolicyFlags );
15321557 clear ();
15331558 }
15341559 }
15351560
1536- private class SendInteractionEndEventsDelayed implements Runnable {
1561+ private class SendAccessibilityEventDelayed implements Runnable {
1562+ private final int mEventType ;
1563+ private final int mDelay ;
1564+
1565+ public SendAccessibilityEventDelayed (int eventType , int delay ) {
1566+ mEventType = eventType ;
1567+ mDelay = delay ;
1568+ }
15371569
15381570 public void remove () {
15391571 mHandler .removeCallbacks (this );
15401572 }
15411573
15421574 public void post () {
1543- mHandler .postDelayed (this , SEND_INTERACTION_END_EVENTS_TIMEOUT );
1575+ mHandler .postDelayed (this , mDelay );
15441576 }
15451577
15461578 public boolean isPending () {
@@ -1556,14 +1588,7 @@ public void forceSendAndRemove() {
15561588
15571589 @ Override
15581590 public void run () {
1559- if (mTouchExplorationGestureEnded ) {
1560- mTouchExplorationGestureEnded = false ;
1561- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_EXPLORATION_GESTURE_END );
1562- }
1563- if (mTouchInteractionEnded ) {
1564- mTouchInteractionEnded = false ;
1565- sendAccessibilityEvent (AccessibilityEvent .TYPE_TOUCH_INTERACTION_END );
1566- }
1591+ sendAccessibilityEvent (mEventType );
15671592 }
15681593 }
15691594
0 commit comments