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

Commit 149b7c24 authored by Tiger's avatar Tiger
Browse files

Don't skip clearing measure cache of ancestors

Otherwise, the measure cache of ancestor views can be stale.

The measure cache is cleared when requestLayout is called. The previous
logic might stop calling requestLayout to the parent view if the request
has been made, which would stop clearing measure cache of ancestors
unexpectedly.

This CL continues clearing the measure cache of ancestors if a view
stops calling requestLayout to its parent.

Fix: 381512167
Flag: EXEMPT bugfix
Test: atest ViewGroupTest WindowMagnificationSettingsTest
      TaplPrivateSpaceNexusTest TaplPrivateSpaceTest
Change-Id: I824adbc769b58075c307b7c23ccb6f8143521b01
parent 0f5e234f
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -28277,14 +28277,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;
        if (mParent != null && !mParent.isLayoutRequested()) {
        if (mParent != null) {
            if (!mParent.isLayoutRequested()) {
                mParent.requestLayout();
            } else {
                clearMeasureCacheOfAncestors();
            }
        }
        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
            mAttachInfo.mViewRequestingLayout = null;
        }
    }
    private void clearMeasureCacheOfAncestors() {
        ViewParent parent = mParent;
        while (parent instanceof View view) {
            if (view.mMeasureCache != null) {
                view.mMeasureCache.clear();
            }
            parent = view.mParent;
        }
    }
    /**
     * Forces this view to be laid out during the next layout pass.
     * This method does not call requestLayout() or forceLayout()
@@ -28640,9 +28654,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    @RemotableViewMethod
    public void setMinimumHeight(int minHeight) {
        if (mMinHeight != minHeight) {
            mMinHeight = minHeight;
            requestLayout();
        }
    }
    /**
     * Returns the minimum width of the view.
@@ -28671,8 +28687,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    @RemotableViewMethod
    public void setMinimumWidth(int minWidth) {
        if (mMinWidth != minWidth) {
            mMinWidth = minWidth;
            requestLayout();
        }
    }
+42 −0
Original line number Diff line number Diff line
@@ -213,6 +213,35 @@ public class ViewGroupTest {
        assertTrue(autofillableViews.containsAll(Arrays.asList(viewA, viewC)));
    }

    @Test
    public void testMeasureCache() {
        final int spec1 = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST);
        final int spec2 = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
        final Context context = getInstrumentation().getContext();
        final View child = new View(context);
        final TestView parent = new TestView(context, 0);
        parent.addView(child);

        child.setPadding(1, 2, 3, 4);
        parent.measure(spec1, spec1);
        assertEquals(4, parent.getMeasuredWidth());
        assertEquals(6, parent.getMeasuredHeight());

        child.setPadding(5, 6, 7, 8);
        parent.measure(spec2, spec2);
        assertEquals(12, parent.getMeasuredWidth());
        assertEquals(14, parent.getMeasuredHeight());

        // This ends the state of forceLayout.
        parent.layout(0, 0, 50, 50);

        // The cached values should be cleared after the new setPadding is called. And the measured
        // width and height should be up-to-date.
        parent.measure(spec1, spec1);
        assertEquals(12, parent.getMeasuredWidth());
        assertEquals(14, parent.getMeasuredHeight());
    }

    private static void getUnobscuredTouchableRegion(Region outRegion, View view) {
        outRegion.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
        final ViewParent parent = view.getParent();
@@ -240,6 +269,19 @@ public class ViewGroupTest {
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            // We don't layout this view.
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int measuredWidth = 0;
            int measuredHeight = 0;
            final int count = getChildCount();
            for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                measuredWidth += child.getPaddingLeft() + child.getPaddingRight();
                measuredHeight += child.getPaddingTop() + child.getPaddingBottom();
            }
            setMeasuredDimension(measuredWidth, measuredHeight);
        }
    }

    public static class AutofillableTestView extends TestView {