diff options
5 files changed, 538 insertions, 144 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 37cc42ee4b73..6d0f27615720 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -711,4 +711,8 @@ <item>@drawable/rounded_corner_bottom</item> <item>@drawable/rounded_corner_bottom_secondary</item> </array> + + <!-- Flag to enable privacy dot views, it shall be true for normal case --> + <bool name="config_enablePrivacyDot">true</bool> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 19d029bfd161..23a3f8d58f71 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -160,6 +160,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private Handler mHandler; private boolean mPendingRotationChange; private boolean mIsRoundedCornerMultipleRadius; + private boolean mIsPrivacyDotEnabled; private int mStatusBarHeightPortrait; private int mStatusBarHeightLandscape; private Drawable mRoundedCornerDrawable; @@ -253,6 +254,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mRotation = mContext.getDisplay().getRotation(); mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId); + mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); mWindowManager = mContext.getSystemService(WindowManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); updateRoundedCornerDrawable(); @@ -312,24 +314,24 @@ public class ScreenDecorations extends SystemUI implements Tunable { } private void setupDecorations() { - if (hasRoundedCorners() || shouldDrawCutout()) { + if (hasRoundedCorners() || shouldDrawCutout() || mIsPrivacyDotEnabled) { updateStatusBarHeight(); final DisplayCutout cutout = getCutout(); - final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); - int rotatedPos; for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { - rotatedPos = getBoundPositionFromRotation(i, mRotation); - if ((bounds != null && !bounds[rotatedPos].isEmpty()) - || shouldShowRoundedCorner(i)) { - createOverlay(i); + if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout) + || shouldShowPrivacyDot(i, cutout)) { + createOverlay(i, cutout); } else { removeOverlay(i); } } - // Overlays have been created, send the dots to the controller - //TODO: need a better way to do this - mDotViewController.initialize( - mTopLeftDot, mTopRightDot, mBottomLeftDot, mBottomRightDot); + + if (mIsPrivacyDotEnabled) { + // Overlays have been created, send the dots to the controller + //TODO: need a better way to do this + mDotViewController.initialize( + mTopLeftDot, mTopRightDot, mBottomLeftDot, mBottomRightDot); + } } else { removeAllOverlays(); } @@ -416,7 +418,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlays[pos] = null; } - private void createOverlay(@BoundsPosition int pos) { + private void createOverlay(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { if (mOverlays == null) { mOverlays = new View[BOUNDS_POSITION_LENGTH]; } @@ -437,7 +439,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlays[pos].setAlpha(0); mOverlays[pos].setForceDarkAllowed(false); - updateView(pos); + updateView(pos, cutout); mWindowManager.addView(mOverlays[pos], getWindowLayoutParams(pos)); @@ -461,34 +463,19 @@ public class ScreenDecorations extends SystemUI implements Tunable { * Allow overrides for top/bottom positions */ private View overlayForPosition(@BoundsPosition int pos) { - switch (pos) { - case BOUNDS_POSITION_TOP: - case BOUNDS_POSITION_LEFT: - View top = LayoutInflater.from(mContext) - .inflate(R.layout.rounded_corners_top, null); - mTopLeftDot = top.findViewById(R.id.privacy_dot_left_container); - mTopRightDot = top.findViewById(R.id.privacy_dot_right_container); - return top; - case BOUNDS_POSITION_BOTTOM: - case BOUNDS_POSITION_RIGHT: - View bottom = LayoutInflater.from(mContext) - .inflate(R.layout.rounded_corners_bottom, null); - mBottomLeftDot = bottom.findViewById(R.id.privacy_dot_left_container); - mBottomRightDot = bottom.findViewById(R.id.privacy_dot_right_container); - return bottom; - default: - throw new IllegalArgumentException("Unknown bounds position"); - } + final int layoutId = (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) + ? R.layout.rounded_corners_top : R.layout.rounded_corners_bottom; + return LayoutInflater.from(mContext).inflate(layoutId, null); } - private void updateView(@BoundsPosition int pos) { + private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { if (mOverlays == null || mOverlays[pos] == null) { return; } // update rounded corner view rotation - updateRoundedCornerView(pos, R.id.left); - updateRoundedCornerView(pos, R.id.right); + updateRoundedCornerView(pos, R.id.left, cutout); + updateRoundedCornerView(pos, R.id.right, cutout); updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom); updateRoundedCornerImageView(); @@ -496,6 +483,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mCutoutViews != null && mCutoutViews[pos] != null) { mCutoutViews[pos].setRotation(mRotation); } + + updatePrivacyDotView(pos, cutout); } @VisibleForTesting @@ -671,11 +660,12 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mOverlays != null) { updateLayoutParams(); + final DisplayCutout cutout = getCutout(); for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { if (mOverlays[i] == null) { continue; } - updateView(i); + updateView(i, cutout); } } } @@ -807,13 +797,14 @@ public class ScreenDecorations extends SystemUI implements Tunable { return drawable; } - private void updateRoundedCornerView(@BoundsPosition int pos, int id) { + private void updateRoundedCornerView(@BoundsPosition int pos, int id, + @Nullable DisplayCutout cutout) { final View rounded = mOverlays[pos].findViewById(id); if (rounded == null) { return; } rounded.setVisibility(View.GONE); - if (shouldShowRoundedCorner(pos)) { + if (shouldShowRoundedCorner(pos, cutout)) { final int gravity = getRoundedCornerGravity(pos, id == R.id.left); ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity; setRoundedCornerOrientation(rounded, gravity); @@ -821,6 +812,26 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + private void updatePrivacyDotView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + final ViewGroup viewGroup = (ViewGroup) mOverlays[pos]; + + final View left = viewGroup.findViewById(R.id.privacy_dot_left_container); + final View right = viewGroup.findViewById(R.id.privacy_dot_right_container); + if (shouldShowPrivacyDot(pos, cutout)) { + // TODO (b/201481944) Privacy Dots pos and var are wrong with long side cutout enable + if (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) { + mTopLeftDot = left; + mTopRightDot = right; + } else { + mBottomLeftDot = left; + mBottomRightDot = right; + } + } else { + viewGroup.removeView(left); + viewGroup.removeView(right); + } + } + private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) { final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); switch (rotatedPos) { @@ -872,12 +883,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { || mIsRoundedCornerMultipleRadius; } - private boolean shouldShowRoundedCorner(@BoundsPosition int pos) { - if (!hasRoundedCorners()) { - return false; - } - - DisplayCutout cutout = getCutout(); + private boolean isDefaultShownOverlayPos(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { // for cutout is null or cutout with only waterfall. final boolean emptyBoundsOrWaterfall = cutout == null || cutout.isBoundsEmpty(); // Shows rounded corner on left and right overlays only when there is no top or bottom @@ -892,6 +899,21 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + private boolean shouldShowRoundedCorner(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + return mIsPrivacyDotEnabled && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); + final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); + return (bounds != null && !bounds[rotatedPos].isEmpty()); + } + private boolean shouldDrawCutout() { return shouldDrawCutout(mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 5f44a7d5d870..fe154d232a88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -72,6 +72,7 @@ public class KeyguardStatusBarView extends RelativeLayout { private boolean mKeyguardUserSwitcherEnabled; private final UserManager mUserManager; + private boolean mIsPrivacyDotEnabled; private int mSystemIconsSwitcherHiddenExpandedMargin; private int mStatusBarPaddingEnd; private int mMinDotWidth; @@ -112,7 +113,7 @@ public class KeyguardStatusBarView extends RelativeLayout { mCutoutSpace = findViewById(R.id.cutout_space_view); mStatusIconArea = findViewById(R.id.status_icon_area); mStatusIconContainer = findViewById(R.id.statusIcons); - + mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); loadDimens(); } @@ -270,9 +271,10 @@ public class KeyguardStatusBarView extends RelativeLayout { mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding); // consider privacy dot space - final int minLeft = isLayoutRtl() ? Math.max(mMinDotWidth, mPadding.first) : mPadding.first; - final int minRight = isLayoutRtl() ? mPadding.second : - Math.max(mMinDotWidth, mPadding.second); + final int minLeft = (isLayoutRtl() && mIsPrivacyDotEnabled) + ? Math.max(mMinDotWidth, mPadding.first) : mPadding.first; + final int minRight = (!isLayoutRtl() && mIsPrivacyDotEnabled) + ? Math.max(mMinDotWidth, mPadding.second) : mPadding.second; setPadding(minLeft, waterfallTop, minRight, 0); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt index 515094bd6ec0..61552f065bc4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -70,6 +70,9 @@ class StatusBarContentInsetsProvider @Inject constructor( // (e.g. network displays) private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE) private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>() + private val isPrivacyDotEnabled: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) { + context.resources.getBoolean(R.bool.config_enablePrivacyDot) + } init { configurationController.addCallback(this) @@ -152,8 +155,9 @@ class StatusBarContentInsetsProvider @Inject constructor( val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL val roundedCornerPadding = rotatedResources .getDimensionPixelSize(R.dimen.rounded_corner_content_padding) - val minDotWidth = rotatedResources - .getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding) + val minDotWidth = if (isPrivacyDotEnabled) + rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding) + else 0 val minLeft: Int val minRight: Int diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 4c7f959e7b8e..c6df1c15e0b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -28,11 +28,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -151,27 +153,155 @@ public class ScreenDecorationsTest extends SysuiTestCase { reset(mTunerService); } + + private void verifyRoundedCornerViewsVisibility( + @DisplayCutout.BoundsPosition final int overlayId, + @View.Visibility final int visibility) { + final View overlay = mScreenDecorations.mOverlays[overlayId]; + final View left = overlay.findViewById(R.id.left); + final View right = overlay.findViewById(R.id.right); + assertNotNull(left); + assertNotNull(right); + assertThat(left.getVisibility()).isEqualTo(visibility); + assertThat(right.getVisibility()).isEqualTo(visibility); + } + + private void verifyTopDotViewsNullable(final boolean isAssertNull) { + if (isAssertNull) { + assertNull(mScreenDecorations.mTopLeftDot); + assertNull(mScreenDecorations.mTopRightDot); + } else { + assertNotNull(mScreenDecorations.mTopLeftDot); + assertNotNull(mScreenDecorations.mTopRightDot); + } + } + + private void verifyBottomDotViewsNullable(final boolean isAssertNull) { + if (isAssertNull) { + assertNull(mScreenDecorations.mBottomLeftDot); + assertNull(mScreenDecorations.mBottomRightDot); + } else { + assertNotNull(mScreenDecorations.mBottomLeftDot); + assertNotNull(mScreenDecorations.mBottomRightDot); + } + } + + private void verifyDotViewsNullable(final boolean isAssertNull) { + verifyTopDotViewsNullable(isAssertNull); + verifyBottomDotViewsNullable(isAssertNull); + } + + private void verifyTopDotViewsVisibility(@View.Visibility final int visibility) { + verifyTopDotViewsNullable(false); + assertThat(mScreenDecorations.mTopLeftDot.getVisibility()).isEqualTo(visibility); + assertThat(mScreenDecorations.mTopRightDot.getVisibility()).isEqualTo(visibility); + } + + private void verifyBottomDotViewsVisibility(@View.Visibility final int visibility) { + verifyBottomDotViewsNullable(false); + assertThat(mScreenDecorations.mBottomLeftDot.getVisibility()).isEqualTo(visibility); + assertThat(mScreenDecorations.mBottomRightDot.getVisibility()).isEqualTo(visibility); + } + + private void verifyDotViewsVisibility(@View.Visibility final int visibility) { + verifyTopDotViewsVisibility(visibility); + verifyBottomDotViewsVisibility(visibility); + } + + private void verifyOverlaysExistAndAdded(final boolean left, final boolean top, + final boolean right, final boolean bottom) { + if (left || top || right || bottom) { + assertNotNull(mScreenDecorations.mOverlays); + } else { + verify(mWindowManager, never()).addView(any(), any()); + return; + } + + if (left) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + } + + if (top) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + } + + if (right) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + } + + if (bottom) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + } + } + @Test - public void testNoRounding_NoCutout() { + public void testNoRounding_NoCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // No views added. - verify(mWindowManager, never()).addView(any(), any()); + verifyOverlaysExistAndAdded(false, false, false, false); // No Tuners tuned. verify(mTunerService, never()).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testNoRounding_NoCutout_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + + // Top and bottom windows are created for privacy dot. + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall not exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test - public void testRounding_NoCutout() { + public void testRounding_NoCutout_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -179,17 +309,49 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top and bottom windows are created for rounded corners. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall not exist + verifyDotViewsNullable(true); + + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testRounding_NoCutout_PrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top and bottom windows are created for rounded corners. // Left and right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); // One tunable. verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test @@ -197,7 +359,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final Point testRadiusPoint = new Point(1, 1); setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -213,7 +375,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final int testTopRadius = 1; final int testBottomRadius = 5; setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */, - false /* multipleRadius */, false /* fillCutout */); + false /* multipleRadius */, false /* fillCutout */, true /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -242,7 +404,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final int testTopRadius = 1; final int testBottomRadius = 5; setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */, - false /* multipleRadius */, false /* fillCutout */); + false /* multipleRadius */, false /* fillCutout */, true /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -278,29 +440,67 @@ public class ScreenDecorationsTest extends SysuiTestCase { } @Test - public void testRoundingMultipleRadius_NoCutout() { + public void testRoundingMultipleRadius_NoCutout_NoPrivacyDot() { final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight()); setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 9999 /* roundedPadding */, true /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // Top and bottom windows are created for rounded corners. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall not exist + verifyDotViewsNullable(true); + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + + // Size of corner view should exactly match max(width, height) of R.drawable.rounded + assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize); + } + + @Test + public void testRoundingMultipleRadius_NoCutout_PrivacyDot() { + final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); + final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 9999 /* roundedPadding */, true /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top and bottom windows are created for rounded corners. // Left and right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); // One tunable. verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); // Size of corner view should exactly match max(width, height) of R.drawable.rounded assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize); @@ -309,10 +509,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { } @Test - public void testNoRounding_CutoutShortEdge() { + public void testNoRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -321,21 +521,53 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - // Left window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Bottom, left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, false); + + // Privacy dots shall not exist because of no privacy + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testNoRounding_CutoutShortEdge_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for top cutout. + // Bottom window is created for privacy dot. + // Left or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Top rounded corner views shall exist because of cutout + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + // Bottom rounded corner views shall exist because of privacy dot + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test - public void testNoRounding_CutoutLongEdge() { + public void testNoRounding_CutoutLongEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -344,21 +576,50 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Left window is created for left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - // Top window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Bottom, top, or right window should be null. + verifyOverlaysExistAndAdded(true, false, false, false); + + // Left rounded corner views shall exist because of cutout + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_LEFT, View.GONE); + + // Top privacy dots shall not exist because of no privacy + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); } @Test - public void testRounding_CutoutShortEdge() { + public void testNoRounding_CutoutLongEdge_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Left window is created for left cutout. + // Right window is created for privacy. + // Bottom, or top window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); + } + + @Test + public void testRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -367,22 +628,55 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for rounded corner and top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); // Bottom window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); - // Left window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Top privacy dots shall not exist because of no privacy dot + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); } @Test - public void testRounding_CutoutLongEdge() { + public void testRounding_CutoutShortEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for rounded corner and top cutout. + // Bottom window is created for rounded corner. + // Left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Top privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); + } + + @Test + public void testRounding_CutoutLongEdge_NoPrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, false /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -391,22 +685,53 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Left window is created for rounded corner and left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); // Right window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]), any()); - // Top window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + // Top, or bottom window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testRounding_CutoutLongEdge_PrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Left window is created for rounded corner, left cutout, and privacy. + // Right window is created for rounded corner and privacy dot. + // Top, or bottom window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, false /* privacyDot */); + + // top and left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for rounded corner and top cutout. + // Bottom window is created for rounded corner. + // Left window is created for left cutout. + // Right window should be null. + verifyOverlaysExistAndAdded(true, true, false, true); } @Test - public void testRounding_CutoutShortAndLongEdge() { + public void testRounding_CutoutShortAndLongEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); // top and left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; @@ -415,23 +740,17 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for rounded corner and top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); // Bottom window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); // Left window is created for left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(true, true, false, true); } @Test - public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout() { + public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // Set to short edge cutout(top). final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -439,11 +758,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { .when(mScreenDecorations).getCutout(); mScreenDecorations.start(); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + verifyOverlaysExistAndAdded(false, true, false, false); // Switch to long edge cutout(left). final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -451,18 +766,37 @@ public class ScreenDecorationsTest extends SysuiTestCase { .when(mScreenDecorations).getCutout(); mScreenDecorations.onConfigurationChanged(new Configuration()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + verifyOverlaysExistAndAdded(true, false, false, false); } @Test - public void testDelayedCutout() { + public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); + + // Set to short edge cutout(top). + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Switch to long edge cutout(left). + final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.onConfigurationChanged(new Configuration()); + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testDelayedCutout_NoPrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -478,11 +812,38 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.onConfigurationChanged(new Configuration()); // Only top windows should be added. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, false); + } + + @Test + public void testDelayedCutout_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Both top and bottom windows should be added because of privacy dot, + // but their visibility shall be gone because of no rounding. + verifyOverlaysExistAndAdded(false, true, false, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) + .thenReturn(true); + mScreenDecorations.onConfigurationChanged(new Configuration()); + + assertNotNull(mScreenDecorations.mOverlays); + // Both top and bottom windows should be added because of privacy dot, + // but their visibility shall be gone because of no rounding. + verifyOverlaysExistAndAdded(false, true, false, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); } @Test @@ -496,7 +857,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testUpdateRoundedCorners() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20)); @@ -511,7 +872,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusTop() { setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); @@ -523,7 +884,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusBottom() { setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); @@ -531,7 +892,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertEquals(new Point(20, 20), mScreenDecorations.mRoundedDefaultBottom); } - @Test public void testBoundingRectsToRegion() throws Exception { Rect rect = new Rect(1, 2, 3, 4); @@ -588,7 +948,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { } private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding, - boolean multipleRadius, boolean fillCutout) { + boolean multipleRadius, boolean fillCutout, boolean privacyDot) { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.array.config_displayUniqueIdArray, new String[]{}); @@ -625,6 +985,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { R.bool.config_roundedCornerMultipleRadius, multipleRadius); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout); + mContext.getOrCreateTestableResources().addOverride( + R.bool.config_enablePrivacyDot, privacyDot); } private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) { |