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

Commit 11335f14 authored by Adam Powell's avatar Adam Powell Committed by Vinod Krishnan
Browse files

DO NOT MERGE Cherry picking 3 CLs to fix CTS testFitSystemWindows

```-:frontmatter
Explicitly track consumed state for WindowInsets

Treating 0-insets as fully consumed is incorrect since it means that
you can't dispatch empty insets down the view hierarchy - traversal
terminates immediately. Track consumed state independent of actual
values. Replacing a given set of insets with all zeroes will mark it
consumed.
----
Fix incorrect dispatch of empty WindowInsets from ActionBarOverlayLayout

Fix a bug where ActionBarOverlayLayout was using a private constructor
of WindowInsets to return empty insets that should have been marked
fully consumed. This caused dispatch to further child views not to
stop appropriately, corrupting application layout in some cases.
```
Fix CTS regression in fitSystemWindows

Don't attempt to apply null insets from a call to fitSystemWindows.
Immediately return false since null insets cannot be applied.
----

Bug: 15452706
Change-Id: I34276a90305b141b4653aef0048f70350c69d02a
parent dd5c9471
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -5923,12 +5923,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
     */
    protected boolean fitSystemWindows(Rect insets) {
    protected boolean fitSystemWindows(Rect insets) {
        if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
        if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
            if (insets == null) {
                // Null insets by definition have already been consumed.
                // This call cannot apply insets since there are none to apply,
                // so return false.
                return false;
            }
            // If we're not in the process of dispatching the newer apply insets call,
            // If we're not in the process of dispatching the newer apply insets call,
            // that means we're not in the compatibility path. Dispatch into the newer
            // that means we're not in the compatibility path. Dispatch into the newer
            // apply insets path and take things from there.
            // apply insets path and take things from there.
            try {
            try {
                mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
                mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
                return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
                return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
            } finally {
            } finally {
                mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
                mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
            }
            }
+2 −2
Original line number Original line Diff line number Diff line
@@ -5433,11 +5433,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @Override
    @Override
    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
        insets = super.dispatchApplyWindowInsets(insets);
        insets = super.dispatchApplyWindowInsets(insets);
        if (insets.hasInsets()) {
        if (!insets.isConsumed()) {
            final int count = getChildCount();
            final int count = getChildCount();
            for (int i = 0; i < count; i++) {
            for (int i = 0; i < count; i++) {
                insets = getChildAt(i).dispatchApplyWindowInsets(insets);
                insets = getChildAt(i).dispatchApplyWindowInsets(insets);
                if (!insets.hasInsets()) {
                if (insets.isConsumed()) {
                    break;
                    break;
                }
                }
            }
            }
+47 −7
Original line number Original line Diff line number Diff line
@@ -35,6 +35,9 @@ public final class WindowInsets {
    private Rect mTempRect;
    private Rect mTempRect;
    private boolean mIsRound;
    private boolean mIsRound;


    private boolean mSystemWindowInsetsConsumed = false;
    private boolean mWindowDecorInsetsConsumed = false;

    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);


    /**
    /**
@@ -43,7 +46,13 @@ public final class WindowInsets {
     * since it would allow them to inadvertently consume unknown insets by returning it.
     * since it would allow them to inadvertently consume unknown insets by returning it.
     * @hide
     * @hide
     */
     */
    public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
    public static final WindowInsets CONSUMED;

    static {
        CONSUMED = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
        CONSUMED.mSystemWindowInsetsConsumed = true;
        CONSUMED.mWindowDecorInsetsConsumed = true;
    }


    /** @hide */
    /** @hide */
    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
@@ -52,13 +61,17 @@ public final class WindowInsets {


    /** @hide */
    /** @hide */
    public WindowInsets(Rect systemWindowInsets, boolean isRound) {
    public WindowInsets(Rect systemWindowInsets, boolean isRound) {
        this(systemWindowInsets, EMPTY_RECT, isRound);
        this(systemWindowInsets, null, isRound);
    }
    }


    /** @hide */
    /** @hide */
    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
        mSystemWindowInsets = systemWindowInsets;
        mSystemWindowInsetsConsumed = systemWindowInsets == null;
        mWindowDecorInsets = windowDecorInsets;
        mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;

        mWindowDecorInsetsConsumed = windowDecorInsets == null;
        mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;

        mIsRound = isRound;
        mIsRound = isRound;
    }
    }


@@ -70,12 +83,14 @@ public final class WindowInsets {
    public WindowInsets(WindowInsets src) {
    public WindowInsets(WindowInsets src) {
        mSystemWindowInsets = src.mSystemWindowInsets;
        mSystemWindowInsets = src.mSystemWindowInsets;
        mWindowDecorInsets = src.mWindowDecorInsets;
        mWindowDecorInsets = src.mWindowDecorInsets;
        mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
        mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
        mIsRound = src.mIsRound;
        mIsRound = src.mIsRound;
    }
    }


    /** @hide */
    /** @hide */
    public WindowInsets(Rect systemWindowInsets) {
    public WindowInsets(Rect systemWindowInsets) {
        this(systemWindowInsets, EMPTY_RECT);
        this(systemWindowInsets, null);
    }
    }


    /**
    /**
@@ -242,6 +257,24 @@ public final class WindowInsets {
        return hasSystemWindowInsets() || hasWindowDecorInsets();
        return hasSystemWindowInsets() || hasWindowDecorInsets();
    }
    }


    /**
     * Check if these insets have been fully consumed.
     *
     * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
     * have been called such that all insets have been set to zero. This affects propagation of
     * insets through the view hierarchy; insets that have not been fully consumed will continue
     * to propagate down to child views.</p>
     *
     * <p>The result of this method is equivalent to the return value of
     * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
     *
     * @return true if the insets have been fully consumed.
     * @hide Pending API
     */
    public boolean isConsumed() {
        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed;
    }

    /**
    /**
     * Returns true if the associated window has a round shape.
     * Returns true if the associated window has a round shape.
     *
     *
@@ -263,7 +296,8 @@ public final class WindowInsets {
     */
     */
    public WindowInsets consumeSystemWindowInsets() {
    public WindowInsets consumeSystemWindowInsets() {
        final WindowInsets result = new WindowInsets(this);
        final WindowInsets result = new WindowInsets(this);
        result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
        result.mSystemWindowInsets = EMPTY_RECT;
        result.mSystemWindowInsetsConsumed = true;
        return result;
        return result;
    }
    }


@@ -281,10 +315,12 @@ public final class WindowInsets {
            boolean right, boolean bottom) {
            boolean right, boolean bottom) {
        if (left || top || right || bottom) {
        if (left || top || right || bottom) {
            final WindowInsets result = new WindowInsets(this);
            final WindowInsets result = new WindowInsets(this);
            result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
            result.mSystemWindowInsets = new Rect(
                    left ? 0 : mSystemWindowInsets.left,
                    top ? 0 : mSystemWindowInsets.top,
                    top ? 0 : mSystemWindowInsets.top,
                    right ? 0 : mSystemWindowInsets.right,
                    right ? 0 : mSystemWindowInsets.right,
                    bottom ? 0 : mSystemWindowInsets.bottom);
                    bottom ? 0 : mSystemWindowInsets.bottom);
            result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
            return result;
            return result;
        }
        }
        return this;
        return this;
@@ -304,6 +340,7 @@ public final class WindowInsets {
            int right, int bottom) {
            int right, int bottom) {
        final WindowInsets result = new WindowInsets(this);
        final WindowInsets result = new WindowInsets(this);
        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
        result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
        return result;
        return result;
    }
    }


@@ -313,6 +350,7 @@ public final class WindowInsets {
    public WindowInsets consumeWindowDecorInsets() {
    public WindowInsets consumeWindowDecorInsets() {
        final WindowInsets result = new WindowInsets(this);
        final WindowInsets result = new WindowInsets(this);
        result.mWindowDecorInsets.set(0, 0, 0, 0);
        result.mWindowDecorInsets.set(0, 0, 0, 0);
        result.mWindowDecorInsetsConsumed = true;
        return result;
        return result;
    }
    }


@@ -327,6 +365,7 @@ public final class WindowInsets {
                    top ? 0 : mWindowDecorInsets.top,
                    top ? 0 : mWindowDecorInsets.top,
                    right ? 0 : mWindowDecorInsets.right,
                    right ? 0 : mWindowDecorInsets.right,
                    bottom ? 0 : mWindowDecorInsets.bottom);
                    bottom ? 0 : mWindowDecorInsets.bottom);
            result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
            return result;
            return result;
        }
        }
        return this;
        return this;
@@ -338,6 +377,7 @@ public final class WindowInsets {
    public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
    public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
        final WindowInsets result = new WindowInsets(this);
        final WindowInsets result = new WindowInsets(this);
        result.mWindowDecorInsets = new Rect(left, top, right, bottom);
        result.mWindowDecorInsets = new Rect(left, top, right, bottom);
        result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
        return result;
        return result;
    }
    }


+9 −1
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.internal.widget;
package com.android.internal.widget;


import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build;
@@ -134,6 +135,13 @@ public class ActionBarOverlayLayout extends ViewGroup {
        }
        }
    }
    }


    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        init(getContext());
        requestApplyInsets();
    }

    @Override
    @Override
    public void onWindowSystemUiVisibilityChanged(int visible) {
    public void onWindowSystemUiVisibilityChanged(int visible) {
        super.onWindowSystemUiVisibilityChanged(visible);
        super.onWindowSystemUiVisibilityChanged(visible);
@@ -219,7 +227,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
        // insets in all cases, we need to know the measured size of the various action
        // insets in all cases, we need to know the measured size of the various action
        // bar elements.  onApplyWindowInsets() happens before the measure pass, so we can't
        // bar elements.  onApplyWindowInsets() happens before the measure pass, so we can't
        // do that here.  Instead we will take this up in onMeasure().
        // do that here.  Instead we will take this up in onMeasure().
        return WindowInsets.EMPTY;
        return WindowInsets.CONSUMED;
    }
    }


    @Override
    @Override