Create an API to get a cutout path
- Added a new API to get the cutout paths.
- Create a @hide class CutoutPathParserInfo
- Used to store the needed info to create the cutout paths.
- Will be used when DisplayCutout.getCutoutPath() is called to
create the cutout paths.
Bug: 172646505
Test: atest DisplayCutoutTest DisplayContentTests WmDisplayCutoutTest
Change-Id: Ief92ce4466f6bffb2a9375388b71de43049b4eef
This commit is contained in:
@@ -46174,6 +46174,7 @@ package android.view {
|
||||
method @NonNull public android.graphics.Rect getBoundingRectRight();
|
||||
method @NonNull public android.graphics.Rect getBoundingRectTop();
|
||||
method @NonNull public java.util.List<android.graphics.Rect> getBoundingRects();
|
||||
method @Nullable public android.graphics.Path getCutoutPath();
|
||||
method public int getSafeInsetBottom();
|
||||
method public int getSafeInsetLeft();
|
||||
method public int getSafeInsetRight();
|
||||
|
||||
@@ -21,7 +21,9 @@ import static android.view.Surface.ROTATION_180;
|
||||
import static android.view.Surface.ROTATION_270;
|
||||
import static android.view.Surface.ROTATION_90;
|
||||
|
||||
import android.annotation.Dimension;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.view.Surface.Rotation;
|
||||
|
||||
/**
|
||||
@@ -69,4 +71,34 @@ public class RotationUtils {
|
||||
}
|
||||
return rotated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a matrix such that given a rotation, it transforms physical display
|
||||
* coordinates to that rotation's logical coordinates.
|
||||
*
|
||||
* @param rotation the rotation to which the matrix should transform
|
||||
* @param out the matrix to be set
|
||||
*/
|
||||
public static void transformPhysicalToLogicalCoordinates(@Rotation int rotation,
|
||||
@Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
|
||||
switch (rotation) {
|
||||
case ROTATION_0:
|
||||
out.reset();
|
||||
break;
|
||||
case ROTATION_90:
|
||||
out.setRotate(270);
|
||||
out.postTranslate(0, physicalWidth);
|
||||
break;
|
||||
case ROTATION_180:
|
||||
out.setRotate(180);
|
||||
out.postTranslate(physicalWidth, physicalHeight);
|
||||
break;
|
||||
case ROTATION_270:
|
||||
out.setRotate(90);
|
||||
out.postTranslate(physicalHeight, 0);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown rotation: " + rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.view.DisplayCutoutProto.BOUND_LEFT;
|
||||
import static android.view.DisplayCutoutProto.BOUND_RIGHT;
|
||||
import static android.view.DisplayCutoutProto.BOUND_TOP;
|
||||
import static android.view.DisplayCutoutProto.INSETS;
|
||||
import static android.view.Surface.ROTATION_0;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||
|
||||
@@ -31,13 +32,16 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.RotationUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.Surface.Rotation;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -69,6 +73,9 @@ public final class DisplayCutout {
|
||||
"com.android.internal.display_cutout_emulation";
|
||||
|
||||
private static final Rect ZERO_RECT = new Rect();
|
||||
private static final CutoutPathParserInfo EMPTY_PARSER_INFO = new CutoutPathParserInfo(
|
||||
0 /* displayWidth */, 0 /* displayHeight */, 0f /* density */, "" /* cutoutSpec */,
|
||||
0 /* rotation */, 0f /* scale */);
|
||||
|
||||
/**
|
||||
* An instance where {@link #isEmpty()} returns {@code true}.
|
||||
@@ -76,7 +83,7 @@ public final class DisplayCutout {
|
||||
* @hide
|
||||
*/
|
||||
public static final DisplayCutout NO_CUTOUT = new DisplayCutout(
|
||||
ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT,
|
||||
ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT, EMPTY_PARSER_INFO,
|
||||
false /* copyArguments */);
|
||||
|
||||
|
||||
@@ -96,11 +103,15 @@ public final class DisplayCutout {
|
||||
@GuardedBy("CACHE_LOCK")
|
||||
private static Insets sCachedWaterfallInsets;
|
||||
|
||||
@GuardedBy("CACHE_LOCK")
|
||||
private static CutoutPathParserInfo sCachedCutoutPathParserInfo;
|
||||
@GuardedBy("CACHE_LOCK")
|
||||
private static Path sCachedCutoutPath;
|
||||
|
||||
private final Rect mSafeInsets;
|
||||
@NonNull
|
||||
private final Insets mWaterfallInsets;
|
||||
|
||||
|
||||
/**
|
||||
* The bound is at the left of the screen.
|
||||
* @hide
|
||||
@@ -210,6 +221,7 @@ public final class DisplayCutout {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o == this) {
|
||||
@@ -231,6 +243,106 @@ public final class DisplayCutout {
|
||||
|
||||
private final Bounds mBounds;
|
||||
|
||||
/**
|
||||
* Stores all the needed info to create the cutout paths.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class CutoutPathParserInfo {
|
||||
private final int mDisplayWidth;
|
||||
private final int mDisplayHeight;
|
||||
private final float mDensity;
|
||||
private final String mCutoutSpec;
|
||||
private final @Rotation int mRotation;
|
||||
private final float mScale;
|
||||
|
||||
public CutoutPathParserInfo(int displayWidth, int displayHeight, float density,
|
||||
String cutoutSpec, @Rotation int rotation, float scale) {
|
||||
mDisplayWidth = displayWidth;
|
||||
mDisplayHeight = displayHeight;
|
||||
mDensity = density;
|
||||
mCutoutSpec = cutoutSpec == null ? "" : cutoutSpec;
|
||||
mRotation = rotation;
|
||||
mScale = scale;
|
||||
}
|
||||
|
||||
public CutoutPathParserInfo(CutoutPathParserInfo cutoutPathParserInfo) {
|
||||
mDisplayWidth = cutoutPathParserInfo.mDisplayWidth;
|
||||
mDisplayHeight = cutoutPathParserInfo.mDisplayHeight;
|
||||
mDensity = cutoutPathParserInfo.mDensity;
|
||||
mCutoutSpec = cutoutPathParserInfo.mCutoutSpec;
|
||||
mRotation = cutoutPathParserInfo.mRotation;
|
||||
mScale = cutoutPathParserInfo.mScale;
|
||||
}
|
||||
|
||||
public int getDisplayWidth() {
|
||||
return mDisplayWidth;
|
||||
}
|
||||
|
||||
public int getDisplayHeight() {
|
||||
return mDisplayHeight;
|
||||
}
|
||||
|
||||
public float getDensity() {
|
||||
return mDensity;
|
||||
}
|
||||
|
||||
public @NonNull String getCutoutSpec() {
|
||||
return mCutoutSpec;
|
||||
}
|
||||
|
||||
public int getRotation() {
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return mScale;
|
||||
}
|
||||
|
||||
private boolean hasCutout() {
|
||||
return !mCutoutSpec.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 0;
|
||||
result = result * 48271 + Integer.hashCode(mDisplayWidth);
|
||||
result = result * 48271 + Integer.hashCode(mDisplayHeight);
|
||||
result = result * 48271 + Float.hashCode(mDensity);
|
||||
result = result * 48271 + mCutoutSpec.hashCode();
|
||||
result = result * 48271 + Integer.hashCode(mRotation);
|
||||
result = result * 48271 + Float.hashCode(mScale);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof CutoutPathParserInfo) {
|
||||
CutoutPathParserInfo c = (CutoutPathParserInfo) o;
|
||||
return mDisplayWidth == c.mDisplayWidth && mDisplayHeight == c.mDisplayHeight
|
||||
&& mDensity == c.mDensity && mCutoutSpec.equals(c.mCutoutSpec)
|
||||
&& mRotation == c.mRotation && mScale == c.mScale;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CutoutPathParserInfo{displayWidth=" + mDisplayWidth
|
||||
+ " displayHeight=" + mDisplayHeight
|
||||
+ " density={" + mDensity + "}"
|
||||
+ " cutoutSpec={" + mCutoutSpec + "}"
|
||||
+ " rotation={" + mRotation + "}"
|
||||
+ " scale={" + mScale + "}"
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
private final @NonNull CutoutPathParserInfo mCutoutPathParserInfo;
|
||||
|
||||
/**
|
||||
* Creates a DisplayCutout instance.
|
||||
*
|
||||
@@ -251,7 +363,8 @@ public final class DisplayCutout {
|
||||
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
|
||||
public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
|
||||
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
|
||||
this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, true);
|
||||
this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, null,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +389,7 @@ public final class DisplayCutout {
|
||||
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom,
|
||||
@NonNull Insets waterfallInsets) {
|
||||
this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
|
||||
true);
|
||||
null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,7 +407,7 @@ public final class DisplayCutout {
|
||||
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
|
||||
@Deprecated
|
||||
public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
|
||||
this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects),
|
||||
this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects), null,
|
||||
true /* copyArguments */);
|
||||
}
|
||||
|
||||
@@ -303,28 +416,42 @@ public final class DisplayCutout {
|
||||
*
|
||||
* @param safeInsets the insets from each edge which avoid the display cutout as returned by
|
||||
* {@link #getSafeInsetTop()} etc.
|
||||
* @param waterfallInsets the insets for the curved areas in waterfall display.
|
||||
* @param boundLeft the left bounding rect of the display cutout in pixels. If null is passed,
|
||||
* it's treated as an empty rectangle (0,0)-(0,0).
|
||||
* @param boundTop the top bounding rect of the display cutout in pixels. If null is passed,
|
||||
* it's treated as an empty rectangle (0,0)-(0,0).
|
||||
* @param boundRight the right bounding rect of the display cutout in pixels. If null is
|
||||
* passed, it's treated as an empty rectangle (0,0)-(0,0).
|
||||
* @param boundBottom the bottom bounding rect of the display cutout in pixels. If null is
|
||||
* passed, it's treated as an empty rectangle (0,0)-(0,0).
|
||||
* @param info the cutout path parser info.
|
||||
* @param copyArguments if true, create a copy of the arguments. If false, the passed arguments
|
||||
* are not copied and MUST remain unchanged forever.
|
||||
*/
|
||||
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft,
|
||||
Rect boundTop, Rect boundRight, Rect boundBottom, boolean copyArguments) {
|
||||
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft, Rect boundTop,
|
||||
Rect boundRight, Rect boundBottom, CutoutPathParserInfo info,
|
||||
boolean copyArguments) {
|
||||
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
|
||||
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
|
||||
mBounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments);
|
||||
mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
|
||||
}
|
||||
|
||||
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect[] bounds,
|
||||
boolean copyArguments) {
|
||||
CutoutPathParserInfo info, boolean copyArguments) {
|
||||
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
|
||||
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
|
||||
mBounds = new Bounds(bounds, copyArguments);
|
||||
mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
|
||||
}
|
||||
|
||||
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds) {
|
||||
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds,
|
||||
CutoutPathParserInfo info) {
|
||||
mSafeInsets = safeInsets;
|
||||
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
|
||||
mBounds = bounds;
|
||||
|
||||
mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
|
||||
}
|
||||
|
||||
private static Rect getCopyOrRef(Rect r, boolean copyArguments) {
|
||||
@@ -534,10 +661,70 @@ public final class DisplayCutout {
|
||||
return mBounds.getRect(BOUNDS_POSITION_BOTTOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Path} that contains the cutout paths of all sides on the display.
|
||||
*
|
||||
* To get a cutout path for one specific side, apps can intersect the {@link Path} with the
|
||||
* {@link Rect} obtained from {@link #getBoundingRectLeft()}, {@link #getBoundingRectTop()},
|
||||
* {@link #getBoundingRectRight()} or {@link #getBoundingRectBottom()}.
|
||||
*
|
||||
* @return a {@link Path} contains all the cutout paths based on display coordinate. Returns
|
||||
* null if there is no cutout on the display.
|
||||
*/
|
||||
public @Nullable Path getCutoutPath() {
|
||||
if (!mCutoutPathParserInfo.hasCutout()) {
|
||||
return null;
|
||||
}
|
||||
synchronized (CACHE_LOCK) {
|
||||
if (mCutoutPathParserInfo.equals(sCachedCutoutPathParserInfo)) {
|
||||
return sCachedCutoutPath;
|
||||
}
|
||||
}
|
||||
final CutoutSpecification cutoutSpec = new CutoutSpecification.Parser(
|
||||
mCutoutPathParserInfo.getDensity(), mCutoutPathParserInfo.getDisplayWidth(),
|
||||
mCutoutPathParserInfo.getDisplayHeight())
|
||||
.parse(mCutoutPathParserInfo.getCutoutSpec());
|
||||
|
||||
final Path cutoutPath = cutoutSpec.getPath();
|
||||
if (cutoutPath == null || cutoutPath.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final Matrix matrix = new Matrix();
|
||||
if (mCutoutPathParserInfo.getRotation() != ROTATION_0) {
|
||||
RotationUtils.transformPhysicalToLogicalCoordinates(
|
||||
mCutoutPathParserInfo.getRotation(),
|
||||
mCutoutPathParserInfo.getDisplayWidth(),
|
||||
mCutoutPathParserInfo.getDisplayHeight(),
|
||||
matrix
|
||||
);
|
||||
}
|
||||
matrix.postScale(mCutoutPathParserInfo.getScale(), mCutoutPathParserInfo.getScale());
|
||||
cutoutPath.transform(matrix);
|
||||
|
||||
synchronized (CACHE_LOCK) {
|
||||
sCachedCutoutPathParserInfo = new CutoutPathParserInfo(mCutoutPathParserInfo);
|
||||
sCachedCutoutPath = cutoutPath;
|
||||
}
|
||||
return cutoutPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link CutoutPathParserInfo};
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public CutoutPathParserInfo getCutoutPathParserInfo() {
|
||||
return mCutoutPathParserInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mSafeInsets.hashCode() * 48271 + mBounds.hashCode()) * 48271
|
||||
+ mWaterfallInsets.hashCode();
|
||||
int result = 0;
|
||||
result = 48271 * result + mSafeInsets.hashCode();
|
||||
result = 48271 * result + mBounds.hashCode();
|
||||
result = 48271 * result + mWaterfallInsets.hashCode();
|
||||
result = 48271 * result + mCutoutPathParserInfo.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -548,7 +735,8 @@ public final class DisplayCutout {
|
||||
if (o instanceof DisplayCutout) {
|
||||
DisplayCutout c = (DisplayCutout) o;
|
||||
return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds)
|
||||
&& mWaterfallInsets.equals(c.mWaterfallInsets);
|
||||
&& mWaterfallInsets.equals(c.mWaterfallInsets)
|
||||
&& mCutoutPathParserInfo.equals(c.mCutoutPathParserInfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -558,6 +746,7 @@ public final class DisplayCutout {
|
||||
return "DisplayCutout{insets=" + mSafeInsets
|
||||
+ " waterfall=" + mWaterfallInsets
|
||||
+ " boundingRect={" + mBounds + "}"
|
||||
+ " cutoutPathParserInfo={" + mCutoutPathParserInfo + "}"
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@@ -607,7 +796,7 @@ public final class DisplayCutout {
|
||||
}
|
||||
|
||||
return new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds,
|
||||
false /* copyArguments */);
|
||||
mCutoutPathParserInfo, false /* copyArguments */);
|
||||
}
|
||||
|
||||
private Rect insetInsets(int insetLeft, int insetTop, int insetRight, int insetBottom,
|
||||
@@ -638,7 +827,8 @@ public final class DisplayCutout {
|
||||
* @hide
|
||||
*/
|
||||
public DisplayCutout replaceSafeInsets(Rect safeInsets) {
|
||||
return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds);
|
||||
return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds,
|
||||
mCutoutPathParserInfo);
|
||||
}
|
||||
|
||||
private static int atLeastZero(int value) {
|
||||
@@ -658,16 +848,18 @@ public final class DisplayCutout {
|
||||
for (int i = 0; i < BOUNDS_POSITION_LENGTH; ++i) {
|
||||
bounds[i] = (pos == i) ? new Rect(left, top, right, bottom) : new Rect();
|
||||
}
|
||||
return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
|
||||
return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null, false /* copyArguments */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from a bounding and waterfall insets.
|
||||
* Creates an instance from bounds, waterfall insets and CutoutPathParserInfo.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static DisplayCutout fromBoundsAndWaterfall(Rect[] bounds, Insets waterfallInsets) {
|
||||
return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, false /* copyArguments */);
|
||||
public static DisplayCutout constructDisplayCutout(Rect[] bounds, Insets waterfallInsets,
|
||||
CutoutPathParserInfo info) {
|
||||
return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, info,
|
||||
false /* copyArguments */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -676,7 +868,8 @@ public final class DisplayCutout {
|
||||
* @hide
|
||||
*/
|
||||
public static DisplayCutout fromBounds(Rect[] bounds) {
|
||||
return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
|
||||
return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null /* cutoutPathParserInfo */,
|
||||
false /* copyArguments */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -686,10 +879,12 @@ public final class DisplayCutout {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
|
||||
return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
|
||||
public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
|
||||
int displayHeight) {
|
||||
return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
|
||||
res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
|
||||
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
|
||||
loadWaterfallInset(res));
|
||||
loadWaterfallInset(res)).second;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -699,7 +894,7 @@ public final class DisplayCutout {
|
||||
*/
|
||||
public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
|
||||
return pathAndDisplayCutoutFromSpec(
|
||||
res.getString(R.string.config_mainBuiltInDisplayCutout),
|
||||
res.getString(R.string.config_mainBuiltInDisplayCutout), null,
|
||||
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
|
||||
loadWaterfallInset(res)).first;
|
||||
}
|
||||
@@ -710,14 +905,30 @@ public final class DisplayCutout {
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
|
||||
float density, Insets waterfallInsets) {
|
||||
public static DisplayCutout fromSpec(String pathSpec, int displayWidth,
|
||||
int displayHeight, float density, Insets waterfallInsets) {
|
||||
return pathAndDisplayCutoutFromSpec(
|
||||
spec, displayWidth, displayHeight, density, waterfallInsets).second;
|
||||
pathSpec, null, displayWidth, displayHeight, density, waterfallInsets)
|
||||
.second;
|
||||
}
|
||||
|
||||
private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(String spec,
|
||||
int displayWidth, int displayHeight, float density, Insets waterfallInsets) {
|
||||
/**
|
||||
* Gets the cutout path and the corresponding DisplayCutout instance from the spec string.
|
||||
*
|
||||
* @param pathSpec the spec string read from config_mainBuiltInDisplayCutout.
|
||||
* @param rectSpec the spec string read from config_mainBuiltInDisplayCutoutRectApproximation.
|
||||
* @param displayWidth the display width.
|
||||
* @param displayHeight the display height.
|
||||
* @param density the display density.
|
||||
* @param waterfallInsets the waterfall insets of the display.
|
||||
* @return a Pair contains the cutout path and the corresponding DisplayCutout instance.
|
||||
*/
|
||||
private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(
|
||||
String pathSpec, String rectSpec, int displayWidth, int displayHeight, float density,
|
||||
Insets waterfallInsets) {
|
||||
// Always use the rect approximation spec to create the cutout if it's not null because
|
||||
// transforming and sending a Region constructed from a path is very costly.
|
||||
String spec = rectSpec != null ? rectSpec : pathSpec;
|
||||
if (TextUtils.isEmpty(spec) && waterfallInsets.equals(Insets.NONE)) {
|
||||
return NULL_PAIR;
|
||||
}
|
||||
@@ -750,9 +961,12 @@ public final class DisplayCutout {
|
||||
Math.max(waterfallInsets.bottom, safeInset.bottom));
|
||||
}
|
||||
|
||||
final CutoutPathParserInfo cutoutPathParserInfo = new CutoutPathParserInfo(displayWidth,
|
||||
displayHeight, density, pathSpec.trim(), ROTATION_0, 1f /* scale */);
|
||||
|
||||
final DisplayCutout cutout = new DisplayCutout(
|
||||
safeInset, waterfallInsets, boundLeft, boundTop,
|
||||
boundRight, boundBottom, false /* copyArguments */);
|
||||
safeInset, waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
|
||||
cutoutPathParserInfo , false /* copyArguments */);
|
||||
final Pair<Path, DisplayCutout> result = new Pair<>(cutoutSpec.getPath(), cutout);
|
||||
synchronized (CACHE_LOCK) {
|
||||
sCachedSpec = spec;
|
||||
@@ -817,6 +1031,12 @@ public final class DisplayCutout {
|
||||
out.writeTypedObject(cutout.mSafeInsets, flags);
|
||||
out.writeTypedArray(cutout.mBounds.getRects(), flags);
|
||||
out.writeTypedObject(cutout.mWaterfallInsets, flags);
|
||||
out.writeInt(cutout.mCutoutPathParserInfo.getDisplayWidth());
|
||||
out.writeInt(cutout.mCutoutPathParserInfo.getDisplayHeight());
|
||||
out.writeFloat(cutout.mCutoutPathParserInfo.getDensity());
|
||||
out.writeString(cutout.mCutoutPathParserInfo.getCutoutSpec());
|
||||
out.writeInt(cutout.mCutoutPathParserInfo.getRotation());
|
||||
out.writeFloat(cutout.mCutoutPathParserInfo.getScale());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,9 +1080,17 @@ public final class DisplayCutout {
|
||||
Rect[] bounds = new Rect[BOUNDS_POSITION_LENGTH];
|
||||
in.readTypedArray(bounds, Rect.CREATOR);
|
||||
Insets waterfallInsets = in.readTypedObject(Insets.CREATOR);
|
||||
int displayWidth = in.readInt();
|
||||
int displayHeight = in.readInt();
|
||||
float density = in.readFloat();
|
||||
String cutoutSpec = in.readString();
|
||||
int rotation = in.readInt();
|
||||
float scale = in.readFloat();
|
||||
final CutoutPathParserInfo info = new CutoutPathParserInfo(
|
||||
displayWidth, displayHeight, density, cutoutSpec, rotation, scale);
|
||||
|
||||
return new DisplayCutout(
|
||||
safeInsets, waterfallInsets, bounds, false /* copyArguments */);
|
||||
safeInsets, waterfallInsets, bounds, info, false /* copyArguments */);
|
||||
}
|
||||
|
||||
public DisplayCutout get() {
|
||||
@@ -884,7 +1112,15 @@ public final class DisplayCutout {
|
||||
bounds.scale(scale);
|
||||
final Rect waterfallInsets = mInner.mWaterfallInsets.toRect();
|
||||
waterfallInsets.scale(scale);
|
||||
mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds);
|
||||
final CutoutPathParserInfo info = new CutoutPathParserInfo(
|
||||
mInner.mCutoutPathParserInfo.getDisplayWidth(),
|
||||
mInner.mCutoutPathParserInfo.getDisplayHeight(),
|
||||
mInner.mCutoutPathParserInfo.getDensity(),
|
||||
mInner.mCutoutPathParserInfo.getCutoutSpec(),
|
||||
mInner.mCutoutPathParserInfo.getRotation(),
|
||||
scale);
|
||||
|
||||
mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,8 @@ import static android.view.DisplayCutout.fromSpec;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -30,6 +32,7 @@ import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -130,6 +133,8 @@ public class DisplayCutoutTest {
|
||||
@Test
|
||||
public void testHasCutout_noCutout() throws Exception {
|
||||
assertTrue(NO_CUTOUT.isBoundsEmpty());
|
||||
assertThat(NO_CUTOUT.getWaterfallInsets(), equalTo(Insets.NONE));
|
||||
assertThat(NO_CUTOUT.getCutoutPath(), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,6 +169,59 @@ public class DisplayCutoutTest {
|
||||
assertEquals(Insets.of(5, 6, 7, 8), cutout.getWaterfallInsets());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCutoutPath() throws Exception {
|
||||
final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
|
||||
final int displayWidth = 200;
|
||||
final int displayHeight = 400;
|
||||
final float density = 1f;
|
||||
final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
|
||||
density, Insets.NONE);
|
||||
assertThat(cutout.getCutoutPath(), notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCutoutPath_caches() throws Exception {
|
||||
final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
|
||||
final int displayWidth = 200;
|
||||
final int displayHeight = 400;
|
||||
final float density = 1f;
|
||||
final Path first = fromSpec(cutoutSpecString, displayWidth, displayHeight,
|
||||
density, Insets.NONE).getCutoutPath();
|
||||
final Path second = fromSpec(cutoutSpecString, displayWidth, displayHeight,
|
||||
density, Insets.NONE).getCutoutPath();
|
||||
assertThat(first, equalTo(second));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCutoutPath_wontCacheIfCutoutPathParerInfoChanged() throws Exception {
|
||||
final int displayWidth = 200;
|
||||
final int displayHeight = 400;
|
||||
final float density = 1f;
|
||||
final Path first = fromSpec("L1,0 L1,1 L0,1 z", displayWidth, displayHeight,
|
||||
density, Insets.NONE).getCutoutPath();
|
||||
final Path second = fromSpec("L2,0 L2,2 L0,2 z", displayWidth, displayHeight,
|
||||
density, Insets.NONE).getCutoutPath();
|
||||
assertThat(first, not(equalTo(second)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCutoutPathParserInfo() throws Exception {
|
||||
final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
|
||||
final int displayWidth = 200;
|
||||
final int displayHeight = 400;
|
||||
final float density = 1f;
|
||||
final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
|
||||
density, Insets.NONE);
|
||||
assertThat(displayWidth, equalTo(cutout.getCutoutPathParserInfo().getDisplayWidth()));
|
||||
assertThat(displayHeight, equalTo(cutout.getCutoutPathParserInfo().getDisplayHeight()));
|
||||
assertThat(density, equalTo(cutout.getCutoutPathParserInfo().getDensity()));
|
||||
assertThat(cutoutSpecString.trim(),
|
||||
equalTo(cutout.getCutoutPathParserInfo().getCutoutSpec()));
|
||||
assertThat(0, equalTo(cutout.getCutoutPathParserInfo().getRotation()));
|
||||
assertThat(1f, equalTo(cutout.getCutoutPathParserInfo().getScale()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashCode() throws Exception {
|
||||
assertEquals(mCutoutWithWaterfall.hashCode(), createCutoutWithWaterfall().hashCode());
|
||||
|
||||
@@ -356,11 +356,11 @@ public class DisplayLayout {
|
||||
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
|
||||
return null;
|
||||
}
|
||||
final Insets waterfallInsets =
|
||||
RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
|
||||
if (rotation == ROTATION_0) {
|
||||
return computeSafeInsets(cutout, displayWidth, displayHeight);
|
||||
}
|
||||
final Insets waterfallInsets =
|
||||
RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
|
||||
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
|
||||
Rect[] cutoutRects = cutout.getBoundingRectsAll();
|
||||
final Rect[] newBounds = new Rect[cutoutRects.length];
|
||||
@@ -372,8 +372,12 @@ public class DisplayLayout {
|
||||
}
|
||||
newBounds[getBoundIndexFromRotation(i, rotation)] = rect;
|
||||
}
|
||||
final DisplayCutout.CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
|
||||
final DisplayCutout.CutoutPathParserInfo newInfo = new DisplayCutout.CutoutPathParserInfo(
|
||||
info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
|
||||
info.getCutoutSpec(), rotation, info.getScale());
|
||||
return computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
|
||||
DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
|
||||
rotated ? displayHeight : displayWidth,
|
||||
rotated ? displayWidth : displayHeight);
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ import android.util.SparseBooleanArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.DisplayCutout.CutoutPathParserInfo;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.IDisplayWindowInsetsController;
|
||||
@@ -1937,18 +1938,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
|
||||
return WmDisplayCutout.NO_CUTOUT;
|
||||
}
|
||||
final Insets waterfallInsets =
|
||||
RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
|
||||
if (rotation == ROTATION_0) {
|
||||
return WmDisplayCutout.computeSafeInsets(
|
||||
cutout, mInitialDisplayWidth, mInitialDisplayHeight);
|
||||
}
|
||||
final Insets waterfallInsets =
|
||||
RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
|
||||
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
|
||||
final Rect[] newBounds = mRotationUtil.getRotatedBounds(
|
||||
cutout.getBoundingRectsAll(),
|
||||
rotation, mInitialDisplayWidth, mInitialDisplayHeight);
|
||||
final CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
|
||||
final CutoutPathParserInfo newInfo = new CutoutPathParserInfo(
|
||||
info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
|
||||
info.getCutoutSpec(), rotation, info.getScale());
|
||||
return WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
|
||||
DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
|
||||
rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
|
||||
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import static android.os.Build.VERSION_CODES.P;
|
||||
import static android.os.Build.VERSION_CODES.Q;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.FLAG_PRIVATE;
|
||||
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
|
||||
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
|
||||
import static android.view.DisplayCutout.fromBoundingRect;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
@@ -96,6 +95,7 @@ import android.app.ActivityTaskManager;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.app.servertransaction.FixedRotationAdjustmentsItem;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.metrics.LogMaker;
|
||||
@@ -707,6 +707,7 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// same width and height.
|
||||
final int displayWidth = dc.mInitialDisplayWidth;
|
||||
final int displayHeight = dc.mInitialDisplayHeight;
|
||||
final float density = dc.mInitialDisplayDensity;
|
||||
final int cutoutWidth = 40;
|
||||
final int cutoutHeight = 10;
|
||||
final int left = (displayWidth - cutoutWidth) / 2;
|
||||
@@ -714,9 +715,13 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
final int right = (displayWidth + cutoutWidth) / 2;
|
||||
final int bottom = cutoutHeight;
|
||||
|
||||
final Rect r1 = new Rect(left, top, right, bottom);
|
||||
final Rect zeroRect = new Rect();
|
||||
final Rect[] bounds = new Rect[]{zeroRect, new Rect(left, top, right, bottom), zeroRect,
|
||||
zeroRect};
|
||||
final DisplayCutout.CutoutPathParserInfo info = new DisplayCutout.CutoutPathParserInfo(
|
||||
displayWidth, displayHeight, density, "", Surface.ROTATION_0, 1f);
|
||||
final DisplayCutout cutout = new WmDisplayCutout(
|
||||
fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
|
||||
DisplayCutout.constructDisplayCutout(bounds, Insets.NONE, info), null)
|
||||
.computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
|
||||
|
||||
dc.mInitialDisplayCutout = cutout;
|
||||
@@ -731,9 +736,12 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// | | ---o
|
||||
// | | |
|
||||
// | | -------------
|
||||
final Rect r = new Rect(top, left, bottom, right);
|
||||
final Rect[] bounds90 = new Rect[]{new Rect(top, left, bottom, right), zeroRect, zeroRect,
|
||||
zeroRect};
|
||||
final DisplayCutout.CutoutPathParserInfo info90 = new DisplayCutout.CutoutPathParserInfo(
|
||||
displayWidth, displayHeight, density, "", Surface.ROTATION_90, 1f);
|
||||
assertEquals(new WmDisplayCutout(
|
||||
fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
|
||||
DisplayCutout.constructDisplayCutout(bounds90, Insets.NONE, info90), null)
|
||||
.computeSafeInsets(displayHeight, displayWidth).getDisplayCutout(),
|
||||
dc.getDisplayInfo().displayCutout);
|
||||
}
|
||||
|
||||
@@ -150,9 +150,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_waterfall() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT},
|
||||
Insets.of(1, 2, 3, 4)),
|
||||
Insets.of(1, 2, 3, 4), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(1, 2, 3, 4), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -161,9 +161,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutTop_greaterThan_waterfallTop() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
|
||||
Insets.of(0, 20, 0, 0)),
|
||||
Insets.of(0, 20, 0, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 30, 0, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -172,9 +172,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutTop_lessThan_waterfallTop() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
|
||||
Insets.of(0, 40, 0, 0)),
|
||||
Insets.of(0, 40, 0, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 40, 0, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -183,9 +183,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutLeft_greaterThan_waterfallLeft() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
|
||||
Insets.of(20, 0, 0, 0)),
|
||||
Insets.of(20, 0, 0, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(30, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -194,9 +194,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutLeft_lessThan_waterfallLeft() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
|
||||
Insets.of(40, 0, 0, 0)),
|
||||
Insets.of(40, 0, 0, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(40, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -205,9 +205,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutBottom_greaterThan_waterfallBottom() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
|
||||
Insets.of(0, 0, 0, 20)),
|
||||
Insets.of(0, 0, 0, 20), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 0, 0, 30), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -216,9 +216,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutBottom_lessThan_waterfallBottom() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
|
||||
Insets.of(0, 0, 0, 40)),
|
||||
Insets.of(0, 0, 0, 40), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 0, 0, 40), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -227,9 +227,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutRight_greaterThan_waterfallRight() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
|
||||
Insets.of(0, 0, 20, 0)),
|
||||
Insets.of(0, 0, 20, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 0, 30, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
@@ -238,9 +238,9 @@ public class WmDisplayCutoutTest {
|
||||
@Test
|
||||
public void computeSafeInsets_cutoutRight_lessThan_waterfallRight() {
|
||||
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
|
||||
DisplayCutout.fromBoundsAndWaterfall(
|
||||
DisplayCutout.constructDisplayCutout(
|
||||
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
|
||||
Insets.of(0, 0, 40, 0)),
|
||||
Insets.of(0, 0, 40, 0), null),
|
||||
200, 400);
|
||||
|
||||
assertEquals(new Rect(0, 0, 40, 0), cutout.getDisplayCutout().getSafeInsets());
|
||||
|
||||
Reference in New Issue
Block a user