diff options
| author | 2020-01-13 22:24:43 +0800 | |
|---|---|---|
| committer | 2020-01-19 14:49:12 +0800 | |
| commit | 7dabcab3dde09ffa08f194c358fbd34afe35b8ff (patch) | |
| tree | 3b7db76326d7a625c39774d1fbbc59643a07ce4f | |
| parent | 0a5e31ee3f3006112a0c9f255a2e1a730eaa1503 (diff) | |
Make DisplayCutout support waterfall insets
For waterfall display, also take the waterfall insets into accout to
comput safe insets.
Change-Id: I1d5663ebd8588021387b7ae5296851769954f996
Bug: 146876976
Test: atest DisplayCutoutTest
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/view/DisplayCutout.java | 249 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/DisplayCutoutTest.java | 159 |
3 files changed, 300 insertions, 110 deletions
diff --git a/api/current.txt b/api/current.txt index 1210d627c99e..0450276d9e4a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -50509,6 +50509,7 @@ package android.view { 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(); @@ -50519,6 +50520,7 @@ package android.view { 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 615dab0f04e4..d433591f2b3c 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -86,7 +86,7 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { 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 @@ 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(), 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 @@ public final class DisplayCutout { // 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 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { } /** + * 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 @@ public final class DisplayCutout { @Override public int hashCode() { - return mSafeInsets.hashCode() * 48271 + mBounds.hashCode(); + return (mSafeInsets.hashCode() * 48271 + mBounds.hashCode()) * 48271 + + mWaterfallInsets.hashCode(); } @Override @@ -486,7 +528,8 @@ public final class DisplayCutout { } 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 @@ public final class DisplayCutout { @Override public String toString() { return "DisplayCutout{insets=" + mSafeInsets + + " waterfall=" + mWaterfallInsets + " boundingRect={" + mBounds + "}" + "}"; } @@ -508,6 +552,7 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { } } - return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); + return new DisplayCutout(safeInsets, mWaterfallInsets, bounds, false /* copyArguments */); } /** @@ -565,7 +610,7 @@ public final class DisplayCutout { * @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 @@ 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, 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 @@ public final class DisplayCutout { * @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 final class DisplayCutout { */ 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 final class DisplayCutout { 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 @@ public final class DisplayCutout { */ @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()); - } + Path p = null; + Rect boundTop = null; + Rect boundBottom = null; + Rect safeInset = new Rect(); 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; - } + 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; + } + final boolean inDp = spec.endsWith(DP_MARKER); + if (inDp) { + spec = spec.substring(0, spec.length() - DP_MARKER.length()); + } - final Matrix m = new Matrix(); - if (inDp) { - m.postScale(density, density); - } - m.postTranslate(offsetX, 0); - p.transform(m); + if (spec.contains(BOTTOM_MARKER)) { + String[] splits = spec.split(BOTTOM_MARKER, 2); + spec = splits[0].trim(); + bottomSpec = splits[1].trim(); + } - Rect boundTop = new Rect(); - toRectAndAddToRegion(p, r, boundTop); - final int topInset = boundTop.bottom; + 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); + } - 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; + 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; } - // 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; } - 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 @@ public final class DisplayCutout { sCachedDisplayHeight = displayHeight; sCachedDensity = density; sCachedCutout = result; + sCachedWaterfallInsets = waterfallInsets; } return result; } @@ -730,6 +805,15 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { out.writeInt(1); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedArray(cutout.mBounds.getRects(), flags); + out.writeTypedObject(cutout.mWaterfallInsets, flags); } } @@ -815,8 +900,10 @@ public final class DisplayCutout { 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 d5a0dfadcbe5..7c2b98f3e167 100644 --- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java +++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java @@ -69,6 +69,8 @@ public class DisplayCutoutTest { null /* boundBottom */); final DisplayCutout mCutoutTop = createCutoutTop(); + final DisplayCutout mCutoutWithWaterfall = createCutoutWithWaterfall(); + final DisplayCutout mWaterfallOnly = createCutoutWaterfallOnly(); @Test public void testExtractBoundsFromList_left() { @@ -126,9 +128,23 @@ public class DisplayCutoutTest { } @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 @@ public class DisplayCutoutTest { } @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 class DisplayCutoutTest { 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 @@ public class DisplayCutoutTest { @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 @@ public class DisplayCutoutTest { } @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 class DisplayCutoutTest { 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 @@ public class DisplayCutoutTest { 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 @@ public class DisplayCutoutTest { 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); + } } |