Loading api/current.txt +3 −3 Original line number Original line Diff line number Diff line Loading @@ -46625,8 +46625,8 @@ package android.view { } } public final class DisplayCutout { public final class DisplayCutout { ctor public DisplayCutout(android.graphics.Rect, android.graphics.Region); ctor public DisplayCutout(android.graphics.Rect, java.util.List<android.graphics.Rect>); method public android.graphics.Region getBounds(); method public java.util.List<android.graphics.Rect> getBoundingRects(); method public int getSafeInsetBottom(); method public int getSafeInsetBottom(); method public int getSafeInsetLeft(); method public int getSafeInsetLeft(); method public int getSafeInsetRight(); method public int getSafeInsetRight(); Loading Loading @@ -49700,9 +49700,9 @@ package android.view { field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7 field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7 field public static final int LAYOUT_CHANGED = 1; // 0x1 field public static final int LAYOUT_CHANGED = 1; // 0x1 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1 field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100 field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100 field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2 field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2 field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1 field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1 core/java/android/view/DisplayCutout.java +118 −122 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,6 @@ package android.view; import static android.view.DisplayCutoutProto.BOUNDS; import static android.view.DisplayCutoutProto.BOUNDS; import static android.view.DisplayCutoutProto.INSETS; import static android.view.DisplayCutoutProto.INSETS; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; Loading @@ -36,23 +32,24 @@ import android.os.Parcelable; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.util.PathParser; import android.util.PathParser; import android.util.Size; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; import java.util.ArrayList; import java.util.List; /** /** * Represents a part of the display that is not functional for displaying content. * Represents the area of the display that is not functional for displaying content. * * * <p>{@code DisplayCutout} is immutable. * <p>{@code DisplayCutout} is immutable. */ */ public final class DisplayCutout { public final class DisplayCutout { private static final String TAG = "DisplayCutout"; private static final String TAG = "DisplayCutout"; private static final String BOTTOM_MARKER = "@bottom"; private static final String DP_MARKER = "@dp"; private static final String DP_MARKER = "@dp"; /** /** Loading @@ -74,7 +71,7 @@ public final class DisplayCutout { * @hide * @hide */ */ public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION, public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION, new Size(0, 0)); false /* copyArguments */); private static final Object CACHE_LOCK = new Object(); private static final Object CACHE_LOCK = new Object(); Loading @@ -89,38 +86,38 @@ public final class DisplayCutout { private final Rect mSafeInsets; private final Rect mSafeInsets; private final Region mBounds; private final Region mBounds; private final Size mFrameSize; // TODO: move frameSize, calculateRelativeTo, etc. into WM. /** /** * Creates a DisplayCutout instance. * Creates a DisplayCutout instance. * * * @param safeInsets the insets from each edge which avoid the display cutout as returned by * @param safeInsets the insets from each edge which avoid the display cutout as returned by * {@link #getSafeInsetTop()} etc. * {@link #getSafeInsetTop()} etc. * @param bounds the bounds of the display cutout as returned by {@link #getBounds()}. * @param boundingRects the bounding rects of the display cutouts as returned by * {@link #getBoundingRects()} ()}. */ */ // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) public DisplayCutout(Rect safeInsets, Region bounds) { public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) { this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT, this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT, bounds != null ? Region.obtain(bounds) : Region.obtain(), boundingRectsToRegion(boundingRects), null /* frameSize */); true /* copyArguments */); } } /** /** * Creates a DisplayCutout instance. * Creates a DisplayCutout instance. * * * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged. * @param copyArguments if true, create a copy of the arguments. If false, the passed arguments * * are not copied and MUST remain unchanged forever. * @hide */ */ @VisibleForTesting private DisplayCutout(Rect safeInsets, Region bounds, boolean copyArguments) { public DisplayCutout(Rect safeInsets, Region bounds, Size frameSize) { mSafeInsets = safeInsets == null ? ZERO_RECT : mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT; (copyArguments ? new Rect(safeInsets) : safeInsets); mBounds = bounds != null ? bounds : Region.obtain(); mBounds = bounds == null ? Region.obtain() : mFrameSize = frameSize; (copyArguments ? Region.obtain(bounds) : bounds); } } /** /** * Returns true if there is no cutout or it is outside of the content view. * Returns true if the safe insets are empty (and therefore the current view does not * overlap with the cutout or cutout area). * * * @hide * @hide */ */ Loading @@ -128,6 +125,15 @@ public final class DisplayCutout { return mSafeInsets.equals(ZERO_RECT); return mSafeInsets.equals(ZERO_RECT); } } /** * Returns true if there is no cutout, i.e. the bounds are empty. * * @hide */ public boolean isBoundsEmpty() { return mBounds.isEmpty(); } /** 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. */ public int getSafeInsetTop() { public int getSafeInsetTop() { return mSafeInsets.top; return mSafeInsets.top; Loading Loading @@ -161,23 +167,60 @@ public final class DisplayCutout { /** /** * Returns the bounding region of the cutout. * Returns the bounding region of the cutout. * * * <p> * <strong>Note:</strong> There may be more than one cutout, in which case the returned * {@code Region} will be non-contiguous and its bounding rect will be meaningless without * intersecting it first. * * Example: * <pre> * // Getting the bounding rectangle of the top display cutout * Region bounds = displayCutout.getBounds(); * bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT); * Rect topDisplayCutout = bounds.getBoundingRect(); * </pre> * * @return the bounding region of the cutout. Coordinates are relative * @return the bounding region of the cutout. Coordinates are relative * to the top-left corner of the content view and in pixel units. * to the top-left corner of the content view and in pixel units. * @hide */ */ public Region getBounds() { public Region getBounds() { return Region.obtain(mBounds); return Region.obtain(mBounds); } } /** /** * Returns the bounding rect of the cutout. * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional * area on the display. * * * @return the bounding rect of the cutout. Coordinates are relative * There will be at most one non-functional area per short edge of the device, and none on * to the top-left corner of the content view. * the long edges. * @hide * * @return a list of bounding {@code Rect}s, one for each display cutout area. */ */ public Rect getBoundingRect() { public List<Rect> getBoundingRects() { // TODO(roosa): Inline. List<Rect> result = new ArrayList<>(); return mBounds.getBounds(); Region bounds = Region.obtain(); // top bounds.set(mBounds); bounds.op(0, 0, Integer.MAX_VALUE, getSafeInsetTop(), Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } // left bounds.set(mBounds); bounds.op(0, 0, getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } // right & bottom bounds.set(mBounds); bounds.op(getSafeInsetLeft() + 1, getSafeInsetTop() + 1, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } bounds.recycle(); return result; } } @Override @Override Loading @@ -195,8 +238,7 @@ public final class DisplayCutout { if (o instanceof DisplayCutout) { if (o instanceof DisplayCutout) { DisplayCutout c = (DisplayCutout) o; DisplayCutout c = (DisplayCutout) o; return mSafeInsets.equals(c.mSafeInsets) return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds) && mBounds.equals(c.mBounds); && Objects.equals(mFrameSize, c.mFrameSize); } } return false; return false; } } Loading @@ -204,7 +246,7 @@ public final class DisplayCutout { @Override @Override public String toString() { public String toString() { return "DisplayCutout{insets=" + mSafeInsets return "DisplayCutout{insets=" + mSafeInsets + " boundingRect=" + getBoundingRect() + " boundingRect=" + mBounds.getBounds() + "}"; + "}"; } } Loading Loading @@ -249,88 +291,19 @@ public final class DisplayCutout { } } bounds.translate(-insetLeft, -insetTop); bounds.translate(-insetLeft, -insetTop); Size frame = mFrameSize == null ? null : new Size( return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); mFrameSize.getWidth() - insetLeft - insetRight, mFrameSize.getHeight() - insetTop - insetBottom); return new DisplayCutout(safeInsets, bounds, frame); } } /** /** * Recalculates the cutout relative to the given reference frame. * Returns a copy of this instance with the safe insets replaced with the parameter. * * * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}. * @param safeInsets the new safe insets in pixels * @return a copy of this instance with the safe insets replaced with the argument. * * * @return a copy of this instance with the safe insets recalculated * @hide * @hide */ */ public DisplayCutout calculateRelativeTo(Rect frame) { public DisplayCutout replaceSafeInsets(Rect safeInsets) { return inset(frame.left, frame.top, return new DisplayCutout(new Rect(safeInsets), mBounds, false /* copyArguments */); mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom); } /** * Calculates the safe insets relative to the given display size. * * @return a copy of this instance with the safe insets calculated * @hide */ public DisplayCutout computeSafeInsets(int width, int height) { if (this == NO_CUTOUT || mBounds.isEmpty()) { return NO_CUTOUT; } return computeSafeInsets(new Size(width, height), mBounds); } private static DisplayCutout computeSafeInsets(Size displaySize, Region bounds) { Rect boundingRect = bounds.getBounds(); Rect safeRect = new Rect(); int bestArea = 0; int bestVariant = 0; for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) { int area = calculateInsetVariantArea(displaySize, boundingRect, variant, safeRect); if (bestArea < area) { bestArea = area; bestVariant = variant; } } calculateInsetVariantArea(displaySize, boundingRect, bestVariant, safeRect); if (safeRect.isEmpty()) { // The entire displaySize overlaps with the cutout. safeRect.set(0, displaySize.getHeight(), 0, 0); } else { // Convert safeRect to insets relative to displaySize. We're reusing the rect here to // avoid an allocation. safeRect.set( Math.max(0, safeRect.left), Math.max(0, safeRect.top), Math.max(0, displaySize.getWidth() - safeRect.right), Math.max(0, displaySize.getHeight() - safeRect.bottom)); } return new DisplayCutout(safeRect, bounds, displaySize); } private static int calculateInsetVariantArea(Size display, Rect boundingRect, int variant, Rect outSafeRect) { switch (variant) { case ROTATION_0: outSafeRect.set(0, 0, display.getWidth(), boundingRect.top); break; case ROTATION_90: outSafeRect.set(0, 0, boundingRect.left, display.getHeight()); break; case ROTATION_180: outSafeRect.set(0, boundingRect.bottom, display.getWidth(), display.getHeight()); break; case ROTATION_270: outSafeRect.set(boundingRect.right, 0, display.getWidth(), display.getHeight()); break; } return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height(); } } private static int atLeastZero(int value) { private static int atLeastZero(int value) { Loading Loading @@ -369,7 +342,7 @@ public final class DisplayCutout { Region bounds = new Region(); Region bounds = new Region(); bounds.setPath(path, clipRegion); bounds.setPath(path, clipRegion); clipRegion.recycle(); clipRegion.recycle(); return new DisplayCutout(ZERO_RECT, bounds, null /* frameSize */); return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */); } } /** /** Loading @@ -377,9 +350,9 @@ public final class DisplayCutout { * * * @hide * @hide */ */ public static DisplayCutout fromResources(Resources res, int displayWidth) { public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) { return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), displayWidth, res.getDisplayMetrics().density); displayWidth, displayHeight, res.getDisplayMetrics().density); } } /** /** Loading @@ -388,7 +361,8 @@ public final class DisplayCutout { * @hide * @hide */ */ @VisibleForTesting(visibility = PRIVATE) @VisibleForTesting(visibility = PRIVATE) public static DisplayCutout fromSpec(String spec, int displayWidth, float density) { public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight, float density) { if (TextUtils.isEmpty(spec)) { if (TextUtils.isEmpty(spec)) { return null; return null; } } Loading @@ -404,7 +378,14 @@ public final class DisplayCutout { spec = spec.substring(0, spec.length() - DP_MARKER.length()); spec = spec.substring(0, spec.length() - DP_MARKER.length()); } } Path p; String bottomSpec = null; if (spec.contains(BOTTOM_MARKER)) { String[] splits = spec.split(BOTTOM_MARKER, 2); spec = splits[0].trim(); bottomSpec = splits[1].trim(); } final Path p; try { try { p = PathParser.createPathFromPathData(spec); p = PathParser.createPathFromPathData(spec); } catch (Throwable e) { } catch (Throwable e) { Loading @@ -419,6 +400,20 @@ public final class DisplayCutout { m.postTranslate(displayWidth / 2f, 0); m.postTranslate(displayWidth / 2f, 0); p.transform(m); p.transform(m); if (bottomSpec != null) { final Path bottomPath; try { bottomPath = PathParser.createPathFromPathData(bottomSpec); } catch (Throwable e) { Log.wtf(TAG, "Could not inflate bottom cutout: ", e); return null; } // Keep top transform m.postTranslate(0, displayHeight); bottomPath.transform(m); p.addPath(bottomPath); } final DisplayCutout result = fromBounds(p); final DisplayCutout result = fromBounds(p); synchronized (CACHE_LOCK) { synchronized (CACHE_LOCK) { sCachedSpec = spec; sCachedSpec = spec; Loading @@ -429,6 +424,16 @@ public final class DisplayCutout { return result; return result; } } private static Region boundingRectsToRegion(List<Rect> rects) { Region result = Region.obtain(); if (rects != null) { for (Rect r : rects) { result.op(r, Region.Op.UNION); } } return result; } /** /** * Helper class for passing {@link DisplayCutout} through binder. * Helper class for passing {@link DisplayCutout} through binder. * * Loading Loading @@ -472,12 +477,6 @@ public final class DisplayCutout { out.writeInt(1); out.writeInt(1); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedObject(cutout.mBounds, flags); out.writeTypedObject(cutout.mBounds, flags); if (cutout.mFrameSize != null) { out.writeInt(cutout.mFrameSize.getWidth()); out.writeInt(cutout.mFrameSize.getHeight()); } else { out.writeInt(-1); } } } } } Loading Loading @@ -520,10 +519,7 @@ public final class DisplayCutout { Rect safeInsets = in.readTypedObject(Rect.CREATOR); Rect safeInsets = in.readTypedObject(Rect.CREATOR); Region bounds = in.readTypedObject(Region.CREATOR); Region bounds = in.readTypedObject(Region.CREATOR); int width = in.readInt(); return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); Size frameSize = width >= 0 ? new Size(width, in.readInt()) : null; return new DisplayCutout(safeInsets, bounds, frameSize); } } public DisplayCutout get() { public DisplayCutout get() { Loading core/java/android/view/WindowManager.java +20 −8 Original line number Original line Diff line number Diff line Loading @@ -2241,18 +2241,20 @@ public interface WindowManager extends ViewManager { /** /** * The window is allowed to extend into the {@link DisplayCutout} area, only if the * The window is allowed to extend into the {@link DisplayCutout} area, only if the * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is * laid out such that it does not overlap with the {@link DisplayCutout} area. * laid out such that it does not overlap with the {@link DisplayCutout} area. * * * <p> * <p> * In practice, this means that if the window did not set FLAG_FULLSCREEN or * In practice, this means that if the window did not set FLAG_FULLSCREEN or * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait. * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the * bottom of the screen. * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the * cutout area. * cutout area. * * * <p> * <p> * The usual precautions for not overlapping with the status bar are sufficient for ensuring * The usual precautions for not overlapping with the status and navigation bar are * that no important content overlaps with the DisplayCutout. * sufficient for ensuring that no important content overlaps with the DisplayCutout. * * * @see DisplayCutout * @see DisplayCutout * @see WindowInsets * @see WindowInsets Loading @@ -2260,8 +2262,18 @@ public interface WindowManager extends ViewManager { public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; /** /** * The window is always allowed to extend into the {@link DisplayCutout} area, * @deprecated use {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES} * even if fullscreen or in landscape. * @hide */ @Deprecated public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; /** * The window is always allowed to extend into the {@link DisplayCutout} areas on the short * edges of the screen. * * The window will never extend into a {@link DisplayCutout} area on the long edges of the * screen. * * * <p> * <p> * The window must make sure that no important content overlaps with the * The window must make sure that no important content overlaps with the Loading @@ -2270,7 +2282,7 @@ public interface WindowManager extends ViewManager { * @see DisplayCutout * @see DisplayCutout * @see WindowInsets#getDisplayCutout() * @see WindowInsets#getDisplayCutout() */ */ public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; /** /** * The window is never allowed to overlap with the DisplayCutout area. * The window is never allowed to overlap with the DisplayCutout area. Loading core/res/res/values/attrs.xml +9 −6 Original line number Original line Diff line number Diff line Loading @@ -2125,29 +2125,32 @@ Defaults to {@code default}. Defaults to {@code default}. @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.R.attr#layoutInDisplayCutoutMode --> @see android.R.attr#layoutInDisplayCutoutMode --> <attr name="windowLayoutInDisplayCutoutMode"> <attr name="windowLayoutInDisplayCutoutMode"> <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the {@code DisplayCutout} is fully contained within the status bar. Otherwise, the window is {@code DisplayCutout} is fully contained within a system bar. Otherwise, the window is laid out such that it does not overlap with the {@code DisplayCutout} area. laid out such that it does not overlap with the {@code DisplayCutout} area. @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT --> --> <enum name="default" value="0" /> <enum name="default" value="0" /> <!-- The window is always allowed to extend into the {@code DisplayCutout} area, <!-- even if fullscreen or in landscape. The window is always allowed to extend into the {@code DisplayCutout} areas on the short edges of the screen even if fullscreen or in landscape. The window will never extend into a {@link DisplayCutout} area on the long edges of the screen. <p> <p> The window must make sure that no important content overlaps with the The window must make sure that no important content overlaps with the {@link DisplayCutout}. {@link DisplayCutout}. @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES --> --> <enum name="always" value="1" /> <enum name="shortEdges" value="1" /> <!-- The window is never allowed to overlap with the DisplayCutout area. <!-- The window is never allowed to overlap with the DisplayCutout area. <p> <p> This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN} This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN} Loading core/tests/coretests/res/values/styles.xml +2 −2 Original line number Original line Diff line number Diff line Loading @@ -25,8 +25,8 @@ <style name="LayoutInDisplayCutoutModeDefault"> <style name="LayoutInDisplayCutoutModeDefault"> <item name="android:windowLayoutInDisplayCutoutMode">default</item> <item name="android:windowLayoutInDisplayCutoutMode">default</item> </style> </style> <style name="LayoutInDisplayCutoutModeAlways"> <style name="LayoutInDisplayCutoutModeShortEdges"> <item name="android:windowLayoutInDisplayCutoutMode">always</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> </style> </style> <style name="LayoutInDisplayCutoutModeNever"> <style name="LayoutInDisplayCutoutModeNever"> <item name="android:windowLayoutInDisplayCutoutMode">never</item> <item name="android:windowLayoutInDisplayCutoutMode">never</item> Loading Loading
api/current.txt +3 −3 Original line number Original line Diff line number Diff line Loading @@ -46625,8 +46625,8 @@ package android.view { } } public final class DisplayCutout { public final class DisplayCutout { ctor public DisplayCutout(android.graphics.Rect, android.graphics.Region); ctor public DisplayCutout(android.graphics.Rect, java.util.List<android.graphics.Rect>); method public android.graphics.Region getBounds(); method public java.util.List<android.graphics.Rect> getBoundingRects(); method public int getSafeInsetBottom(); method public int getSafeInsetBottom(); method public int getSafeInsetLeft(); method public int getSafeInsetLeft(); method public int getSafeInsetRight(); method public int getSafeInsetRight(); Loading Loading @@ -49700,9 +49700,9 @@ package android.view { field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7 field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7 field public static final int LAYOUT_CHANGED = 1; // 0x1 field public static final int LAYOUT_CHANGED = 1; // 0x1 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1 field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100 field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100 field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2 field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2 field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1 field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
core/java/android/view/DisplayCutout.java +118 −122 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,6 @@ package android.view; import static android.view.DisplayCutoutProto.BOUNDS; import static android.view.DisplayCutoutProto.BOUNDS; import static android.view.DisplayCutoutProto.INSETS; import static android.view.DisplayCutoutProto.INSETS; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; Loading @@ -36,23 +32,24 @@ import android.os.Parcelable; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.util.PathParser; import android.util.PathParser; import android.util.Size; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; import java.util.ArrayList; import java.util.List; /** /** * Represents a part of the display that is not functional for displaying content. * Represents the area of the display that is not functional for displaying content. * * * <p>{@code DisplayCutout} is immutable. * <p>{@code DisplayCutout} is immutable. */ */ public final class DisplayCutout { public final class DisplayCutout { private static final String TAG = "DisplayCutout"; private static final String TAG = "DisplayCutout"; private static final String BOTTOM_MARKER = "@bottom"; private static final String DP_MARKER = "@dp"; private static final String DP_MARKER = "@dp"; /** /** Loading @@ -74,7 +71,7 @@ public final class DisplayCutout { * @hide * @hide */ */ public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION, public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION, new Size(0, 0)); false /* copyArguments */); private static final Object CACHE_LOCK = new Object(); private static final Object CACHE_LOCK = new Object(); Loading @@ -89,38 +86,38 @@ public final class DisplayCutout { private final Rect mSafeInsets; private final Rect mSafeInsets; private final Region mBounds; private final Region mBounds; private final Size mFrameSize; // TODO: move frameSize, calculateRelativeTo, etc. into WM. /** /** * Creates a DisplayCutout instance. * Creates a DisplayCutout instance. * * * @param safeInsets the insets from each edge which avoid the display cutout as returned by * @param safeInsets the insets from each edge which avoid the display cutout as returned by * {@link #getSafeInsetTop()} etc. * {@link #getSafeInsetTop()} etc. * @param bounds the bounds of the display cutout as returned by {@link #getBounds()}. * @param boundingRects the bounding rects of the display cutouts as returned by * {@link #getBoundingRects()} ()}. */ */ // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) public DisplayCutout(Rect safeInsets, Region bounds) { public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) { this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT, this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT, bounds != null ? Region.obtain(bounds) : Region.obtain(), boundingRectsToRegion(boundingRects), null /* frameSize */); true /* copyArguments */); } } /** /** * Creates a DisplayCutout instance. * Creates a DisplayCutout instance. * * * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged. * @param copyArguments if true, create a copy of the arguments. If false, the passed arguments * * are not copied and MUST remain unchanged forever. * @hide */ */ @VisibleForTesting private DisplayCutout(Rect safeInsets, Region bounds, boolean copyArguments) { public DisplayCutout(Rect safeInsets, Region bounds, Size frameSize) { mSafeInsets = safeInsets == null ? ZERO_RECT : mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT; (copyArguments ? new Rect(safeInsets) : safeInsets); mBounds = bounds != null ? bounds : Region.obtain(); mBounds = bounds == null ? Region.obtain() : mFrameSize = frameSize; (copyArguments ? Region.obtain(bounds) : bounds); } } /** /** * Returns true if there is no cutout or it is outside of the content view. * Returns true if the safe insets are empty (and therefore the current view does not * overlap with the cutout or cutout area). * * * @hide * @hide */ */ Loading @@ -128,6 +125,15 @@ public final class DisplayCutout { return mSafeInsets.equals(ZERO_RECT); return mSafeInsets.equals(ZERO_RECT); } } /** * Returns true if there is no cutout, i.e. the bounds are empty. * * @hide */ public boolean isBoundsEmpty() { return mBounds.isEmpty(); } /** 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. */ public int getSafeInsetTop() { public int getSafeInsetTop() { return mSafeInsets.top; return mSafeInsets.top; Loading Loading @@ -161,23 +167,60 @@ public final class DisplayCutout { /** /** * Returns the bounding region of the cutout. * Returns the bounding region of the cutout. * * * <p> * <strong>Note:</strong> There may be more than one cutout, in which case the returned * {@code Region} will be non-contiguous and its bounding rect will be meaningless without * intersecting it first. * * Example: * <pre> * // Getting the bounding rectangle of the top display cutout * Region bounds = displayCutout.getBounds(); * bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT); * Rect topDisplayCutout = bounds.getBoundingRect(); * </pre> * * @return the bounding region of the cutout. Coordinates are relative * @return the bounding region of the cutout. Coordinates are relative * to the top-left corner of the content view and in pixel units. * to the top-left corner of the content view and in pixel units. * @hide */ */ public Region getBounds() { public Region getBounds() { return Region.obtain(mBounds); return Region.obtain(mBounds); } } /** /** * Returns the bounding rect of the cutout. * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional * area on the display. * * * @return the bounding rect of the cutout. Coordinates are relative * There will be at most one non-functional area per short edge of the device, and none on * to the top-left corner of the content view. * the long edges. * @hide * * @return a list of bounding {@code Rect}s, one for each display cutout area. */ */ public Rect getBoundingRect() { public List<Rect> getBoundingRects() { // TODO(roosa): Inline. List<Rect> result = new ArrayList<>(); return mBounds.getBounds(); Region bounds = Region.obtain(); // top bounds.set(mBounds); bounds.op(0, 0, Integer.MAX_VALUE, getSafeInsetTop(), Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } // left bounds.set(mBounds); bounds.op(0, 0, getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } // right & bottom bounds.set(mBounds); bounds.op(getSafeInsetLeft() + 1, getSafeInsetTop() + 1, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); if (!bounds.isEmpty()) { result.add(bounds.getBounds()); } bounds.recycle(); return result; } } @Override @Override Loading @@ -195,8 +238,7 @@ public final class DisplayCutout { if (o instanceof DisplayCutout) { if (o instanceof DisplayCutout) { DisplayCutout c = (DisplayCutout) o; DisplayCutout c = (DisplayCutout) o; return mSafeInsets.equals(c.mSafeInsets) return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds) && mBounds.equals(c.mBounds); && Objects.equals(mFrameSize, c.mFrameSize); } } return false; return false; } } Loading @@ -204,7 +246,7 @@ public final class DisplayCutout { @Override @Override public String toString() { public String toString() { return "DisplayCutout{insets=" + mSafeInsets return "DisplayCutout{insets=" + mSafeInsets + " boundingRect=" + getBoundingRect() + " boundingRect=" + mBounds.getBounds() + "}"; + "}"; } } Loading Loading @@ -249,88 +291,19 @@ public final class DisplayCutout { } } bounds.translate(-insetLeft, -insetTop); bounds.translate(-insetLeft, -insetTop); Size frame = mFrameSize == null ? null : new Size( return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); mFrameSize.getWidth() - insetLeft - insetRight, mFrameSize.getHeight() - insetTop - insetBottom); return new DisplayCutout(safeInsets, bounds, frame); } } /** /** * Recalculates the cutout relative to the given reference frame. * Returns a copy of this instance with the safe insets replaced with the parameter. * * * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}. * @param safeInsets the new safe insets in pixels * @return a copy of this instance with the safe insets replaced with the argument. * * * @return a copy of this instance with the safe insets recalculated * @hide * @hide */ */ public DisplayCutout calculateRelativeTo(Rect frame) { public DisplayCutout replaceSafeInsets(Rect safeInsets) { return inset(frame.left, frame.top, return new DisplayCutout(new Rect(safeInsets), mBounds, false /* copyArguments */); mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom); } /** * Calculates the safe insets relative to the given display size. * * @return a copy of this instance with the safe insets calculated * @hide */ public DisplayCutout computeSafeInsets(int width, int height) { if (this == NO_CUTOUT || mBounds.isEmpty()) { return NO_CUTOUT; } return computeSafeInsets(new Size(width, height), mBounds); } private static DisplayCutout computeSafeInsets(Size displaySize, Region bounds) { Rect boundingRect = bounds.getBounds(); Rect safeRect = new Rect(); int bestArea = 0; int bestVariant = 0; for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) { int area = calculateInsetVariantArea(displaySize, boundingRect, variant, safeRect); if (bestArea < area) { bestArea = area; bestVariant = variant; } } calculateInsetVariantArea(displaySize, boundingRect, bestVariant, safeRect); if (safeRect.isEmpty()) { // The entire displaySize overlaps with the cutout. safeRect.set(0, displaySize.getHeight(), 0, 0); } else { // Convert safeRect to insets relative to displaySize. We're reusing the rect here to // avoid an allocation. safeRect.set( Math.max(0, safeRect.left), Math.max(0, safeRect.top), Math.max(0, displaySize.getWidth() - safeRect.right), Math.max(0, displaySize.getHeight() - safeRect.bottom)); } return new DisplayCutout(safeRect, bounds, displaySize); } private static int calculateInsetVariantArea(Size display, Rect boundingRect, int variant, Rect outSafeRect) { switch (variant) { case ROTATION_0: outSafeRect.set(0, 0, display.getWidth(), boundingRect.top); break; case ROTATION_90: outSafeRect.set(0, 0, boundingRect.left, display.getHeight()); break; case ROTATION_180: outSafeRect.set(0, boundingRect.bottom, display.getWidth(), display.getHeight()); break; case ROTATION_270: outSafeRect.set(boundingRect.right, 0, display.getWidth(), display.getHeight()); break; } return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height(); } } private static int atLeastZero(int value) { private static int atLeastZero(int value) { Loading Loading @@ -369,7 +342,7 @@ public final class DisplayCutout { Region bounds = new Region(); Region bounds = new Region(); bounds.setPath(path, clipRegion); bounds.setPath(path, clipRegion); clipRegion.recycle(); clipRegion.recycle(); return new DisplayCutout(ZERO_RECT, bounds, null /* frameSize */); return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */); } } /** /** Loading @@ -377,9 +350,9 @@ public final class DisplayCutout { * * * @hide * @hide */ */ public static DisplayCutout fromResources(Resources res, int displayWidth) { public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) { return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), displayWidth, res.getDisplayMetrics().density); displayWidth, displayHeight, res.getDisplayMetrics().density); } } /** /** Loading @@ -388,7 +361,8 @@ public final class DisplayCutout { * @hide * @hide */ */ @VisibleForTesting(visibility = PRIVATE) @VisibleForTesting(visibility = PRIVATE) public static DisplayCutout fromSpec(String spec, int displayWidth, float density) { public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight, float density) { if (TextUtils.isEmpty(spec)) { if (TextUtils.isEmpty(spec)) { return null; return null; } } Loading @@ -404,7 +378,14 @@ public final class DisplayCutout { spec = spec.substring(0, spec.length() - DP_MARKER.length()); spec = spec.substring(0, spec.length() - DP_MARKER.length()); } } Path p; String bottomSpec = null; if (spec.contains(BOTTOM_MARKER)) { String[] splits = spec.split(BOTTOM_MARKER, 2); spec = splits[0].trim(); bottomSpec = splits[1].trim(); } final Path p; try { try { p = PathParser.createPathFromPathData(spec); p = PathParser.createPathFromPathData(spec); } catch (Throwable e) { } catch (Throwable e) { Loading @@ -419,6 +400,20 @@ public final class DisplayCutout { m.postTranslate(displayWidth / 2f, 0); m.postTranslate(displayWidth / 2f, 0); p.transform(m); p.transform(m); if (bottomSpec != null) { final Path bottomPath; try { bottomPath = PathParser.createPathFromPathData(bottomSpec); } catch (Throwable e) { Log.wtf(TAG, "Could not inflate bottom cutout: ", e); return null; } // Keep top transform m.postTranslate(0, displayHeight); bottomPath.transform(m); p.addPath(bottomPath); } final DisplayCutout result = fromBounds(p); final DisplayCutout result = fromBounds(p); synchronized (CACHE_LOCK) { synchronized (CACHE_LOCK) { sCachedSpec = spec; sCachedSpec = spec; Loading @@ -429,6 +424,16 @@ public final class DisplayCutout { return result; return result; } } private static Region boundingRectsToRegion(List<Rect> rects) { Region result = Region.obtain(); if (rects != null) { for (Rect r : rects) { result.op(r, Region.Op.UNION); } } return result; } /** /** * Helper class for passing {@link DisplayCutout} through binder. * Helper class for passing {@link DisplayCutout} through binder. * * Loading Loading @@ -472,12 +477,6 @@ public final class DisplayCutout { out.writeInt(1); out.writeInt(1); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedObject(cutout.mBounds, flags); out.writeTypedObject(cutout.mBounds, flags); if (cutout.mFrameSize != null) { out.writeInt(cutout.mFrameSize.getWidth()); out.writeInt(cutout.mFrameSize.getHeight()); } else { out.writeInt(-1); } } } } } Loading Loading @@ -520,10 +519,7 @@ public final class DisplayCutout { Rect safeInsets = in.readTypedObject(Rect.CREATOR); Rect safeInsets = in.readTypedObject(Rect.CREATOR); Region bounds = in.readTypedObject(Region.CREATOR); Region bounds = in.readTypedObject(Region.CREATOR); int width = in.readInt(); return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); Size frameSize = width >= 0 ? new Size(width, in.readInt()) : null; return new DisplayCutout(safeInsets, bounds, frameSize); } } public DisplayCutout get() { public DisplayCutout get() { Loading
core/java/android/view/WindowManager.java +20 −8 Original line number Original line Diff line number Diff line Loading @@ -2241,18 +2241,20 @@ public interface WindowManager extends ViewManager { /** /** * The window is allowed to extend into the {@link DisplayCutout} area, only if the * The window is allowed to extend into the {@link DisplayCutout} area, only if the * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is * laid out such that it does not overlap with the {@link DisplayCutout} area. * laid out such that it does not overlap with the {@link DisplayCutout} area. * * * <p> * <p> * In practice, this means that if the window did not set FLAG_FULLSCREEN or * In practice, this means that if the window did not set FLAG_FULLSCREEN or * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait. * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the * bottom of the screen. * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the * cutout area. * cutout area. * * * <p> * <p> * The usual precautions for not overlapping with the status bar are sufficient for ensuring * The usual precautions for not overlapping with the status and navigation bar are * that no important content overlaps with the DisplayCutout. * sufficient for ensuring that no important content overlaps with the DisplayCutout. * * * @see DisplayCutout * @see DisplayCutout * @see WindowInsets * @see WindowInsets Loading @@ -2260,8 +2262,18 @@ public interface WindowManager extends ViewManager { public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; /** /** * The window is always allowed to extend into the {@link DisplayCutout} area, * @deprecated use {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES} * even if fullscreen or in landscape. * @hide */ @Deprecated public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; /** * The window is always allowed to extend into the {@link DisplayCutout} areas on the short * edges of the screen. * * The window will never extend into a {@link DisplayCutout} area on the long edges of the * screen. * * * <p> * <p> * The window must make sure that no important content overlaps with the * The window must make sure that no important content overlaps with the Loading @@ -2270,7 +2282,7 @@ public interface WindowManager extends ViewManager { * @see DisplayCutout * @see DisplayCutout * @see WindowInsets#getDisplayCutout() * @see WindowInsets#getDisplayCutout() */ */ public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; /** /** * The window is never allowed to overlap with the DisplayCutout area. * The window is never allowed to overlap with the DisplayCutout area. Loading
core/res/res/values/attrs.xml +9 −6 Original line number Original line Diff line number Diff line Loading @@ -2125,29 +2125,32 @@ Defaults to {@code default}. Defaults to {@code default}. @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.R.attr#layoutInDisplayCutoutMode --> @see android.R.attr#layoutInDisplayCutoutMode --> <attr name="windowLayoutInDisplayCutoutMode"> <attr name="windowLayoutInDisplayCutoutMode"> <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the {@code DisplayCutout} is fully contained within the status bar. Otherwise, the window is {@code DisplayCutout} is fully contained within a system bar. Otherwise, the window is laid out such that it does not overlap with the {@code DisplayCutout} area. laid out such that it does not overlap with the {@code DisplayCutout} area. @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT --> --> <enum name="default" value="0" /> <enum name="default" value="0" /> <!-- The window is always allowed to extend into the {@code DisplayCutout} area, <!-- even if fullscreen or in landscape. The window is always allowed to extend into the {@code DisplayCutout} areas on the short edges of the screen even if fullscreen or in landscape. The window will never extend into a {@link DisplayCutout} area on the long edges of the screen. <p> <p> The window must make sure that no important content overlaps with the The window must make sure that no important content overlaps with the {@link DisplayCutout}. {@link DisplayCutout}. @see android.view.DisplayCutout @see android.view.DisplayCutout @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES --> --> <enum name="always" value="1" /> <enum name="shortEdges" value="1" /> <!-- The window is never allowed to overlap with the DisplayCutout area. <!-- The window is never allowed to overlap with the DisplayCutout area. <p> <p> This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN} This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN} Loading
core/tests/coretests/res/values/styles.xml +2 −2 Original line number Original line Diff line number Diff line Loading @@ -25,8 +25,8 @@ <style name="LayoutInDisplayCutoutModeDefault"> <style name="LayoutInDisplayCutoutModeDefault"> <item name="android:windowLayoutInDisplayCutoutMode">default</item> <item name="android:windowLayoutInDisplayCutoutMode">default</item> </style> </style> <style name="LayoutInDisplayCutoutModeAlways"> <style name="LayoutInDisplayCutoutModeShortEdges"> <item name="android:windowLayoutInDisplayCutoutMode">always</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> </style> </style> <style name="LayoutInDisplayCutoutModeNever"> <style name="LayoutInDisplayCutoutModeNever"> <item name="android:windowLayoutInDisplayCutoutMode">never</item> <item name="android:windowLayoutInDisplayCutoutMode">never</item> Loading