diff options
| author | 2016-01-22 10:14:02 -0500 | |
|---|---|---|
| committer | 2016-01-22 10:14:02 -0500 | |
| commit | a7b85e6855fa8474a002b0bcce62ab988c3636a9 (patch) | |
| tree | 7bf97891be6b8a14e49787dc8d695c22b5de07ba | |
| parent | b7cc096fd49e99c01a9e963a895f6d26d685e474 (diff) | |
Verify results of methods called during child ordering
Also updates nullability annotations for methods called during touch
dispatch. Verifies that TouchTarget and HoverTarget are not recycled
multiple times.
Bug: 26611563
Change-Id: Ica5ff18e18b325b12fe72b8ca145443b25625fe4
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 123 |
1 files changed, 85 insertions, 38 deletions
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 868dddaa0270..fbe4c5d41941 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1653,10 +1653,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1; i >= 0; i--) { - final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); - PointF point = getLocalPoint(); + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + final PointF point = getLocalPoint(); if (isTransformedTouchPointInView(x, y, child, point)) { final PointerIcon pointerIcon = child.getPointerIcon(event, point.x, point.y); if (pointerIcon != null) { @@ -1672,6 +1671,22 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return super.getPointerIcon(event, x, y); } + private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) { + final int childIndex; + if (customOrder) { + final int childIndex1 = getChildDrawingOrder(childrenCount, i); + if (childIndex1 >= childrenCount) { + throw new IndexOutOfBoundsException("getChildDrawingOrder() " + + "returned invalid index " + childIndex1 + + " (child count is " + childrenCount + ")"); + } + childIndex = childIndex1; + } else { + childIndex = i; + } + return childIndex; + } + @SuppressWarnings({"ConstantConditions"}) @Override protected boolean dispatchHoverEvent(MotionEvent event) { @@ -1699,9 +1714,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final View[] children = mChildren; HoverTarget lastHoverTarget = null; for (int i = childrenCount - 1; i >= 0; i--) { - int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); + final int childIndex = getAndVerifyPreorderedIndex( + childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView( + preorderedList, children, childIndex); if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; @@ -1983,9 +1999,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1; i >= 0; i--) { - int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; @@ -2132,10 +2147,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1; i >= 0; i--) { - final int childIndex = customOrder - ? getChildDrawingOrder(childrenCount, i) : i; - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); + final int childIndex = getAndVerifyPreorderedIndex( + childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView( + preorderedList, children, childIndex); // If there is a view that has accessibility focus we want it // to get the event first and if not handled we will perform a @@ -2313,7 +2328,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Resets the cancel next up flag. * Returns true if the flag was previously set. */ - private static boolean resetCancelNextUpFlag(View view) { + private static boolean resetCancelNextUpFlag(@NonNull View view) { if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) { view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; return true; @@ -2366,7 +2381,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Gets the touch target for specified child view. * Returns null if not found. */ - private TouchTarget getTouchTarget(View child) { + private TouchTarget getTouchTarget(@NonNull View child) { for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) { if (target.child == child) { return target; @@ -2379,8 +2394,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Adds a touch target for specified child to the beginning of the list. * Assumes the target child is not already present. */ - private TouchTarget addTouchTarget(View child, int pointerIdBits) { - TouchTarget target = TouchTarget.obtain(child, pointerIdBits); + private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) { + final TouchTarget target = TouchTarget.obtain(child, pointerIdBits); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target; @@ -2442,7 +2457,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Returns true if a child view can receive pointer events. * @hide */ - private static boolean canViewReceivePointerEvents(View child) { + private static boolean canViewReceivePointerEvents(@NonNull View child) { return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null; } @@ -2888,7 +2903,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i=0; i<childrenCount; i++) { int childIndex; try { - childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; + childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); } catch (IndexOutOfBoundsException e) { childIndex = i; if (mContext.getApplicationInfo().targetSdkVersion @@ -2933,9 +2948,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw e; } } - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); - ViewStructure cstructure = structure.newChild(i); + + final View child = getAndVerifyPreorderedView( + preorderedList, children, childIndex); + final ViewStructure cstructure = structure.newChild(i); child.dispatchProvideStructure(cstructure); } } @@ -2943,6 +2959,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children, + int childIndex) { + final View child; + if (preorderedList != null) { + child = preorderedList.get(childIndex); + if (child == null) { + throw new RuntimeException("Invalid preorderedList contained null child at index " + + childIndex); + } + } else { + child = children[childIndex]; + } + return child; + } + /** @hide */ @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { @@ -3380,9 +3411,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager transientIndex = -1; } } - int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; - final View child = (preorderedList == null) - ? children[childIndex] : preorderedList.get(childIndex); + + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } @@ -3502,21 +3533,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * children. */ ArrayList<View> buildOrderedChildList() { - final int count = mChildrenCount; - if (count <= 1 || !hasChildWithZ()) return null; + final int childrenCount = mChildrenCount; + if (childrenCount <= 1 || !hasChildWithZ()) return null; if (mPreSortedChildren == null) { - mPreSortedChildren = new ArrayList<View>(count); + mPreSortedChildren = new ArrayList<>(childrenCount); } else { - mPreSortedChildren.ensureCapacity(count); + mPreSortedChildren.ensureCapacity(childrenCount); } - final boolean useCustomOrder = isChildrenDrawingOrderEnabled(); - for (int i = 0; i < mChildrenCount; i++) { + final boolean customOrder = isChildrenDrawingOrderEnabled(); + for (int i = 0; i < childrenCount; i++) { // add next child (in child order) to end of list - int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i; - View nextChild = mChildren[childIndex]; - float currentZ = nextChild.getZ(); + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View nextChild = mChildren[childIndex]; + final float currentZ = nextChild.getZ(); // insert ahead of any Views with greater Z int insertIndex = i; @@ -7475,7 +7506,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private TouchTarget() { } - public static TouchTarget obtain(View child, int pointerIdBits) { + public static TouchTarget obtain(@NonNull View child, int pointerIdBits) { + if (child == null) { + throw new IllegalArgumentException("child must be non-null"); + } + final TouchTarget target; synchronized (sRecycleLock) { if (sRecycleBin == null) { @@ -7493,6 +7528,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } public void recycle() { + if (child == null) { + throw new IllegalStateException("already recycled once"); + } + synchronized (sRecycleLock) { if (sRecycledCount < MAX_RECYCLED) { next = sRecycleBin; @@ -7522,7 +7561,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private HoverTarget() { } - public static HoverTarget obtain(View child) { + public static HoverTarget obtain(@NonNull View child) { + if (child == null) { + throw new IllegalArgumentException("child must be non-null"); + } + final HoverTarget target; synchronized (sRecycleLock) { if (sRecycleBin == null) { @@ -7530,7 +7573,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } else { target = sRecycleBin; sRecycleBin = target.next; - sRecycledCount--; + sRecycledCount--; target.next = null; } } @@ -7539,6 +7582,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } public void recycle() { + if (child == null) { + throw new IllegalStateException("already recycled once"); + } + synchronized (sRecycleLock) { if (sRecycledCount < MAX_RECYCLED) { next = sRecycleBin; |