summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-04-19 15:19:19 -0700
committerJeff Brown <jeffbrown@google.com>2012-04-19 15:21:08 -0700
commit59a422e90035ce5df45c526607db2d3303e3112e (patch)
tree21d79b2f13d88b1cf9ef36cac8525e6f05c1c108
parent00710e906bdafd58386ee7f81fa84addd218122f (diff)
downloadframeworks_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.java2
-rw-r--r--core/java/android/view/ViewGroup.java78
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);