Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7b85e68 authored by Alan Viverette's avatar Alan Viverette
Browse files

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
parent b7cc096f
Loading
Loading
Loading
Loading
+85 −38
Original line number Diff line number Diff line
@@ -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) {
@@ -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;