Merge "Make DisplayCutout support waterfall insets"
diff --git a/api/current.txt b/api/current.txt
index 7469299..175c89b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -50525,6 +50525,7 @@
public final class DisplayCutout {
ctor public DisplayCutout(@NonNull android.graphics.Insets, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect);
+ ctor public DisplayCutout(@NonNull android.graphics.Insets, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @NonNull android.graphics.Insets);
ctor @Deprecated public DisplayCutout(@Nullable android.graphics.Rect, @Nullable java.util.List<android.graphics.Rect>);
method @NonNull public android.graphics.Rect getBoundingRectBottom();
method @NonNull public android.graphics.Rect getBoundingRectLeft();
@@ -50535,6 +50536,7 @@
method public int getSafeInsetLeft();
method public int getSafeInsetRight();
method public int getSafeInsetTop();
+ method @NonNull public android.graphics.Insets getWaterfallInsets();
}
public final class DragAndDropPermissions implements android.os.Parcelable {
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 615dab0..d433591 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -86,7 +86,7 @@
* @hide
*/
public static final DisplayCutout NO_CUTOUT = new DisplayCutout(
- ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT,
+ ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT,
false /* copyArguments */);
@@ -103,8 +103,12 @@
private static float sCachedDensity;
@GuardedBy("CACHE_LOCK")
private static Pair<Path, DisplayCutout> sCachedCutout = NULL_PAIR;
+ @GuardedBy("CACHE_LOCK")
+ private static Insets sCachedWaterfallInsets;
private final Rect mSafeInsets;
+ @NonNull
+ private final Insets mWaterfallInsets;
/**
@@ -251,7 +255,32 @@
// 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(), boundLeft, boundTop, boundRight, boundBottom, true);
+ this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, true);
+ }
+
+ /**
+ * Creates a DisplayCutout instance.
+ *
+ * <p>Note that this is only useful for tests. For production code, developers should always
+ * use a {@link DisplayCutout} obtained from the system.</p>
+ *
+ * @param safeInsets the insets from each edge which avoid the display cutout as returned by
+ * {@link #getSafeInsetTop()} etc.
+ * @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 waterfallInsets the insets for the curved areas in waterfall display.
+ */
+ public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
+ @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom,
+ @NonNull Insets waterfallInsets) {
+ this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
+ true);
}
/**
@@ -269,7 +298,7 @@
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
- this(safeInsets, extractBoundsFromList(safeInsets, boundingRects),
+ this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects),
true /* copyArguments */);
}
@@ -281,19 +310,23 @@
* @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, Rect boundLeft, Rect boundTop, Rect boundRight,
- Rect boundBottom, boolean copyArguments) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft,
+ Rect boundTop, Rect boundRight, Rect boundBottom, boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
+ mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments);
}
- private DisplayCutout(Rect safeInsets, Rect[] bounds, boolean copyArguments) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect[] bounds,
+ boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
+ mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(bounds, copyArguments);
}
- private DisplayCutout(Rect safeInsets, Bounds bounds) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds) {
mSafeInsets = safeInsets;
+ mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = bounds;
}
@@ -309,6 +342,14 @@
}
/**
+ * Return the waterfall insets.
+ */
+ public @NonNull Insets getWaterfallInsets() {
+ return mWaterfallInsets;
+ }
+
+
+ /**
* Find the position of the bounding rect, and create an array of Rect whose index represents
* the position (= BoundsPosition).
*
@@ -476,7 +517,8 @@
@Override
public int hashCode() {
- return mSafeInsets.hashCode() * 48271 + mBounds.hashCode();
+ return (mSafeInsets.hashCode() * 48271 + mBounds.hashCode()) * 48271
+ + mWaterfallInsets.hashCode();
}
@Override
@@ -486,7 +528,8 @@
}
if (o instanceof DisplayCutout) {
DisplayCutout c = (DisplayCutout) o;
- return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds);
+ return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds)
+ && mWaterfallInsets.equals(c.mWaterfallInsets);
}
return false;
}
@@ -494,6 +537,7 @@
@Override
public String toString() {
return "DisplayCutout{insets=" + mSafeInsets
+ + " waterfall=" + mWaterfallInsets
+ " boundingRect={" + mBounds + "}"
+ "}";
}
@@ -508,6 +552,7 @@
mBounds.getRect(BOUNDS_POSITION_TOP).dumpDebug(proto, BOUND_TOP);
mBounds.getRect(BOUNDS_POSITION_RIGHT).dumpDebug(proto, BOUND_RIGHT);
mBounds.getRect(BOUNDS_POSITION_BOTTOM).dumpDebug(proto, BOUND_BOTTOM);
+ mWaterfallInsets.toRect().dumpDebug(proto, INSETS);
proto.end(token);
}
@@ -553,7 +598,7 @@
}
}
- return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
+ return new DisplayCutout(safeInsets, mWaterfallInsets, bounds, false /* copyArguments */);
}
/**
@@ -565,7 +610,7 @@
* @hide
*/
public DisplayCutout replaceSafeInsets(Rect safeInsets) {
- return new DisplayCutout(new Rect(safeInsets), mBounds);
+ return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds);
}
private static int atLeastZero(int value) {
@@ -585,7 +630,16 @@
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, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
+ }
+
+ /**
+ * Creates an instance from a bounding and waterfall insets.
+ *
+ * @hide
+ */
+ public static DisplayCutout fromBoundsAndWaterfall(Rect[] bounds, Insets waterfallInsets) {
+ return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, false /* copyArguments */);
}
/**
@@ -594,7 +648,7 @@
* @hide
*/
public static DisplayCutout fromBounds(Rect[] bounds) {
- return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
}
/**
@@ -606,7 +660,8 @@
*/
public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
- displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT);
+ displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
+ loadWaterfallInset(res));
}
/**
@@ -617,7 +672,8 @@
public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
return pathAndDisplayCutoutFromSpec(
res.getString(R.string.config_mainBuiltInDisplayCutout),
- displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first;
+ displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
+ loadWaterfallInset(res)).first;
}
/**
@@ -627,91 +683,109 @@
*/
@VisibleForTesting(visibility = PRIVATE)
public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
- float density) {
- return pathAndDisplayCutoutFromSpec(spec, displayWidth, displayHeight, density).second;
+ float density, Insets waterfallInsets) {
+ return pathAndDisplayCutoutFromSpec(
+ spec, displayWidth, displayHeight, density, waterfallInsets).second;
}
private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(String spec,
- int displayWidth, int displayHeight, float density) {
- if (TextUtils.isEmpty(spec)) {
+ int displayWidth, int displayHeight, float density, Insets waterfallInsets) {
+ if (TextUtils.isEmpty(spec) && waterfallInsets.equals(Insets.NONE)) {
return NULL_PAIR;
}
+
synchronized (CACHE_LOCK) {
if (spec.equals(sCachedSpec) && sCachedDisplayWidth == displayWidth
&& sCachedDisplayHeight == displayHeight
- && sCachedDensity == density) {
+ && sCachedDensity == density
+ && waterfallInsets.equals(sCachedWaterfallInsets)) {
return sCachedCutout;
}
}
- spec = spec.trim();
- final float offsetX;
- if (spec.endsWith(RIGHT_MARKER)) {
- offsetX = displayWidth;
- spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
- } else if (spec.endsWith(LEFT_MARKER)) {
- offsetX = 0;
- spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
- } else {
- offsetX = displayWidth / 2f;
- }
- final boolean inDp = spec.endsWith(DP_MARKER);
- if (inDp) {
- spec = spec.substring(0, spec.length() - DP_MARKER.length());
- }
- 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;
- final Region r = Region.obtain();
- try {
- p = PathParser.createPathFromPathData(spec);
- } catch (Throwable e) {
- Log.wtf(TAG, "Could not inflate cutout: ", e);
- return NULL_PAIR;
- }
-
- final Matrix m = new Matrix();
- if (inDp) {
- m.postScale(density, density);
- }
- m.postTranslate(offsetX, 0);
- p.transform(m);
-
- Rect boundTop = new Rect();
- toRectAndAddToRegion(p, r, boundTop);
- final int topInset = boundTop.bottom;
-
+ Path p = null;
+ Rect boundTop = null;
Rect boundBottom = null;
- final int bottomInset;
- 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_PAIR;
+ Rect safeInset = new Rect();
+ String bottomSpec = null;
+ if (!TextUtils.isEmpty(spec)) {
+ spec = spec.trim();
+ final float offsetX;
+ if (spec.endsWith(RIGHT_MARKER)) {
+ offsetX = displayWidth;
+ spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
+ } else if (spec.endsWith(LEFT_MARKER)) {
+ offsetX = 0;
+ spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
+ } else {
+ offsetX = displayWidth / 2f;
}
- // Keep top transform
- m.postTranslate(0, displayHeight);
- bottomPath.transform(m);
- p.addPath(bottomPath);
- boundBottom = new Rect();
- toRectAndAddToRegion(bottomPath, r, boundBottom);
- bottomInset = displayHeight - boundBottom.top;
- } else {
- bottomInset = 0;
+ final boolean inDp = spec.endsWith(DP_MARKER);
+ if (inDp) {
+ spec = spec.substring(0, spec.length() - DP_MARKER.length());
+ }
+
+ if (spec.contains(BOTTOM_MARKER)) {
+ String[] splits = spec.split(BOTTOM_MARKER, 2);
+ spec = splits[0].trim();
+ bottomSpec = splits[1].trim();
+ }
+
+ final Matrix m = new Matrix();
+ final Region r = Region.obtain();
+ if (!spec.isEmpty()) {
+ try {
+ p = PathParser.createPathFromPathData(spec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate cutout: ", e);
+ }
+
+ if (p != null) {
+ if (inDp) {
+ m.postScale(density, density);
+ }
+ m.postTranslate(offsetX, 0);
+ p.transform(m);
+
+ boundTop = new Rect();
+ toRectAndAddToRegion(p, r, boundTop);
+ safeInset.top = boundTop.bottom;
+ }
+ }
+
+ if (bottomSpec != null) {
+ int bottomInset = 0;
+ Path bottomPath = null;
+ try {
+ bottomPath = PathParser.createPathFromPathData(bottomSpec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
+ }
+
+ if (bottomPath != null) {
+ // Keep top transform
+ m.postTranslate(0, displayHeight);
+ bottomPath.transform(m);
+ p.addPath(bottomPath);
+ boundBottom = new Rect();
+ toRectAndAddToRegion(bottomPath, r, boundBottom);
+ bottomInset = displayHeight - boundBottom.top;
+ }
+ safeInset.bottom = bottomInset;
+ }
}
- Rect safeInset = new Rect(0, topInset, 0, bottomInset);
- final DisplayCutout cutout = new DisplayCutout(
- safeInset, null /* boundLeft */, boundTop, null /* boundRight */, boundBottom,
- false /* copyArguments */);
+ if (!waterfallInsets.equals(Insets.NONE)) {
+ safeInset.set(
+ Math.max(waterfallInsets.left, safeInset.left),
+ Math.max(waterfallInsets.top, safeInset.top),
+ Math.max(waterfallInsets.right, safeInset.right),
+ Math.max(waterfallInsets.bottom, safeInset.bottom));
+ }
+ final DisplayCutout cutout = new DisplayCutout(
+ safeInset, waterfallInsets, null /* boundLeft */, boundTop,
+ null /* boundRight */, boundBottom, false /* copyArguments */);
final Pair<Path, DisplayCutout> result = new Pair<>(p, cutout);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
@@ -719,6 +793,7 @@
sCachedDisplayHeight = displayHeight;
sCachedDensity = density;
sCachedCutout = result;
+ sCachedWaterfallInsets = waterfallInsets;
}
return result;
}
@@ -730,6 +805,15 @@
inoutRegion.op(inoutRect, Op.UNION);
}
+
+ private static Insets loadWaterfallInset(Resources res) {
+ return Insets.of(
+ res.getDimensionPixelSize(R.dimen.waterfall_display_left_edge_size),
+ res.getDimensionPixelSize(R.dimen.waterfall_display_top_edge_size),
+ res.getDimensionPixelSize(R.dimen.waterfall_display_right_edge_size),
+ res.getDimensionPixelSize(R.dimen.waterfall_display_bottom_edge_size));
+ }
+
/**
* Helper class for passing {@link DisplayCutout} through binder.
*
@@ -773,6 +857,7 @@
out.writeInt(1);
out.writeTypedObject(cutout.mSafeInsets, flags);
out.writeTypedArray(cutout.mBounds.getRects(), flags);
+ out.writeTypedObject(cutout.mWaterfallInsets, flags);
}
}
@@ -815,8 +900,10 @@
Rect safeInsets = in.readTypedObject(Rect.CREATOR);
Rect[] bounds = new Rect[BOUNDS_POSITION_LENGTH];
in.readTypedArray(bounds, Rect.CREATOR);
+ Insets waterfallInsets = in.readTypedObject(Insets.CREATOR);
- return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
+ return new DisplayCutout(
+ safeInsets, waterfallInsets, bounds, false /* copyArguments */);
}
public DisplayCutout get() {
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index d5a0dfa..7c2b98f 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -69,6 +69,8 @@
null /* boundBottom */);
final DisplayCutout mCutoutTop = createCutoutTop();
+ final DisplayCutout mCutoutWithWaterfall = createCutoutWithWaterfall();
+ final DisplayCutout mWaterfallOnly = createCutoutWaterfallOnly();
@Test
public void testExtractBoundsFromList_left() {
@@ -126,9 +128,23 @@
}
@Test
- public void hasCutout() throws Exception {
- assertTrue(NO_CUTOUT.isEmpty());
- assertFalse(mCutoutTop.isEmpty());
+ public void testHasCutout_noCutout() throws Exception {
+ assertTrue(NO_CUTOUT.isBoundsEmpty());
+ }
+
+ @Test
+ public void testHasCutout_cutoutOnly() {
+ assertFalse(mCutoutTop.isBoundsEmpty());
+ }
+
+ @Test
+ public void testHasCutout_cutoutWithWaterfall() {
+ assertFalse(mCutoutWithWaterfall.isBoundsEmpty());
+ }
+
+ @Test
+ public void testHasCutout_waterfallOnly() {
+ assertTrue(mWaterfallOnly.isBoundsEmpty());
}
@Test
@@ -142,20 +158,27 @@
}
@Test
+ public void testGetWaterfallInsets() throws Exception {
+ DisplayCutout cutout =
+ createCutoutWaterfallOnly(Insets.of(5, 6, 7, 8));
+ assertEquals(Insets.of(5, 6, 7, 8), cutout.getWaterfallInsets());
+ }
+
+ @Test
public void testHashCode() throws Exception {
- assertEquals(mCutoutTop.hashCode(), createCutoutTop().hashCode());
- assertNotEquals(mCutoutTop.hashCode(), mCutoutNumbers.hashCode());
+ assertEquals(mCutoutWithWaterfall.hashCode(), createCutoutWithWaterfall().hashCode());
+ assertNotEquals(mCutoutWithWaterfall.hashCode(), mCutoutNumbers.hashCode());
}
@Test
public void testEquals() throws Exception {
- assertEquals(mCutoutTop, createCutoutTop());
- assertNotEquals(mCutoutTop, mCutoutNumbers);
+ assertEquals(mCutoutWithWaterfall, createCutoutWithWaterfall());
+ assertNotEquals(mCutoutWithWaterfall, mCutoutNumbers);
}
@Test
public void testToString() throws Exception {
- assertFalse(mCutoutTop.toString().isEmpty());
+ assertFalse(mCutoutWithWaterfall.toString().isEmpty());
assertFalse(mCutoutNumbers.toString().isEmpty());
}
@@ -240,12 +263,12 @@
public void parcel_unparcel_regular() {
Parcel p = Parcel.obtain();
- new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+ new ParcelableWrapper(mCutoutWithWaterfall).writeToParcel(p, 0);
int posAfterWrite = p.dataPosition();
p.setDataPosition(0);
- assertEquals(mCutoutTop, ParcelableWrapper.CREATOR.createFromParcel(p).get());
+ assertEquals(mCutoutWithWaterfall, ParcelableWrapper.CREATOR.createFromParcel(p).get());
assertEquals(posAfterWrite, p.dataPosition());
}
@@ -264,44 +287,64 @@
@Test
public void fromSpec_caches() {
- DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f);
- assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), sameInstance(cached));
+ Insets waterfallInsets = Insets.of(0, 20, 0, 20);
+ DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets),
+ sameInstance(cached));
}
@Test
public void fromSpec_wontCacheIfSpecChanges() {
- DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 400, 1f);
- assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
+ DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 400, 1f, Insets.NONE);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE),
+ not(sameInstance(cached)));
}
@Test
public void fromSpec_wontCacheIfScreenWidthChanges() {
- DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 400, 1f);
- assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
+ DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 400, 1f, Insets.NONE);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE),
+ not(sameInstance(cached)));
}
@Test
public void fromSpec_wontCacheIfScreenHeightChanges() {
- DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 4000, 1f);
- assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
+ DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 4000, 1f, Insets.NONE);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE),
+ not(sameInstance(cached)));
}
@Test
public void fromSpec_wontCacheIfDensityChanges() {
- DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f);
- assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
+ DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE),
+ not(sameInstance(cached)));
+ }
+
+ @Test
+ public void fromSpec_wontCacheIfWaterfallInsetsChange() {
+ Insets waterfallInsets = Insets.of(0, 20, 0, 20);
+ DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE);
+ assertThat(
+ fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, waterfallInsets),
+ not(sameInstance(cached)));
}
@Test
public void fromSpec_setsSafeInsets_top() {
- DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f);
+ DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f, Insets.NONE);
assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 0)));
}
@Test
public void fromSpec_setsSafeInsets_top_and_bottom() {
DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z"
- + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f);
+ + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f, Insets.NONE);
assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 10)));
assertThat(cutout.getBoundingRectsAll(), equalTo(new Rect[]{
ZERO_RECT, new Rect(50, 0, 150, 20),
@@ -310,6 +353,38 @@
}
@Test
+ public void fromSpec_setsSafeInsets_waterfallTopBottom() {
+ DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(0, 30, 0, 30));
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 30, 0, 30)));
+ }
+
+ @Test
+ public void fromSpec_setsSafeInsets_waterfallLeftRight() {
+ DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 0, 30, 0));
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 0, 30, 0)));
+ }
+
+ @Test
+ public void fromSpec_setsSafeInsets_waterfall_allEdges() {
+ DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 30, 30, 30));
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 30, 30, 30)));
+ }
+
+ @Test
+ public void fromSpec_setsSafeInsets_cutoutTopBottom_waterfallTopBottom() {
+ DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z"
+ + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, Insets.of(0, 30, 0, 30));
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 30, 0, 30)));
+ }
+
+ @Test
+ public void fromSpec_setsSafeInsets_cutoutTopBottom_waterfallLeftRight() {
+ DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z"
+ + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, Insets.of(30, 0, 30, 0));
+ assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 20, 30, 20)));
+ }
+
+ @Test
public void parcel_unparcel_nocutout() {
Parcel p = Parcel.obtain();
@@ -326,7 +401,7 @@
public void parcel_unparcel_inplace() {
Parcel p = Parcel.obtain();
- new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+ new ParcelableWrapper(mCutoutWithWaterfall).writeToParcel(p, 0);
int posAfterWrite = p.dataPosition();
p.setDataPosition(0);
@@ -334,22 +409,24 @@
ParcelableWrapper wrapper = new ParcelableWrapper();
wrapper.readFromParcel(p);
- assertEquals(mCutoutTop, wrapper.get());
+ assertEquals(mCutoutWithWaterfall, wrapper.get());
assertEquals(posAfterWrite, p.dataPosition());
}
@Test
public void wrapper_hashcode() throws Exception {
- assertEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
- new ParcelableWrapper(createCutoutTop()).hashCode());
- assertNotEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
+ assertEquals(new ParcelableWrapper(mCutoutWithWaterfall).hashCode(),
+ new ParcelableWrapper(createCutoutWithWaterfall()).hashCode());
+ assertNotEquals(new ParcelableWrapper(mCutoutWithWaterfall).hashCode(),
new ParcelableWrapper(mCutoutNumbers).hashCode());
}
@Test
public void wrapper_equals() throws Exception {
- assertEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(createCutoutTop()));
- assertNotEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(mCutoutNumbers));
+ assertEquals(new ParcelableWrapper(mCutoutWithWaterfall),
+ new ParcelableWrapper(createCutoutWithWaterfall()));
+ assertNotEquals(new ParcelableWrapper(mCutoutWithWaterfall),
+ new ParcelableWrapper(mCutoutNumbers));
}
private static DisplayCutout createCutoutTop() {
@@ -363,4 +440,28 @@
safeInset, null /* boundLeft */, boundTop, null /* boundRight */,
null /* boundBottom */);
}
+
+ private static DisplayCutout createCutoutWithWaterfall() {
+ return new DisplayCutout(
+ Insets.of(20, 100, 20, 0),
+ ZERO_RECT,
+ new Rect(50, 0, 75, 100),
+ ZERO_RECT,
+ ZERO_RECT,
+ Insets.of(20, 0, 20, 0));
+ }
+
+ private static DisplayCutout createCutoutWaterfallOnly() {
+ return createCutoutWaterfallOnly(Insets.of(20, 0, 20, 0));
+ }
+
+ private static DisplayCutout createCutoutWaterfallOnly(Insets waterfallInsets) {
+ return new DisplayCutout(
+ Insets.of(20, 0, 20, 0),
+ ZERO_RECT,
+ ZERO_RECT,
+ ZERO_RECT,
+ ZERO_RECT,
+ waterfallInsets);
+ }
}