@@ -1569,6 +1569,43 @@ protected boolean dispatchHoverEvent(MotionEvent event) {
15691569 return handled ;
15701570 }
15711571
1572+ private void exitHoverTargets () {
1573+ if (mHoveredSelf || mFirstHoverTarget != null ) {
1574+ final long now = SystemClock .uptimeMillis ();
1575+ MotionEvent event = MotionEvent .obtain (now , now ,
1576+ MotionEvent .ACTION_HOVER_EXIT , 0.0f , 0.0f , 0 );
1577+ event .setSource (InputDevice .SOURCE_TOUCHSCREEN );
1578+ dispatchHoverEvent (event );
1579+ event .recycle ();
1580+ }
1581+ }
1582+
1583+ private void cancelHoverTarget (View view ) {
1584+ HoverTarget predecessor = null ;
1585+ HoverTarget target = mFirstHoverTarget ;
1586+ while (target != null ) {
1587+ final HoverTarget next = target .next ;
1588+ if (target .child == view ) {
1589+ if (predecessor == null ) {
1590+ mFirstHoverTarget = next ;
1591+ } else {
1592+ predecessor .next = next ;
1593+ }
1594+ target .recycle ();
1595+
1596+ final long now = SystemClock .uptimeMillis ();
1597+ MotionEvent event = MotionEvent .obtain (now , now ,
1598+ MotionEvent .ACTION_HOVER_EXIT , 0.0f , 0.0f , 0 );
1599+ event .setSource (InputDevice .SOURCE_TOUCHSCREEN );
1600+ view .dispatchHoverEvent (event );
1601+ event .recycle ();
1602+ return ;
1603+ }
1604+ predecessor = target ;
1605+ target = next ;
1606+ }
1607+ }
1608+
15721609 /** @hide */
15731610 @ Override
15741611 protected boolean hasHoveredChild () {
@@ -1997,6 +2034,32 @@ private void removePointersFromTouchTargets(int pointerIdBits) {
19972034 }
19982035 }
19992036
2037+ private void cancelTouchTarget (View view ) {
2038+ TouchTarget predecessor = null ;
2039+ TouchTarget target = mFirstTouchTarget ;
2040+ while (target != null ) {
2041+ final TouchTarget next = target .next ;
2042+ if (target .child == view ) {
2043+ if (predecessor == null ) {
2044+ mFirstTouchTarget = next ;
2045+ } else {
2046+ predecessor .next = next ;
2047+ }
2048+ target .recycle ();
2049+
2050+ final long now = SystemClock .uptimeMillis ();
2051+ MotionEvent event = MotionEvent .obtain (now , now ,
2052+ MotionEvent .ACTION_CANCEL , 0.0f , 0.0f , 0 );
2053+ event .setSource (InputDevice .SOURCE_TOUCHSCREEN );
2054+ view .dispatchTouchEvent (event );
2055+ event .recycle ();
2056+ return ;
2057+ }
2058+ predecessor = target ;
2059+ target = next ;
2060+ }
2061+ }
2062+
20002063 /**
20012064 * Returns true if a child view can receive pointer events.
20022065 * @hide
@@ -2416,6 +2479,9 @@ void dispatchDetachedFromWindow() {
24162479 // first send it an ACTION_CANCEL motion event.
24172480 cancelAndClearTouchTargets (null );
24182481
2482+ // Similarly, set ACTION_EXIT to all hover targets and clear them.
2483+ exitHoverTargets ();
2484+
24192485 // In case view is detached while transition is running
24202486 mLayoutSuppressed = false ;
24212487
@@ -3453,6 +3519,9 @@ private void removeViewInternal(int index, View view) {
34533519 clearChildFocus = true ;
34543520 }
34553521
3522+ cancelTouchTarget (view );
3523+ cancelHoverTarget (view );
3524+
34563525 if (view .getAnimation () != null ||
34573526 (mTransitioningViews != null && mTransitioningViews .contains (view ))) {
34583527 addDisappearingView (view );
@@ -3533,6 +3602,9 @@ private void removeViewsInternal(int start, int count) {
35333602 clearChildFocus = view ;
35343603 }
35353604
3605+ cancelTouchTarget (view );
3606+ cancelHoverTarget (view );
3607+
35363608 if (view .getAnimation () != null ||
35373609 (mTransitioningViews != null && mTransitioningViews .contains (view ))) {
35383610 addDisappearingView (view );
@@ -3603,6 +3675,9 @@ public void removeAllViewsInLayout() {
36033675 clearChildFocus = view ;
36043676 }
36053677
3678+ cancelTouchTarget (view );
3679+ cancelHoverTarget (view );
3680+
36063681 if (view .getAnimation () != null ||
36073682 (mTransitioningViews != null && mTransitioningViews .contains (view ))) {
36083683 addDisappearingView (view );
@@ -3648,6 +3723,9 @@ protected void removeDetachedView(View child, boolean animate) {
36483723 child .clearFocus ();
36493724 }
36503725
3726+ cancelTouchTarget (child );
3727+ cancelHoverTarget (child );
3728+
36513729 if ((animate && child .getAnimation () != null ) ||
36523730 (mTransitioningViews != null && mTransitioningViews .contains (child ))) {
36533731 addDisappearingView (child );
0 commit comments