summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/view/DisplayCutout.java24
-rw-r--r--core/java/android/view/InsetsSource.java4
-rw-r--r--core/java/android/view/InsetsState.java35
-rw-r--r--core/java/android/view/WindowInsets.java34
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java20
7 files changed, 131 insertions, 11 deletions
diff --git a/api/current.txt b/api/current.txt
index 8477754d9095..e2d054800d4a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -55520,6 +55520,7 @@ package android.view {
public static final class WindowInsets.Type {
method public static int captionBar();
+ method public static int displayCutout();
method public static int ime();
method public static int mandatorySystemGestures();
method public static int navigationBars();
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 0ab856ec5b4d..679c912e846f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -393,22 +393,38 @@ public final class DisplayCutout {
return mSafeInsets.equals(ZERO_RECT);
}
- /** Returns the inset from the top which avoids the display cutout in pixels. */
+ /**
+ * Returns the inset from the top which avoids the display cutout in pixels.
+ *
+ * @see WindowInsets.Type#displayCutout()
+ */
public int getSafeInsetTop() {
return mSafeInsets.top;
}
- /** Returns the inset from the bottom which avoids the display cutout in pixels. */
+ /**
+ * Returns the inset from the bottom which avoids the display cutout in pixels.
+ *
+ * @see WindowInsets.Type#displayCutout()
+ */
public int getSafeInsetBottom() {
return mSafeInsets.bottom;
}
- /** Returns the inset from the left which avoids the display cutout in pixels. */
+ /**
+ * Returns the inset from the left which avoids the display cutout in pixels.
+ *
+ * @see WindowInsets.Type#displayCutout()
+ */
public int getSafeInsetLeft() {
return mSafeInsets.left;
}
- /** Returns the inset from the right which avoids the display cutout in pixels. */
+ /**
+ * Returns the inset from the right which avoids the display cutout in pixels.
+ *
+ * @see WindowInsets.Type#displayCutout()
+ */
public int getSafeInsetRight() {
return mSafeInsets.right;
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 6caa4fed6409..719f649cb5a2 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -58,6 +58,10 @@ public class InsetsSource implements Parcelable {
: null;
}
+ public void setFrame(int left, int top, int right, int bottom) {
+ mFrame.set(left, top, right, bottom);
+ }
+
public void setFrame(Rect frame) {
mFrame.set(frame);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 8648682aaa2e..c877c454be91 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
import static android.view.WindowInsets.Type.isVisibleInsetsType;
@@ -71,6 +72,10 @@ public class InsetsState implements Parcelable {
ITYPE_RIGHT_GESTURES,
ITYPE_TOP_TAPPABLE_ELEMENT,
ITYPE_BOTTOM_TAPPABLE_ELEMENT,
+ ITYPE_LEFT_DISPLAY_CUTOUT,
+ ITYPE_TOP_DISPLAY_CUTOUT,
+ ITYPE_RIGHT_DISPLAY_CUTOUT,
+ ITYPE_BOTTOM_DISPLAY_CUTOUT,
ITYPE_IME
})
public @interface InternalInsetsType {}
@@ -88,8 +93,13 @@ public class InsetsState implements Parcelable {
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 7;
public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 8;
+ public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 9;
+ public static final int ITYPE_TOP_DISPLAY_CUTOUT = 10;
+ public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 11;
+ public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 12;
+
/** Input method window. */
- public static final int ITYPE_IME = 9;
+ public static final int ITYPE_IME = 13;
static final int LAST_TYPE = ITYPE_IME;
@@ -185,8 +195,8 @@ public class InsetsState implements Parcelable {
final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
- ? systemBars() | ime()
- : systemBars(),
+ ? systemBars() | displayCutout() | ime()
+ : systemBars() | displayCutout(),
sNewInsetsMode == NEW_INSETS_MODE_FULL
&& (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
@@ -358,6 +368,12 @@ public class InsetsState implements Parcelable {
if ((types & Type.CAPTION_BAR) != 0) {
result.add(ITYPE_CAPTION_BAR);
}
+ if ((types & Type.DISPLAY_CUTOUT) != 0) {
+ result.add(ITYPE_LEFT_DISPLAY_CUTOUT);
+ result.add(ITYPE_TOP_DISPLAY_CUTOUT);
+ result.add(ITYPE_RIGHT_DISPLAY_CUTOUT);
+ result.add(ITYPE_BOTTOM_DISPLAY_CUTOUT);
+ }
if ((types & Type.IME) != 0) {
result.add(ITYPE_IME);
}
@@ -388,6 +404,11 @@ public class InsetsState implements Parcelable {
case ITYPE_TOP_TAPPABLE_ELEMENT:
case ITYPE_BOTTOM_TAPPABLE_ELEMENT:
return Type.TAPPABLE_ELEMENT;
+ case ITYPE_LEFT_DISPLAY_CUTOUT:
+ case ITYPE_TOP_DISPLAY_CUTOUT:
+ case ITYPE_RIGHT_DISPLAY_CUTOUT:
+ case ITYPE_BOTTOM_DISPLAY_CUTOUT:
+ return Type.DISPLAY_CUTOUT;
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
@@ -437,6 +458,14 @@ public class InsetsState implements Parcelable {
return "ITYPE_TOP_TAPPABLE_ELEMENT";
case ITYPE_BOTTOM_TAPPABLE_ELEMENT:
return "ITYPE_BOTTOM_TAPPABLE_ELEMENT";
+ case ITYPE_LEFT_DISPLAY_CUTOUT:
+ return "ITYPE_LEFT_DISPLAY_CUTOUT";
+ case ITYPE_TOP_DISPLAY_CUTOUT:
+ return "ITYPE_TOP_DISPLAY_CUTOUT";
+ case ITYPE_RIGHT_DISPLAY_CUTOUT:
+ return "ITYPE_RIGHT_DISPLAY_CUTOUT";
+ case ITYPE_BOTTOM_DISPLAY_CUTOUT:
+ return "ITYPE_BOTTOM_DISPLAY_CUTOUT";
case ITYPE_IME:
return "ITYPE_IME";
default:
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index a6c311e1daa5..20fa5cab0464 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,6 +17,7 @@
package android.view;
+import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.LAST;
@@ -1209,6 +1210,13 @@ public final class WindowInsets {
@NonNull
public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
+ if (!mDisplayCutout.isEmpty()) {
+ final Insets safeInsets = Insets.of(mDisplayCutout.getSafeInsets());
+ final int index = indexOf(DISPLAY_CUTOUT);
+ mTypeInsetsMap[index] = safeInsets;
+ mTypeMaxInsetsMap[index] = safeInsets;
+ mTypeVisibilityMap[index] = true;
+ }
return this;
}
@@ -1256,8 +1264,10 @@ public final class WindowInsets {
static final int MANDATORY_SYSTEM_GESTURES = 1 << 5;
static final int TAPPABLE_ELEMENT = 1 << 6;
- static final int LAST = 1 << 7;
- static final int SIZE = 8;
+ static final int DISPLAY_CUTOUT = 1 << 7;
+
+ static final int LAST = 1 << 8;
+ static final int SIZE = 9;
static final int WINDOW_DECOR = LAST;
static int indexOf(@InsetsType int type) {
@@ -1276,8 +1286,10 @@ public final class WindowInsets {
return 5;
case TAPPABLE_ELEMENT:
return 6;
- case WINDOW_DECOR:
+ case DISPLAY_CUTOUT:
return 7;
+ case WINDOW_DECOR:
+ return 8;
default:
throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
+ " type=" + type);
@@ -1290,7 +1302,7 @@ public final class WindowInsets {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {STATUS_BARS, NAVIGATION_BARS, CAPTION_BAR, IME, WINDOW_DECOR,
- SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
+ SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT, DISPLAY_CUTOUT})
public @interface InsetsType {
}
@@ -1358,6 +1370,20 @@ public final class WindowInsets {
}
/**
+ * Returns an insets type representing the area that used by {@link DisplayCutout}.
+ *
+ * <p>This is equivalent to the safe insets on {@link #getDisplayCutout()}.</p>
+ *
+ * @see DisplayCutout#getSafeInsetLeft()
+ * @see DisplayCutout#getSafeInsetTop()
+ * @see DisplayCutout#getSafeInsetRight()
+ * @see DisplayCutout#getSafeInsetBottom()
+ */
+ public static @InsetsType int displayCutout() {
+ return DISPLAY_CUTOUT;
+ }
+
+ /**
* @return All system bars. Includes {@link #statusBars()}, {@link #captionBar()} as well as
* {@link #navigationBars()}, but not {@link #ime()}.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4e872ac9507e..44507390142c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -25,12 +25,16 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.TYPE_INTERNAL;
+import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
+import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@@ -1430,6 +1434,7 @@ public class DisplayPolicy {
*/
void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
displayFrames.onBeginLayout();
+ updateInsetsStateForDisplayCutout(displayFrames, insetsState);
insetsState.setDisplayFrame(displayFrames.mUnrestricted);
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (mNavigationBar != null) {
@@ -1458,6 +1463,8 @@ public class DisplayPolicy {
*/
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
displayFrames.onBeginLayout();
+ updateInsetsStateForDisplayCutout(displayFrames,
+ mDisplayContent.getInsetsStateController().getRawInsetsState());
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -1524,6 +1531,23 @@ public class DisplayPolicy {
mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
}
+ private static void updateInsetsStateForDisplayCutout(DisplayFrames displayFrames,
+ InsetsState state) {
+ if (displayFrames.mDisplayCutout.getDisplayCutout().isEmpty()) {
+ state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
+ return;
+ }
+ final Rect u = displayFrames.mUnrestricted;
+ final Rect s = displayFrames.mDisplayCutoutSafe;
+ state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(u.left, u.top, s.left, u.bottom);
+ state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(u.left, u.top, u.right, s.top);
+ state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(s.right, u.top, u.right, u.bottom);
+ state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
+ }
+
/** Enforces the last layout policy for display frames. */
private void postAdjustDisplayFrames(DisplayFrames displayFrames) {
if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 203fa61b7546..e2c27ea55b13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -269,6 +269,26 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
+ @Test
+ public void layoutWindowLw_fitDisplayCutout() {
+ assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+ addDisplayCutout();
+
+ mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
+ mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ }
+
// TODO(b/118118435): remove after migration
@Test
public void layoutWindowLw_appDrawsBarsLegacy() {