summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jorge Gil <jorgegil@google.com> 2024-07-11 21:28:32 +0000
committer Jorge Gil <jorgegil@google.com> 2024-07-23 21:15:11 +0000
commit507dca83b33a1afe23331b5d3095f1efb5d7520f (patch)
tree4e8869d21634299e685af37dd59f158b1fbf87a0
parent36a3e6e7f5ebe845847c320e11e35a8d2fd0542f (diff)
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
-rw-r--r--core/java/android/view/InsetsSource.java14
-rw-r--r--core/java/android/view/InsetsState.java16
-rw-r--r--core/java/android/view/WindowInsets.java56
-rw-r--r--core/java/com/android/internal/policy/DecorView.java33
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java24
-rw-r--r--core/tests/coretests/src/android/view/WindowInsetsTest.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java76
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt1
11 files changed, 225 insertions, 51 deletions
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 5c10db19b403..b796e0b1c429 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -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();
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index bbd9acfd4cd7..6b4340a02edc 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -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),
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 561d979f2f9d..297e8ffa0bca 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -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
@@ -1024,6 +1030,13 @@ public final class WindowInsets {
/**
* @hide
*/
+ public boolean isForceConsumingOpaqueCaptionBar() {
+ return mForceConsumingOpaqueCaptionBar;
+ }
+
+ /**
+ * @hide
+ */
public @InsetsType int getSuppressScrimTypes() {
return mSuppressScrimTypes;
}
@@ -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;
@@ -1687,6 +1706,13 @@ public final class WindowInsets {
/** @hide */
@NonNull
+ public Builder setForceConsumingOpaqueCaptionBar(boolean forceConsumingOpaqueCaptionBar) {
+ mForceConsumingOpaqueCaptionBar = forceConsumingOpaqueCaptionBar;
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
public Builder setSuppressScrimTypes(@InsetsType int suppressScrimTypes) {
mSuppressScrimTypes = suppressScrimTypes;
return this;
@@ -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);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 87e22ed42cbd..48283930595d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -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;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 16bd20a42b2a..75749c7eff09 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -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());
+ }
}
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index ab4543cb8001..00b3b09d1cc9 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -40,14 +40,14 @@ public class WindowInsetsTest {
@Test
public void systemWindowInsets_afterConsuming_isConsumed() {
assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
- null, false, 0, 0, null, null, null, null,
+ null, false, 0, false, 0, null, null, null, null,
WindowInsets.Type.systemBars(), false, null, null, 0, 0)
.consumeSystemWindowInsets().isConsumed());
}
@Test
public void multiNullConstructor_isConsumed() {
- assertTrue(new WindowInsets(null, null, null, false, 0, 0, null, null, null, null,
+ assertTrue(new WindowInsets(null, null, null, false, 0, false, 0, null, null, null, null,
WindowInsets.Type.systemBars(), false, null, null, 0, 0).isConsumed());
}
@@ -64,7 +64,7 @@ public class WindowInsetsTest {
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, 0,
- 0, null, null, null, DisplayShape.NONE, systemBars(),
+ false, 0, null, null, null, DisplayShape.NONE, systemBars(),
true /* compatIgnoreVisibility */, null, null, 0, 0);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 529def7ca3d7..2ebb9fe46c64 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -19,6 +19,8 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.windowingModeToString;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
@@ -574,6 +576,17 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
// through to the windows below so that the app can respond to input events on
// their custom content.
relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+ } else {
+ if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ // Force-consume the caption bar insets when the app tries to hide the caption.
+ // This improves app compatibility of immersive apps.
+ relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING;
+ }
+ }
+ if (Flags.enableCaptionCompatInsetForceConsumptionAlways()) {
+ // Always force-consume the caption bar insets for maximum app compatibility,
+ // including non-immersive apps that just don't handle caption insets properly.
+ relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
}
// Report occluding elements as bounding rects to the insets system so that apps can
// draw in the empty space in the center:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index a691f59a2155..5f00aa28d666 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
-import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
@@ -54,7 +53,6 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -375,7 +373,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
final WindowDecorationInsets newInsets = new WindowDecorationInsets(
- mTaskInfo.token, mOwner, captionInsetsRect, boundingRects);
+ mTaskInfo.token, mOwner, captionInsetsRect, boundingRects,
+ params.mInsetSourceFlags);
if (!newInsets.equals(mWindowDecorationInsets)) {
// Add or update this caption as an insets source.
mWindowDecorationInsets = newInsets;
@@ -660,7 +659,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
final WindowDecorationInsets newInsets = new WindowDecorationInsets(mTaskInfo.token,
- mOwner, captionInsets, null /* boundingRets */);
+ mOwner, captionInsets, null /* boundingRets */, 0 /* flags */);
if (!newInsets.equals(mWindowDecorationInsets)) {
mWindowDecorationInsets = newInsets;
mWindowDecorationInsets.addOrUpdate(wct);
@@ -674,6 +673,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
int mCaptionWidthId;
final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();
int mInputFeatures;
+ @InsetsSource.Flags int mInsetSourceFlags;
int mShadowRadiusId;
int mCornerRadius;
@@ -689,6 +689,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mCaptionWidthId = Resources.ID_NULL;
mOccludingCaptionElements.clear();
mInputFeatures = 0;
+ mInsetSourceFlags = 0;
mShadowRadiusId = Resources.ID_NULL;
mCornerRadius = 0;
@@ -753,20 +754,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
private final Binder mOwner;
private final Rect mFrame;
private final Rect[] mBoundingRects;
+ private final @InsetsSource.Flags int mFlags;
private WindowDecorationInsets(WindowContainerToken token, Binder owner, Rect frame,
- Rect[] boundingRects) {
+ Rect[] boundingRects, @InsetsSource.Flags int flags) {
mToken = token;
mOwner = owner;
mFrame = frame;
mBoundingRects = boundingRects;
+ mFlags = flags;
}
void addOrUpdate(WindowContainerTransaction wct) {
- final @InsetsSource.Flags int captionSourceFlags =
- Flags.enableCaptionCompatInsetForceConsumption() ? FLAG_FORCE_CONSUMING : 0;
wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects,
- captionSourceFlags);
+ mFlags);
wct.addInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures(), mFrame,
mBoundingRects, 0 /* flags */);
}
@@ -782,12 +783,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
if (!(o instanceof WindowDecoration.WindowDecorationInsets that)) return false;
return Objects.equals(mToken, that.mToken) && Objects.equals(mOwner,
that.mOwner) && Objects.equals(mFrame, that.mFrame)
- && Objects.deepEquals(mBoundingRects, that.mBoundingRects);
+ && Objects.deepEquals(mBoundingRects, that.mBoundingRects)
+ && mFlags == that.mFlags;
}
@Override
public int hashCode() {
- return Objects.hash(mToken, mOwner, mFrame, Arrays.hashCode(mBoundingRects));
+ return Objects.hash(mToken, mOwner, mFrame, Arrays.hashCode(mBoundingRects), mFlags);
}
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 412fef30d4fb..81434919b2d8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -398,6 +400,80 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
+ public void updateRelayoutParams_defaultHeader_addsForceConsumingFlag() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) != 0).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
+ public void updateRelayoutParams_customHeader_noForceConsumptionFlag() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(
+ APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) == 0).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS)
+ public void updateRelayoutParams_header_addsForceConsumingCaptionBar() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat(
+ (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0)
+ .isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS)
+ public void updateRelayoutParams_handle_skipsForceConsumingCaptionBar() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat(
+ (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) == 0)
+ .isTrue();
+ }
+
@DisableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
public void relayout_fullscreenTask_appliesTransactionImmediately() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 2d1bf14ffbb3..ca6e03c45e7e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
@@ -56,7 +57,6 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
@@ -75,7 +75,6 @@ import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
-import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -781,8 +780,7 @@ public class WindowDecorationTests extends ShellTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
- public void testRelayout_captionInsetForceConsume() {
+ public void testRelayout_captionInsetSourceFlags() {
final Display defaultDisplay = mock(Display.class);
doReturn(defaultDisplay).when(mMockDisplayController)
.getDisplay(Display.DEFAULT_DISPLAY);
@@ -794,11 +792,14 @@ public class WindowDecorationTests extends ShellTestCase {
final ActivityManager.RunningTaskInfo taskInfo =
builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
+ mRelayoutParams.mInsetSourceFlags =
+ FLAG_FORCE_CONSUMING | FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
windowDecor.relayout(taskInfo);
- // Caption inset source should be force-consuming.
+ // Caption inset source should add params' flags.
verify(mMockWindowContainerTransaction).addInsetsSource(eq(token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any(), eq(FLAG_FORCE_CONSUMING));
+ eq(0) /* index */, eq(captionBar()), any(), any(),
+ eq(FLAG_FORCE_CONSUMING | FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index fd2dead02c6c..e670884eff17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -334,6 +334,7 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
/* typeVisibilityMap = */ booleanArrayOf(),
/* isRound = */ false,
/* forceConsumingTypes = */ 0,
+ /* forceConsumingCaptionBar = */ false,
/* suppressScrimTypes = */ 0,
/* displayCutout = */ DisplayCutout.NO_CUTOUT,
/* roundedCorners = */ RoundedCorners.NO_ROUNDED_CORNERS,