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

Commit 507dca83 authored by Jorge Gil's avatar Jorge Gil
Browse files

Add FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR

Adds the flag to the InsetsSource created by the caption bar in shell,
and makes the DecorView consume the caption bar insets when set,
regardless of whether the caption bar is hidden or shown, as long as the
window is requesting opaque caption bars (i.e. did not set
APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND)

Bug: 352563889
Flag: com.android.window.flags.enable_caption_compat_inset_force_consumption_always
Test: open non-immersive apps in freeform that don't handle caption bar
insets (Naver App, Spotify or OneDrive), check caption doesn't overlap
with app content
Test: atest DesktopModeWindowDecorationTests WindowDecorationTests
WindowInsetsTest InsetStateTest

Change-Id: Idb16f647f6a77e04b634e700b5345335b24d284d
parent 36a3e6e7
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -104,12 +104,23 @@ public class InsetsSource implements Parcelable {
     */
    public static final int FLAG_ANIMATE_RESIZING = 1 << 3;

    /**
     * Controls whether the {@link WindowInsets.Type#captionBar()} insets provided by this source
     * should always be forcibly consumed. Unlike with {@link #FLAG_FORCE_CONSUMING}, when this
     * flag is used the caption bar will be consumed even when the bar is requested to be visible.
     *
     * Note: this flag does not take effect when the window applies
     * {@link WindowInsetsController.Appearance#APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND}.
     */
    public static final int FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR = 1 << 4;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = "FLAG_", value = {
            FLAG_SUPPRESS_SCRIM,
            FLAG_INSETS_ROUNDED_CORNER,
            FLAG_FORCE_CONSUMING,
            FLAG_ANIMATE_RESIZING,
            FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR
    })
    public @interface Flags {}

@@ -555,6 +566,9 @@ public class InsetsSource implements Parcelable {
        if ((flags & FLAG_ANIMATE_RESIZING) != 0) {
            joiner.add("ANIMATE_RESIZING");
        }
        if ((flags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) {
            joiner.add("FORCE_CONSUMING_OPAQUE_CAPTION_BAR");
        }
        return joiner.toString();
    }

+13 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.view;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.util.SequenceUtils.getInitSeq;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
import static android.view.InsetsStateProto.DISPLAY_FRAME;
@@ -54,6 +55,7 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;

import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;

import java.io.PrintWriter;
import java.util.Objects;
@@ -131,18 +133,25 @@ public class InsetsState implements Parcelable {
        final Rect relativeFrame = new Rect(frame);
        final Rect relativeFrameMax = new Rect(frame);
        @InsetsType int forceConsumingTypes = 0;
        boolean forceConsumingOpaqueCaptionBar = false;
        @InsetsType int suppressScrimTypes = 0;
        final Rect[][] typeBoundingRectsMap = new Rect[Type.SIZE][];
        final Rect[][] typeMaxBoundingRectsMap = new Rect[Type.SIZE][];
        for (int i = mSources.size() - 1; i >= 0; i--) {
            final InsetsSource source = mSources.valueAt(i);
            final @InsetsType int type = source.getType();
            final @InsetsSource.Flags int flags = source.getFlags();

            if ((source.getFlags() & InsetsSource.FLAG_FORCE_CONSUMING) != 0) {
            if ((flags & InsetsSource.FLAG_FORCE_CONSUMING) != 0) {
                forceConsumingTypes |= type;
            }

            if ((source.getFlags() & InsetsSource.FLAG_SUPPRESS_SCRIM) != 0) {
            if (Flags.enableCaptionCompatInsetForceConsumptionAlways()
                    && (flags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) {
                forceConsumingOpaqueCaptionBar = true;
            }

            if ((flags & InsetsSource.FLAG_SUPPRESS_SCRIM) != 0) {
                suppressScrimTypes |= type;
            }

@@ -177,7 +186,8 @@ public class InsetsState implements Parcelable {
        }

        return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
                forceConsumingTypes, suppressScrimTypes, calculateRelativeCutout(frame),
                forceConsumingTypes, forceConsumingOpaqueCaptionBar, suppressScrimTypes,
                calculateRelativeCutout(frame),
                calculateRelativeRoundedCorners(frame),
                calculateRelativePrivacyIndicatorBounds(frame),
                calculateRelativeDisplayShape(frame),
+41 −15
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ public final class WindowInsets {
    private final int mFrameHeight;

    private final @InsetsType int mForceConsumingTypes;
    private final boolean mForceConsumingOpaqueCaptionBar;
    private final @InsetsType int mSuppressScrimTypes;
    private final boolean mSystemWindowInsetsConsumed;
    private final boolean mStableInsetsConsumed;
@@ -123,7 +124,7 @@ public final class WindowInsets {

    static {
        CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
                createCompatVisibilityMap(createCompatTypeMap(null)), false, 0, 0, null,
                createCompatVisibilityMap(createCompatTypeMap(null)), false, 0, false, 0, null,
                null, null, null, systemBars(), false, null, null, 0, 0);
    }

@@ -144,6 +145,7 @@ public final class WindowInsets {
            boolean[] typeVisibilityMap,
            boolean isRound,
            @InsetsType int forceConsumingTypes,
            boolean forceConsumingOpaqueCaptionBar,
            @InsetsType int suppressScrimTypes,
            DisplayCutout displayCutout,
            RoundedCorners roundedCorners,
@@ -166,6 +168,7 @@ public final class WindowInsets {
        mTypeVisibilityMap = typeVisibilityMap;
        mIsRound = isRound;
        mForceConsumingTypes = forceConsumingTypes;
        mForceConsumingOpaqueCaptionBar = forceConsumingOpaqueCaptionBar;
        mSuppressScrimTypes = suppressScrimTypes;
        mCompatInsetsTypes = compatInsetsTypes;
        mCompatIgnoreVisibility = compatIgnoreVisibility;
@@ -196,7 +199,9 @@ public final class WindowInsets {
        this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
                src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
                src.mTypeVisibilityMap, src.mIsRound,
                src.mForceConsumingTypes, src.mSuppressScrimTypes,
                src.mForceConsumingTypes,
                src.mForceConsumingOpaqueCaptionBar,
                src.mSuppressScrimTypes,
                displayCutoutCopyConstructorArgument(src),
                src.mRoundedCorners,
                src.mPrivacyIndicatorBounds,
@@ -257,7 +262,7 @@ public final class WindowInsets {
    /** @hide */
    @UnsupportedAppUsage
    public WindowInsets(Rect systemWindowInsets) {
        this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, 0, 0,
        this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, 0, false, 0,
                null, null, null, null, systemBars(), false /* compatIgnoreVisibility */,
                new Rect[SIZE][], null, 0, 0);
    }
@@ -675,10 +680,10 @@ public final class WindowInsets {
        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
                mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                mTypeVisibilityMap,
                mIsRound, mForceConsumingTypes, mSuppressScrimTypes,
                null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape,
                mCompatInsetsTypes, mCompatIgnoreVisibility,
                mSystemWindowInsetsConsumed ? null : mTypeBoundingRectsMap,
                mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
                mSuppressScrimTypes, null /* displayCutout */, mRoundedCorners,
                mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
                mCompatIgnoreVisibility, mSystemWindowInsetsConsumed ? null : mTypeBoundingRectsMap,
                mStableInsetsConsumed ? null : mTypeMaxBoundingRectsMap,
                mFrameWidth, mFrameHeight);
    }
@@ -729,7 +734,8 @@ public final class WindowInsets {
    public WindowInsets consumeSystemWindowInsets() {
        return new WindowInsets(null, null,
                mTypeVisibilityMap,
                mIsRound, mForceConsumingTypes, mSuppressScrimTypes,
                mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
                mSuppressScrimTypes,
                // If the system window insets types contain displayCutout, we should also consume
                // it.
                (mCompatInsetsTypes & displayCutout()) != 0
@@ -1021,6 +1027,13 @@ public final class WindowInsets {
        return mForceConsumingTypes;
    }

    /**
     * @hide
     */
    public boolean isForceConsumingOpaqueCaptionBar() {
        return mForceConsumingOpaqueCaptionBar;
    }

    /**
     * @hide
     */
@@ -1058,6 +1071,8 @@ public final class WindowInsets {
        result.append("\n    ");
        result.append("forceConsumingTypes=" + Type.toString(mForceConsumingTypes));
        result.append("\n    ");
        result.append("forceConsumingOpaqueCaptionBar=" + mForceConsumingOpaqueCaptionBar);
        result.append("\n    ");
        result.append("suppressScrimTypes=" + Type.toString(mSuppressScrimTypes));
        result.append("\n    ");
        result.append("compatInsetsTypes=" + Type.toString(mCompatInsetsTypes));
@@ -1180,7 +1195,8 @@ public final class WindowInsets {
                        ? null
                        : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
                mTypeVisibilityMap,
                mIsRound, mForceConsumingTypes, mSuppressScrimTypes,
                mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
                mSuppressScrimTypes,
                mDisplayCutoutConsumed
                        ? null
                        : mDisplayCutout == null
@@ -1214,6 +1230,7 @@ public final class WindowInsets {

        return mIsRound == that.mIsRound
                && mForceConsumingTypes == that.mForceConsumingTypes
                && mForceConsumingOpaqueCaptionBar == that.mForceConsumingOpaqueCaptionBar
                && mSuppressScrimTypes == that.mSuppressScrimTypes
                && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
                && mStableInsetsConsumed == that.mStableInsetsConsumed
@@ -1235,9 +1252,9 @@ public final class WindowInsets {
    public int hashCode() {
        return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
                Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
                mForceConsumingTypes, mSuppressScrimTypes, mSystemWindowInsetsConsumed,
                mStableInsetsConsumed, mDisplayCutoutConsumed, mPrivacyIndicatorBounds,
                mDisplayShape, Arrays.deepHashCode(mTypeBoundingRectsMap),
                mForceConsumingTypes, mForceConsumingOpaqueCaptionBar, mSuppressScrimTypes,
                mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed,
                mPrivacyIndicatorBounds, mDisplayShape, Arrays.deepHashCode(mTypeBoundingRectsMap),
                Arrays.deepHashCode(mTypeMaxBoundingRectsMap), mFrameWidth, mFrameHeight);
    }

@@ -1367,6 +1384,7 @@ public final class WindowInsets {

        private boolean mIsRound;
        private @InsetsType int mForceConsumingTypes;
        private boolean mForceConsumingOpaqueCaptionBar;
        private @InsetsType int mSuppressScrimTypes;

        private PrivacyIndicatorBounds mPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
@@ -1399,6 +1417,7 @@ public final class WindowInsets {
            mRoundedCorners = insets.mRoundedCorners;
            mIsRound = insets.mIsRound;
            mForceConsumingTypes = insets.mForceConsumingTypes;
            mForceConsumingOpaqueCaptionBar = insets.mForceConsumingOpaqueCaptionBar;
            mSuppressScrimTypes = insets.mSuppressScrimTypes;
            mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
            mDisplayShape = insets.mDisplayShape;
@@ -1685,6 +1704,13 @@ public final class WindowInsets {
            return this;
        }

        /** @hide */
        @NonNull
        public Builder setForceConsumingOpaqueCaptionBar(boolean forceConsumingOpaqueCaptionBar) {
            mForceConsumingOpaqueCaptionBar = forceConsumingOpaqueCaptionBar;
            return this;
        }

        /** @hide */
        @NonNull
        public Builder setSuppressScrimTypes(@InsetsType int suppressScrimTypes) {
@@ -1763,9 +1789,9 @@ public final class WindowInsets {
        public WindowInsets build() {
            return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
                    mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
                    mIsRound, mForceConsumingTypes, mSuppressScrimTypes, mDisplayCutout,
                    mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
                    false /* compatIgnoreVisibility */,
                    mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
                    mSuppressScrimTypes, mDisplayCutout, mRoundedCorners, mPrivacyIndicatorBounds,
                    mDisplayShape, systemBars(), false /* compatIgnoreVisibility */,
                    mSystemInsetsConsumed ? null : mTypeBoundingRectsMap,
                    mStableInsetsConsumed ? null : mTypeMaxBoundingRectsMap,
                    mFrameWidth, mFrameHeight);
+20 −13
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsetsController.APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -36,6 +37,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.flags.Flags.customizableWindowHeaders;

import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;

@@ -226,6 +228,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    private boolean mLastHasLeftStableInset = false;
    private int mLastWindowFlags = 0;
    private @InsetsType int mLastForceConsumingTypes = 0;
    private boolean mLastForceConsumingOpaqueCaptionBar = false;
    private @InsetsType int mLastSuppressScrimTypes = 0;

    private int mRootScrollY = 0;
@@ -1068,8 +1071,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        WindowManager.LayoutParams attrs = mWindow.getAttributes();
        int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();

        final ViewRootImpl viewRoot = getViewRootImpl();
        final WindowInsetsController controller = getWindowInsetsController();
        final @InsetsType int requestedVisibleTypes = controller.getRequestedVisibleTypes();
        final @Appearance int appearance = viewRoot != null
                ? viewRoot.mWindowAttributes.insetsFlags.appearance
                : controller.getSystemBarsAppearance();

        // IME is an exceptional floating window that requires color view.
        final boolean isImeWindow =
@@ -1080,13 +1087,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                    & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
            mLastWindowFlags = attrs.flags;

            final ViewRootImpl viewRoot = getViewRootImpl();
            final @Appearance int appearance = viewRoot != null
                    ? viewRoot.mWindowAttributes.insetsFlags.appearance
                    : controller.getSystemBarsAppearance();

            if (insets != null) {
                mLastForceConsumingTypes = insets.getForceConsumingTypes();
                mLastForceConsumingOpaqueCaptionBar = insets.isForceConsumingOpaqueCaptionBar();

                final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
                        getResources().getConfiguration().windowConfiguration.getActivityType(),
@@ -1209,16 +1212,20 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind

        final boolean hideCaptionBar = fullscreen
                || (requestedVisibleTypes & WindowInsets.Type.captionBar()) == 0;
        final boolean consumingCaptionBar =
                ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
        final boolean consumingCaptionBar = Flags.enableCaptionCompatInsetForceConsumption()
                && ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
                        && hideCaptionBar);

        final int consumedTop;
        if (Flags.enableCaptionCompatInsetForceConsumption()) {
            consumedTop = (consumingStatusBar || consumingCaptionBar) ? mLastTopInset : 0;
        } else {
            consumedTop = consumingStatusBar ? mLastTopInset : 0;
        }
        final boolean isOpaqueCaptionBar = customizableWindowHeaders()
                && (appearance & APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) == 0;
        final boolean consumingOpaqueCaptionBar =
                Flags.enableCaptionCompatInsetForceConsumptionAlways()
                        && mLastForceConsumingOpaqueCaptionBar
                        && isOpaqueCaptionBar;

        final int consumedTop =
                (consumingStatusBar || consumingCaptionBar || consumingOpaqueCaptionBar)
                        ? mLastTopInset : 0;
        int consumedRight = consumingNavBar ? mLastRightInset : 0;
        int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
        int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
+24 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.view;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
import static android.view.InsetsSource.ID_IME;
import static android.view.InsetsSource.SIDE_BOTTOM;
import static android.view.InsetsSource.SIDE_TOP;
@@ -54,12 +55,17 @@ import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;

import androidx.test.runner.AndroidJUnit4;

import com.android.window.flags.Flags;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -78,6 +84,9 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class InsetsStateTest {

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private static final int ID_STATUS_BAR = InsetsSource.createId(
            null /* owner */, 0 /* index */, statusBars());
    private static final int ID_NAVIGATION_BAR = InsetsSource.createId(
@@ -854,4 +863,19 @@ public class InsetsStateTest {
        );

    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS)
    public void testCalculateInsets_forceConsumingCaptionBar() {
        mState.getOrCreateSource(ID_CAPTION_BAR, captionBar())
                .setFrame(new Rect(0, 0, 100, 100))
                .setVisible(true)
                .setFlags(FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR);

        final WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 1000, 1000), null, false,
                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                new SparseIntArray());

        assertTrue(insets.isForceConsumingOpaqueCaptionBar());
    }
}
Loading