diff options
| author | Jeff Brown <jeffbrown@google.com> | 2012-04-19 15:19:19 -0700 |
|---|---|---|
| committer | Jeff Brown <jeffbrown@google.com> | 2012-04-19 15:21:08 -0700 |
| commit | 59a422e90035ce5df45c526607db2d3303e3112e (patch) | |
| tree | 21d79b2f13d88b1cf9ef36cac8525e6f05c1c108 | |
| parent | 00710e906bdafd58386ee7f81fa84addd218122f (diff) | |
| download | frameworks_base-59a422e90035ce5df45c526607db2d3303e3112e.zip frameworks_base-59a422e90035ce5df45c526607db2d3303e3112e.tar.gz frameworks_base-59a422e90035ce5df45c526607db2d3303e3112e.tar.bz2 | |
Ensure that touch and hover targets are cleared when needed.
When views are removed from a view or a view is detached from
a window, we need to update the touch and hover targets appropriately.
Failing to do this resulted in a NPE while dispatching an
ACTION_HOVER_EXIT to a view that had previously been removed.
Removed views should not get input events.
Change-Id: I4af4f8e2c4028347d3f570894fd1b3b366d11455
| -rw-r--r-- | core/java/android/view/View.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 78 |
2 files changed, 79 insertions, 1 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 537c474..ab3413e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -7338,7 +7338,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); // If the window does not have input focus we take away accessibility // focus as soon as the user stop hovering over the view. - if (!mAttachInfo.mHasWindowFocus) { + if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) { getViewRootImpl().setAccessibilityFocusedHost(null); } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 91e945b..1641d4c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1569,6 +1569,43 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return handled; } + private void exitHoverTargets() { + if (mHoveredSelf || mFirstHoverTarget != null) { + final long now = SystemClock.uptimeMillis(); + MotionEvent event = MotionEvent.obtain(now, now, + MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0); + event.setSource(InputDevice.SOURCE_TOUCHSCREEN); + dispatchHoverEvent(event); + event.recycle(); + } + } + + private void cancelHoverTarget(View view) { + HoverTarget predecessor = null; + HoverTarget target = mFirstHoverTarget; + while (target != null) { + final HoverTarget next = target.next; + if (target.child == view) { + if (predecessor == null) { + mFirstHoverTarget = next; + } else { + predecessor.next = next; + } + target.recycle(); + + final long now = SystemClock.uptimeMillis(); + MotionEvent event = MotionEvent.obtain(now, now, + MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0); + event.setSource(InputDevice.SOURCE_TOUCHSCREEN); + view.dispatchHoverEvent(event); + event.recycle(); + return; + } + predecessor = target; + target = next; + } + } + /** @hide */ @Override protected boolean hasHoveredChild() { @@ -1997,6 +2034,32 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + private void cancelTouchTarget(View view) { + TouchTarget predecessor = null; + TouchTarget target = mFirstTouchTarget; + while (target != null) { + final TouchTarget next = target.next; + if (target.child == view) { + if (predecessor == null) { + mFirstTouchTarget = next; + } else { + predecessor.next = next; + } + target.recycle(); + + final long now = SystemClock.uptimeMillis(); + MotionEvent event = MotionEvent.obtain(now, now, + MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); + event.setSource(InputDevice.SOURCE_TOUCHSCREEN); + view.dispatchTouchEvent(event); + event.recycle(); + return; + } + predecessor = target; + target = next; + } + } + /** * Returns true if a child view can receive pointer events. * @hide @@ -2416,6 +2479,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // first send it an ACTION_CANCEL motion event. cancelAndClearTouchTargets(null); + // Similarly, set ACTION_EXIT to all hover targets and clear them. + exitHoverTargets(); + // In case view is detached while transition is running mLayoutSuppressed = false; @@ -3453,6 +3519,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = true; } + cancelTouchTarget(view); + cancelHoverTarget(view); + if (view.getAnimation() != null || (mTransitioningViews != null && mTransitioningViews.contains(view))) { addDisappearingView(view); @@ -3533,6 +3602,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = view; } + cancelTouchTarget(view); + cancelHoverTarget(view); + if (view.getAnimation() != null || (mTransitioningViews != null && mTransitioningViews.contains(view))) { addDisappearingView(view); @@ -3603,6 +3675,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = view; } + cancelTouchTarget(view); + cancelHoverTarget(view); + if (view.getAnimation() != null || (mTransitioningViews != null && mTransitioningViews.contains(view))) { addDisappearingView(view); @@ -3648,6 +3723,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.clearFocus(); } + cancelTouchTarget(child); + cancelHoverTarget(child); + if ((animate && child.getAnimation() != null) || (mTransitioningViews != null && mTransitioningViews.contains(child))) { addDisappearingView(child); |
