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

Commit 9de95db4 authored by Chris Craik's avatar Chris Craik
Browse files

Replace invalidateChild/invalidateChildInParent

Fixes: 34361503
Test: CTS: android.view.cts.ViewGroupTest
      APCT: android.view.ViewInvalidateTest

Simplify and unify HW accelerated invalidate/damage codepaths, since
both simply walk up to ViewRootImpl and schedule a traversal.

Adds a new overridable method 'onDescendantInvalidated' for observing
subtree rendering updates.

Change-Id: I7ef1f914c3411317692451787b3810b23e019591
parent fffa2eb0
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -44641,8 +44641,8 @@ package android.view {
    method public int getPersistentDrawingCache();
    method public boolean getTouchscreenBlocksFocus();
    method public int indexOfChild(android.view.View);
    method public final void invalidateChild(android.view.View, android.graphics.Rect);
    method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
    method public deprecated boolean isAnimationCacheEnabled();
    method protected boolean isChildrenDrawingOrderEnabled();
@@ -44805,14 +44805,15 @@ package android.view {
    method public abstract android.view.ViewParent getParentForAccessibility();
    method public abstract int getTextAlignment();
    method public abstract int getTextDirection();
    method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract boolean isLayoutDirectionResolved();
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public default void onDescendantInvalidated(android.view.View, android.view.View);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
    method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
+5 −4
Original line number Diff line number Diff line
@@ -47999,8 +47999,8 @@ package android.view {
    method public int getPersistentDrawingCache();
    method public boolean getTouchscreenBlocksFocus();
    method public int indexOfChild(android.view.View);
    method public final void invalidateChild(android.view.View, android.graphics.Rect);
    method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
    method public deprecated boolean isAnimationCacheEnabled();
    method protected boolean isChildrenDrawingOrderEnabled();
@@ -48163,14 +48163,15 @@ package android.view {
    method public abstract android.view.ViewParent getParentForAccessibility();
    method public abstract int getTextAlignment();
    method public abstract int getTextDirection();
    method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract boolean isLayoutDirectionResolved();
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public default void onDescendantInvalidated(android.view.View, android.view.View);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
    method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
+5 −4
Original line number Diff line number Diff line
@@ -44937,8 +44937,8 @@ package android.view {
    method public int getPersistentDrawingCache();
    method public boolean getTouchscreenBlocksFocus();
    method public int indexOfChild(android.view.View);
    method public final void invalidateChild(android.view.View, android.graphics.Rect);
    method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
    method public deprecated boolean isAnimationCacheEnabled();
    method protected boolean isChildrenDrawingOrderEnabled();
@@ -45101,14 +45101,15 @@ package android.view {
    method public abstract android.view.ViewParent getParentForAccessibility();
    method public abstract int getTextAlignment();
    method public abstract int getTextDirection();
    method public abstract void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
    method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
    method public abstract boolean isLayoutDirectionResolved();
    method public abstract boolean isLayoutRequested();
    method public abstract boolean isTextAlignmentResolved();
    method public abstract boolean isTextDirectionResolved();
    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
    method public default void onDescendantInvalidated(android.view.View, android.view.View);
    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
    method public abstract boolean onNestedPreFling(android.view.View, float, float);
    method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
+2 −10
Original line number Diff line number Diff line
@@ -14334,16 +14334,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @hide
     */
    protected void damageInParent() {
        final AttachInfo ai = mAttachInfo;
        final ViewParent p = mParent;
        if (p != null && ai != null) {
            final Rect r = ai.mTmpInvalRect;
            r.set(0, 0, mRight - mLeft, mBottom - mTop);
            if (mParent instanceof ViewGroup) {
                ((ViewGroup) mParent).damageChild(this, r);
            } else {
                mParent.invalidateChild(this, r);
            }
        if (mParent != null && mAttachInfo != null) {
            mParent.onDescendantInvalidated(this, this);
        }
    }
+40 −143
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.view;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;

import android.animation.LayoutTransition;
import android.annotation.CallSuper;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.UiThread;
@@ -5372,100 +5373,60 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
    }

    /**
     * HW-only, Rect-ignoring invalidation path.
     *
     * Returns false if this path was unable to complete successfully. This means
     * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
     * damage area.
     *
     * Hardware acceleration ignores damage rectangles, since native computes damage for everything
     * drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area).
     *
     * Ignores opaque dirty optimizations, always using the full PFLAG_DIRTY flag.
    @Override
    @CallSuper
    public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
        /*
         * HW-only, Rect-ignoring damage codepath
         *
     * Ignores FLAG_OPTIMIZE_INVALIDATE, since we're not computing a rect,
     *         so no point in optimizing that.
     * @hide
         * We don't deal with rectangles here, since RenderThread native code computes damage for
         * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
         */
    public boolean tryInvalidateChildHardware(View child) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo == null || !attachInfo.mHardwareAccelerated) {
            return false;
        }

        // verify it's ViewGroups up to a ViewRootImpl
        ViewRootImpl viewRoot = null;
        ViewParent parent = getParent();
        while (parent != null) {
            if (parent instanceof ViewGroup) {
                parent = parent.getParent();
            } else if (parent instanceof ViewRootImpl) {
                viewRoot = (ViewRootImpl) parent;
                break;
            } else {
                // unknown parent type, abort
                return false;
            }
        }
        if (viewRoot == null) {
            // unable to find ViewRoot
            return false;
        }

        final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;

        if (child.mLayerType != LAYER_TYPE_NONE) {
            mPrivateFlags |= PFLAG_INVALIDATED;
        }

        parent = this;
        do {
            if (parent != viewRoot) {
                // Note: we cast here without checking isinstance, to avoid cost of isinstance again
                ViewGroup viewGroup = (ViewGroup) parent;
                if (drawAnimation) {
                    viewGroup.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
                }
        // if set, combine the animation flag into the parent
        mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);

        if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
            // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
            // optimization in provides in a DisplayList world.
                viewGroup.mPrivateFlags =
                        (viewGroup.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
            mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;

                // simplified invalidateChildInParent behavior: clear cache validity to be safe,
                // and mark inval if in layer
                viewGroup.mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
                if (viewGroup.mLayerType != LAYER_TYPE_NONE) {
                    viewGroup.mPrivateFlags |= PFLAG_INVALIDATED;
                }
            } else {
                if (drawAnimation) {
                    viewRoot.mIsAnimating = true;
            // simplified invalidateChildInParent behavior: clear cache validity to be safe...
            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
        }
                ((ViewRootImpl) parent).invalidate();
                return true;

        // ... and mark inval if in software layer that needs to repaint (hw handled in native)
        if (mLayerType == LAYER_TYPE_SOFTWARE) {
            // Layered parents should be invalidated. Escalate to a full invalidate (and note that
            // we do this after consuming any relevant flags from the originating descendant)
            mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
            target = this;
        }

            parent = parent.getParent();
        } while (parent != null);
        return true;
        if (mParent != null) {
            mParent.onDescendantInvalidated(this, target);
        }
    }


    /**
     * Don't call or override this method. It is used for the implementation of
     * the view hierarchy.
     *
     * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
     * draw state in descendants.
     */
    @Deprecated
    @Override
    public final void invalidateChild(View child, final Rect dirty) {
        if (tryInvalidateChildHardware(child)) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null && attachInfo.mHardwareAccelerated) {
            // HW accelerated fast path
            onDescendantInvalidated(child, child);
            return;
        }

        ViewParent parent = this;

        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            // If the child is drawing an animation, we want to copy this flag onto
            // ourselves and the parent to make sure the invalidate request goes
@@ -5568,7 +5529,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     * This implementation returns null if this ViewGroup does not have a parent,
     * if this ViewGroup is already fully invalidated or if the dirty rectangle
     * does not intersect with this ViewGroup's bounds.
     *
     * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
     * draw state in descendants.
     */
    @Deprecated
    @Override
    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
@@ -5616,74 +5581,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return null;
    }

    /**
     * Native-calculated damage path
     * Returns false if this path was unable to complete successfully. This means
     * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
     * damage area
     * @hide
     */
    public boolean damageChildDeferred() {
        ViewParent parent = getParent();
        while (parent != null) {
            if (parent instanceof ViewGroup) {
                parent = parent.getParent();
            } else if (parent instanceof ViewRootImpl) {
                ((ViewRootImpl) parent).invalidate();
                return true;
            } else {
                parent = null;
            }
        }
        return false;
    }

    /**
     * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
     * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
     * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
     *
     * @hide
     */
    public void damageChild(View child, final Rect dirty) {
        if (damageChildDeferred()) {
            return;
        }

        ViewParent parent = this;

        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            int left = child.mLeft;
            int top = child.mTop;
            if (!child.getMatrix().isIdentity()) {
                child.transformRect(dirty);
            }

            do {
                if (parent instanceof ViewGroup) {
                    ViewGroup parentVG = (ViewGroup) parent;
                    if (parentVG.mLayerType != LAYER_TYPE_NONE) {
                        // Layered parents should be recreated, not just re-issued
                        parentVG.invalidate();
                        parent = null;
                    } else {
                        parent = parentVG.damageChildInParent(left, top, dirty);
                        left = parentVG.mLeft;
                        top = parentVG.mTop;
                    }
                } else {
                    // Reached the top; this calls into the usual invalidate method in
                    // ViewRootImpl, which schedules a traversal
                    final int[] location = attachInfo.mInvalidateChildLocation;
                    location[0] = left;
                    location[1] = top;
                    parent = parent.invalidateChildInParent(location, dirty);
                }
            } while (parent != null);
        }
    }

    /**
     * Quick invalidation method that simply transforms the dirty rect into the parent's
     * coordinate system, pruning the invalidation if the parent has already been invalidated.
Loading