diff options
8 files changed, 326 insertions, 561 deletions
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index f013f9b49955..dca5ea836fa4 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -132,9 +132,6 @@ <item type="id" name="status_bar_view_state_tag" /> <item type="id" name="display_cutout" /> - <item type="id" name="display_cutout_left" /> - <item type="id" name="display_cutout_right" /> - <item type="id" name="display_cutout_bottom" /> <item type="id" name="row_tag_for_content_view" /> diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 9fab2ea34193..aaaa3f77924a 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -43,7 +43,6 @@ import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.graphics.common.AlphaInterpretation; import android.hardware.graphics.common.DisplayDecorationSupport; -import android.os.Build; import android.os.Handler; import android.os.SystemProperties; import android.os.Trace; @@ -73,7 +72,6 @@ import com.android.settingslib.Utils; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.decor.CutoutDecorProviderFactory; import com.android.systemui.decor.DecorProvider; import com.android.systemui.decor.DecorProviderFactory; import com.android.systemui.decor.DecorProviderKt; @@ -141,11 +139,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab protected RoundedCornerResDelegate mRoundedCornerResDelegate; @VisibleForTesting protected DecorProviderFactory mRoundedCornerFactory; - private CutoutDecorProviderFactory mCutoutFactory; private int mProviderRefreshToken = 0; @VisibleForTesting protected OverlayWindow[] mOverlays = null; @VisibleForTesting + @Nullable + DisplayCutoutView[] mCutoutViews; + @VisibleForTesting ViewGroup mScreenDecorHwcWindow; @VisibleForTesting ScreenDecorHwcLayer mScreenDecorHwcLayer; @@ -187,28 +187,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab return; } - final int[] ids = { - R.id.display_cutout, - R.id.display_cutout_left, - R.id.display_cutout_right, - R.id.display_cutout_bottom - }; - int setProtectionCnt = 0; - for (int id: ids) { - final View view = getOverlayView(id); - if (!(view instanceof DisplayCutoutView)) { - continue; - } - ++setProtectionCnt; - final DisplayCutoutView dcv = (DisplayCutoutView) view; - dcv.setProtection(protectionPath, bounds); - dcv.enableShowProtection(true); - } - if (setProtectionCnt == 0) { - if (Build.isDebuggable()) { - throw new RuntimeException("CutoutView not initialized showCameraProtection"); - } else { - Log.e(TAG, "CutoutView not initialized showCameraProtection"); + if (mCutoutViews == null) { + Log.w(TAG, "DisplayCutoutView not initialized onApplyCameraProtection"); + return; + } + + // Show the extra protection around the front facing camera if necessary + for (DisplayCutoutView dcv : mCutoutViews) { + // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile + if (dcv != null) { + dcv.setProtection(protectionPath, bounds); + dcv.enableShowProtection(true); } } } @@ -230,26 +219,15 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab return; } - final int[] ids = { - R.id.display_cutout, - R.id.display_cutout_left, - R.id.display_cutout_right, - R.id.display_cutout_bottom - }; - int setProtectionCnt = 0; - for (int id: ids) { - final View view = getOverlayView(id); - if (!(view instanceof DisplayCutoutView)) { - continue; - } - ++setProtectionCnt; - ((DisplayCutoutView) view).enableShowProtection(false); + if (mCutoutViews == null) { + Log.w(TAG, "DisplayCutoutView not initialized onHideCameraProtection"); + return; } - if (setProtectionCnt == 0) { - if (Build.isDebuggable()) { - throw new RuntimeException("CutoutView not initialized hideCameraProtection"); - } else { - Log.e(TAG, "CutoutView not initialized hideCameraProtection"); + // Go back to the regular anti-aliasing + for (DisplayCutoutView dcv : mCutoutViews) { + // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile + if (dcv != null) { + dcv.enableShowProtection(false); } } } @@ -357,7 +335,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab decorProviders.addAll(mFaceScanningFactory.getProviders()); if (!hasHwLayer) { decorProviders.addAll(mRoundedCornerFactory.getProviders()); - decorProviders.addAll(mCutoutFactory.getProviders()); } return decorProviders; } @@ -402,7 +379,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio( getPhysicalPixelDisplaySizeRatio()); mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate); - mCutoutFactory = getCutoutFactory(); mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport(); updateHwLayerRoundedCornerDrawable(); setupDecorations(); @@ -507,13 +483,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab if (needToUpdateProviderViews) { updateOverlayProviderViews(null); } else { - updateOverlayProviderViews(new Integer[] { - mFaceScanningViewId, - R.id.display_cutout, - R.id.display_cutout_left, - R.id.display_cutout_right, - R.id.display_cutout_bottom, - }); + updateOverlayProviderViews(new Integer[] { mFaceScanningViewId }); + } + + if (mCutoutViews != null) { + final int size = mCutoutViews.length; + for (int i = 0; i < size; i++) { + final DisplayCutoutView cutoutView = mCutoutViews[i]; + if (cutoutView == null) { + continue; + } + cutoutView.onDisplayChanged(newUniqueId); + } } if (mScreenDecorHwcLayer != null) { @@ -526,9 +507,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab updateConfiguration(); } - @VisibleForTesting @Nullable - View getOverlayView(@IdRes int id) { + private View getOverlayView(@IdRes int id) { if (mOverlays == null) { return null; } @@ -585,18 +565,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab removeHwcOverlay(); } - boolean[] hasCreatedOverlay = new boolean[BOUNDS_POSITION_LENGTH]; + final DisplayCutout cutout = getCutout(); final boolean shouldOptimizeVisibility = shouldOptimizeVisibility(); - Integer bound; - while ((bound = DecorProviderKt.getProperBound(decorProviders)) != null) { - hasCreatedOverlay[bound] = true; - Pair<List<DecorProvider>, List<DecorProvider>> pair = - DecorProviderKt.partitionAlignedBound(decorProviders, bound); - decorProviders = pair.getSecond(); - createOverlay(bound, pair.getFirst(), shouldOptimizeVisibility); - } for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { - if (!hasCreatedOverlay[i]) { + if (shouldShowSwLayerCutout(i, cutout) + || shouldShowSwLayerFaceScan(i, cutout) + || shouldShowSwLayerRoundedCorner(i, cutout) + || shouldShowSwLayerPrivacyDot(i, cutout)) { + Pair<List<DecorProvider>, List<DecorProvider>> pair = + DecorProviderKt.partitionAlignedBound(decorProviders, i); + decorProviders = pair.getSecond(); + createOverlay(i, pair.getFirst(), shouldOptimizeVisibility); + } else { removeOverlay(i); } } @@ -659,10 +639,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } - // For unit test to override - protected CutoutDecorProviderFactory getCutoutFactory() { - return new CutoutDecorProviderFactory(mContext.getResources(), - mContext.getDisplay()); + @VisibleForTesting + DisplayCutout getCutout() { + return mContext.getDisplay().getCutout(); } @VisibleForTesting @@ -752,6 +731,16 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab overlayView.setAlpha(0); overlayView.setForceDarkAllowed(false); + // Only show cutout in mOverlays when hwc doesn't support screen decoration + if (mHwcScreenDecorationSupport == null) { + if (mCutoutViews == null) { + mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH]; + } + mCutoutViews[pos] = new DisplayCutoutView(mContext, pos); + overlayView.addView(mCutoutViews[pos]); + mCutoutViews[pos].updateRotation(mRotation); + } + mWindowManager.addView(overlayView, getWindowLayoutParams(pos)); overlayView.addOnLayoutChangeListener(new OnLayoutChangeListener() { @@ -958,12 +947,27 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mTintColor = Color.RED; } + if (mOverlays == null) { + return; + } + + for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { + if (mOverlays[i] == null) { + continue; + } + final ViewGroup overlayView = mOverlays[i].getRootView(); + final int size = overlayView.getChildCount(); + View child; + for (int j = 0; j < size; j++) { + child = overlayView.getChildAt(j); + if (child instanceof DisplayCutoutView && child.getId() == R.id.display_cutout) { + ((DisplayCutoutView) child).setColor(mTintColor); + } + } + } + updateOverlayProviderViews(new Integer[] { mFaceScanningViewId, - R.id.display_cutout, - R.id.display_cutout_left, - R.id.display_cutout_right, - R.id.display_cutout_bottom, R.id.rounded_corner_top_left, R.id.rounded_corner_top_right, R.id.rounded_corner_bottom_left, @@ -1088,6 +1092,15 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab updateHwLayerRoundedCornerDrawable(); } updateLayoutParams(); + // update cutout view rotation + if (mCutoutViews != null) { + for (final DisplayCutoutView cutoutView: mCutoutViews) { + if (cutoutView == null) { + continue; + } + cutoutView.updateRotation(mRotation); + } + } // update all provider views inside overlay updateOverlayProviderViews(null); @@ -1106,6 +1119,46 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab return mRoundedCornerFactory.getHasProviders(); } + 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 + // cutout. + final int rotatedTop = getBoundPositionFromRotation(BOUNDS_POSITION_TOP, mRotation); + final int rotatedBottom = getBoundPositionFromRotation(BOUNDS_POSITION_BOTTOM, mRotation); + if (emptyBoundsOrWaterfall || !cutout.getBoundingRectsAll()[rotatedTop].isEmpty() + || !cutout.getBoundingRectsAll()[rotatedBottom].isEmpty()) { + return pos == BOUNDS_POSITION_TOP || pos == BOUNDS_POSITION_BOTTOM; + } else { + return pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_RIGHT; + } + } + + private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout) + && mHwcScreenDecorationSupport == null; + } + + private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowSwLayerFaceScan(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + return mFaceScanningFactory.getHasProviders() && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowSwLayerCutout(@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() + && mHwcScreenDecorationSupport == null); + } + private boolean shouldOptimizeVisibility() { return (isPrivacyDotEnabled() || mFaceScanningFactory.getHasProviders()) && (mHwcScreenDecorationSupport != null @@ -1114,7 +1167,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } private boolean shouldDrawCutout() { - return mCutoutFactory.getHasProviders(); + return shouldDrawCutout(mContext); } static boolean shouldDrawCutout(Context context) { @@ -1230,6 +1283,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab paint.setColor(mColor); paint.setStyle(Paint.Style.FILL); + setId(R.id.display_cutout); if (DEBUG) { getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG, getWindowTitleByPos(pos) + " drawn in rot " + mRotation)); @@ -1237,9 +1291,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } public void setColor(int color) { - if (color == mColor) { - return; - } mColor = color; paint.setColor(mColor); invalidate(); diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt deleted file mode 100644 index cbed21cf65d6..000000000000 --- a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.content.res.Resources -import android.util.Log -import android.view.Display -import android.view.DisplayCutout -import android.view.DisplayInfo - -class CutoutDecorProviderFactory constructor( - private val res: Resources, - private val display: Display?, -) : DecorProviderFactory() { - - val displayInfo = DisplayInfo() - - override val hasProviders: Boolean - get() { - display?.getDisplayInfo(displayInfo) ?: run { - Log.w(TAG, "display is null, can't update displayInfo") - } - return DisplayCutout.getFillBuiltInDisplayCutout(res, displayInfo.uniqueId) - } - - override val providers: List<DecorProvider> - get() { - if (!hasProviders) { - return emptyList() - } - - return ArrayList<DecorProvider>().also { list -> - // We need to update displayInfo before using it, but it has already updated during - // accessing hasProviders field - displayInfo.displayCutout?.getBoundBaseOnCurrentRotation()?.let { bounds -> - for (bound in bounds) { - list.add( - CutoutDecorProviderImpl(bound.baseOnRotation0(displayInfo.rotation)) - ) - } - } - } - } -} - -private const val TAG = "CutoutDecorProviderFactory" diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt deleted file mode 100644 index 991b54e8035e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.content.Context -import android.view.DisplayCutout -import android.view.Surface -import android.view.View -import android.view.ViewGroup -import com.android.systemui.R -import com.android.systemui.ScreenDecorations.DisplayCutoutView - -class CutoutDecorProviderImpl( - @DisplayCutout.BoundsPosition override val alignedBound: Int -) : BoundDecorProvider() { - - override val viewId: Int = when (alignedBound) { - DisplayCutout.BOUNDS_POSITION_TOP -> R.id.display_cutout - DisplayCutout.BOUNDS_POSITION_LEFT -> R.id.display_cutout_left - DisplayCutout.BOUNDS_POSITION_RIGHT -> R.id.display_cutout_right - else -> R.id.display_cutout_bottom - } - - override fun inflateView( - context: Context, - parent: ViewGroup, - @Surface.Rotation rotation: Int, - tintColor: Int - ): View { - return DisplayCutoutView(context, alignedBound).also { view -> - view.id = viewId - view.setColor(tintColor) - parent.addView(view) - view.updateRotation(rotation) - } - } - - override fun onReloadResAndMeasure( - view: View, - reloadToken: Int, - @Surface.Rotation rotation: Int, - tintColor: Int, - displayUniqueId: String? - ) { - (view as? DisplayCutoutView)?.let { cutoutView -> - cutoutView.setColor(tintColor) - cutoutView.updateRotation(rotation) - cutoutView.onDisplayChanged(displayUniqueId) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt index 260c4b5a7830..de6d7278971c 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt @@ -32,7 +32,7 @@ abstract class DecorProvider { abstract val viewId: Int /** The number of total aligned bounds */ - val numOfAlignedBound: Int + val numOfAlignedEdge: Int get() = alignedBounds.size /** The aligned bounds for the view which is created through inflateView() */ @@ -57,8 +57,16 @@ abstract class DecorProvider { @Surface.Rotation rotation: Int, tintColor: Int ): View +} - override fun toString() = "${javaClass.simpleName}{alignedBounds=$alignedBounds}" +/** + * Split list to 2 list, and return it back as Pair<>. The providers on the first list contains this + * alignedBound element. The providers on the second list do not contain this alignedBound element + */ +fun List<DecorProvider>.partitionAlignedBound( + @DisplayCutout.BoundsPosition alignedBound: Int +): Pair<List<DecorProvider>, List<DecorProvider>> { + return partition { it.alignedBounds.contains(alignedBound) } } /** @@ -86,60 +94,3 @@ abstract class BoundDecorProvider : DecorProvider() { listOf(alignedBound) } } - -/** - * Split list to 2 list, and return it back as Pair<>. The providers on the first list contains this - * alignedBound element. The providers on the second list do not contain this alignedBound element - */ -fun List<DecorProvider>.partitionAlignedBound( - @DisplayCutout.BoundsPosition alignedBound: Int -): Pair<List<DecorProvider>, List<DecorProvider>> { - return partition { it.alignedBounds.contains(alignedBound) } -} - -/** - * Get the proper bound from DecorProvider list - * Time complexity: O(N), N is the number of providers - * - * Choose order - * 1. Return null if list is empty - * 2. If list contains BoundDecorProvider, return its alignedBound[0] because it is a must-have - * bound - * 3. Return the bound with most DecorProviders - */ -fun List<DecorProvider>.getProperBound(): Int? { - // Return null if list is empty - if (isEmpty()) { - return null - } - - // Choose alignedBounds[0] of BoundDecorProvider if any - val singleBoundProvider = firstOrNull { it.numOfAlignedBound == 1 } - if (singleBoundProvider != null) { - return singleBoundProvider.alignedBounds[0] - } - - // Return the bound with most DecorProviders - val boundCount = intArrayOf(0, 0, 0, 0) - for (provider in this) { - for (bound in provider.alignedBounds) { - boundCount[bound]++ - } - } - var maxCount = 0 - var maxCountBound: Int? = null - val bounds = arrayOf( - // Put top and bottom at first to get the highest priority to be chosen - DisplayCutout.BOUNDS_POSITION_TOP, - DisplayCutout.BOUNDS_POSITION_BOTTOM, - DisplayCutout.BOUNDS_POSITION_LEFT, - DisplayCutout.BOUNDS_POSITION_RIGHT - ) - for (bound in bounds) { - if (boundCount[bound] > maxCount) { - maxCountBound = bound - maxCount = boundCount[bound] - } - } - return maxCountBound -} diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt index 45b8a08a9b45..dfb0b5aad912 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt @@ -114,8 +114,7 @@ class OverlayWindow(private val context: Context) { pw.println(" rootView=$rootView") for (i in 0 until rootView.childCount) { val child = rootView.getChildAt(i) - val provider = viewProviderMap[child.id]?.second - pw.println(" child[$i]=$child $provider") + pw.println(" child[$i]=$child") } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index df10dfe9f160..64a7986d05b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; +import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH; import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; @@ -35,7 +36,6 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -49,6 +49,7 @@ import android.annotation.IdRes; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.TypedArray; +import android.graphics.Insets; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -59,6 +60,7 @@ import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.util.RotationUtils; import android.util.Size; import android.view.Display; import android.view.DisplayCutout; @@ -78,8 +80,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.decor.CornerDecorProvider; -import com.android.systemui.decor.CutoutDecorProviderFactory; -import com.android.systemui.decor.CutoutDecorProviderImpl; import com.android.systemui.decor.DecorProvider; import com.android.systemui.decor.DecorProviderFactory; import com.android.systemui.decor.FaceScanningOverlayProviderImpl; @@ -157,9 +157,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { @Mock private DisplayInfo mDisplayInfo; private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener; - @Mock - private CutoutDecorProviderFactory mCutoutFactory; - private List<DecorProvider> mMockCutoutList; @Before public void setup() { @@ -209,11 +206,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { DisplayCutout.BOUNDS_POSITION_RIGHT, R.layout.privacy_dot_bottom_right)); - // Default no cutout - mMockCutoutList = new ArrayList<>(); - doAnswer(it -> !(mMockCutoutList.isEmpty())).when(mCutoutFactory).getHasProviders(); - doReturn(mMockCutoutList).when(mCutoutFactory).getProviders(); - mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl( BOUNDS_POSITION_TOP, mAuthController, @@ -247,11 +239,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { super.updateOverlayWindowVisibilityIfViewExists(view); mExecutor.runAllReady(); } - - @Override - protected CutoutDecorProviderFactory getCutoutFactory() { - return ScreenDecorationsTest.this.mCutoutFactory; - } }); mScreenDecorations.mDisplayInfo = mDisplayInfo; doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio(); @@ -442,9 +429,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // No views added. @@ -459,9 +448,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); @@ -493,9 +484,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); @@ -523,9 +516,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); @@ -560,9 +555,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); - - // no cutout (default) + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // Size of corner view should same as rounded_corner_radius{_top|_bottom} @@ -578,9 +574,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView() @@ -613,10 +611,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); + 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(); View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() @@ -646,10 +647,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // Top window is created for top cutout. @@ -667,10 +671,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_CutoutShortEdge_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // Top window is created for top cutout. @@ -699,10 +706,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_CutoutLongEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); + 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. @@ -724,10 +734,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_CutoutLongEdge_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); + 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. @@ -749,10 +762,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // Top window is created for rounded corner and top cutout. @@ -775,10 +791,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutShortEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // Top window is created for rounded corner and top cutout. @@ -804,10 +823,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutLongEdge_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); + 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 and left cutout. @@ -820,10 +842,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutLongEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); + 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. @@ -838,11 +863,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // top and left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); + 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. @@ -856,11 +883,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testRounding_CutoutShortAndLongEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // top and left cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT)); - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); + 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. @@ -876,16 +905,21 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // Set to short edge cutout(top). - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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, false, View.VISIBLE); // Switch to long edge cutout(left). - mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_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, false, false, View.VISIBLE); @@ -895,10 +929,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); // Set to short edge cutout(top). - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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, View.VISIBLE); @@ -906,7 +943,9 @@ public class ScreenDecorationsTest extends SysuiTestCase { verify(mDotViewController, times(1)).setShowingListener(null); // Switch to long edge cutout(left). - mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_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, View.VISIBLE); @@ -934,16 +973,20 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testDelayedCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); - // No cutout (default) + // 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(); verifyOverlaysExistAndAdded(false, false, false, false, null); - // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); - + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) + .thenReturn(true); mScreenDecorations.onConfigurationChanged(new Configuration()); // Only top windows should be added. @@ -954,9 +997,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testDelayedCutout_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); - // no cutout (default) + // 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 with INVISIBLE because of only privacy dot, @@ -968,9 +1015,9 @@ public class ScreenDecorationsTest extends SysuiTestCase { verify(mDotViewController, times(1)).setShowingListener( mScreenDecorations.mPrivacyDotShowingListener); - // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); - + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) + .thenReturn(true); mScreenDecorations.onConfigurationChanged(new Configuration()); // Both top and bottom windows should be added with VISIBLE because of privacy dot and @@ -996,7 +1043,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning*/); mDisplayInfo.rotation = Surface.ROTATION_0; mScreenDecorations.start(); @@ -1010,7 +1058,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning*/); mDisplayInfo.rotation = Surface.ROTATION_270; mScreenDecorations.onConfigurationChanged(null); @@ -1023,7 +1072,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusTop() { setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); mScreenDecorations.start(); @@ -1044,7 +1094,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusBottom() { setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); mScreenDecorations.start(); @@ -1115,10 +1166,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testSupportHwcLayer_SwitchFrom_NotSupport() { setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // should only inflate mOverlays when the hwc doesn't support screen decoration @@ -1141,13 +1195,16 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testNotSupportHwcLayer_SwitchFrom_Support() { setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); decorationSupport.format = PixelFormat.R_8; doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // should only inflate hwc layer when the hwc supports screen decoration @@ -1177,13 +1234,16 @@ public class ScreenDecorationsTest extends SysuiTestCase { /* roundedTopDrawable */, getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + true /* faceScanning */); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); decorationSupport.format = PixelFormat.R_8; doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer @@ -1217,9 +1277,11 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, + true /* faceScanning */); - // no cutout (default) + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer @@ -1253,13 +1315,16 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testHwcLayer_noPrivacyDot_noFaceScanning() { setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); decorationSupport.format = PixelFormat.R_8; doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); @@ -1272,13 +1337,16 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testHwcLayer_PrivacyDot_FaceScanning() { setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + true /* faceScanning */); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); decorationSupport.format = PixelFormat.R_8; doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); @@ -1296,13 +1364,16 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnDisplayChanged_hwcLayer() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); decorationSupport.format = PixelFormat.R_8; doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); @@ -1319,16 +1390,18 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnDisplayChanged_nonHwcLayer() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_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(); - final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView) - mScreenDecorations.getOverlayView(R.id.display_cutout); - assertNotNull(cutoutView); + final ScreenDecorations.DisplayCutoutView cutoutView = + mScreenDecorations.mCutoutViews[BOUNDS_POSITION_TOP]; spyOn(cutoutView); doReturn(mDisplay).when(cutoutView).getDisplay(); @@ -1341,7 +1414,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testHasSameProvidersWithNullOverlays() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, + false /* faceScanning */); mScreenDecorations.start(); @@ -1359,7 +1433,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testHasSameProvidersWithPrivacyDots() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); + 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, + false /* faceScanning */); mScreenDecorations.start(); @@ -1396,7 +1471,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { private void setupResources(int radius, int radiusTop, int radiusBottom, @Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable, - int roundedPadding, boolean privacyDot, boolean faceScanning) { + int roundedPadding, boolean fillCutout, boolean privacyDot, boolean faceScanning) { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.array.config_displayUniqueIdArray, new String[]{}); @@ -1436,6 +1511,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { } mContext.getOrCreateTestableResources().addOverride( R.dimen.rounded_corner_content_padding, roundedPadding); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout); mPrivacyDecorProviders = new ArrayList<>(); if (privacyDot) { @@ -1454,4 +1531,19 @@ public class ScreenDecorationsTest extends SysuiTestCase { when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders); when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(faceScanning); } + + private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) { + final int rotation = mContext.getDisplay().getRotation(); + final Insets insets = RotationUtils.rotateInsets(safeInsets, rotation); + final Rect[] sorted = new Rect[BOUNDS_POSITION_LENGTH]; + for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { + final int rotatedPos = ScreenDecorations.getBoundPositionFromRotation(i, rotation); + if (cutoutBounds[i] != null) { + RotationUtils.rotateBounds(cutoutBounds[i], new Rect(0, 0, 100, 200), rotation); + } + sorted[rotatedPos] = cutoutBounds[i]; + } + return new DisplayCutout(insets, sorted[BOUNDS_POSITION_LEFT], sorted[BOUNDS_POSITION_TOP], + sorted[BOUNDS_POSITION_RIGHT], sorted[BOUNDS_POSITION_BOTTOM]); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt deleted file mode 100644 index 1040ec453a7c..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.graphics.Insets -import android.graphics.Rect -import android.testing.AndroidTestingRunner -import android.testing.TestableResources -import android.util.RotationUtils -import android.util.Size -import android.view.Display -import android.view.DisplayCutout -import android.view.DisplayCutout.BOUNDS_POSITION_LENGTH -import android.view.DisplayInfo -import android.view.Surface -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.util.mockito.any -import org.junit.Assert -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito.doAnswer -import org.mockito.MockitoAnnotations - -@RunWith(AndroidTestingRunner::class) -@SmallTest -class CutoutDecorProviderFactoryTest : SysuiTestCase() { - - @Mock private lateinit var display: Display - private var testableRes: TestableResources? = null - private lateinit var factory: CutoutDecorProviderFactory - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - testableRes = mContext.orCreateTestableResources - factory = CutoutDecorProviderFactory(testableRes!!.resources, display) - } - - private fun setupFillCutout(fillCutout: Boolean) { - testableRes!!.addOverride( - com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout - ) - } - - private fun setupDisplayInfo( - displayCutout: DisplayCutout? = null, - @Surface.Rotation rotation: Int = Surface.ROTATION_0, - displayId: Int = -1 - ) { - doAnswer { - it.getArgument<DisplayInfo>(0).let { info -> - info.displayCutout = displayCutout - info.rotation = rotation - info.displayId = displayId - } - true - }.`when`(display).getDisplayInfo(any<DisplayInfo>()) - } - - private fun getCutout( - safeInsets: Insets, - cutoutBounds: Array<Rect?>, - @Surface.Rotation rotation: Int = Surface.ROTATION_0, - cutoutParentSizeForRotate: Size = Size(100, 200) - ): DisplayCutout { - val insets = RotationUtils.rotateInsets(safeInsets, rotation) - val sorted = arrayOfNulls<Rect>(BOUNDS_POSITION_LENGTH) - for (pos in 0 until BOUNDS_POSITION_LENGTH) { - val rotatedPos = (pos - rotation + BOUNDS_POSITION_LENGTH) % BOUNDS_POSITION_LENGTH - if (cutoutBounds[pos] != null) { - RotationUtils.rotateBounds( - cutoutBounds[pos], - cutoutParentSizeForRotate.width, - cutoutParentSizeForRotate.height, - rotation - ) - } - sorted[rotatedPos] = cutoutBounds[pos] - } - return DisplayCutout( - insets, - sorted[DisplayCutout.BOUNDS_POSITION_LEFT], - sorted[DisplayCutout.BOUNDS_POSITION_TOP], - sorted[DisplayCutout.BOUNDS_POSITION_RIGHT], - sorted[DisplayCutout.BOUNDS_POSITION_BOTTOM] - ) - } - - @Test - fun testGetNothingIfNoCutout() { - setupFillCutout(false) - - Assert.assertFalse(factory.hasProviders) - Assert.assertEquals(0, factory.providers.size) - } - - @Test - fun testGetTopCutoutProvider() { - setupFillCutout(true) - setupDisplayInfo( - getCutout( - safeInsets = Insets.of(0, 1, 0, 0), - cutoutBounds = arrayOf(null, Rect(9, 0, 10, 1), null, null) - ) - ) - - Assert.assertTrue(factory.hasProviders) - - val providers = factory.providers - Assert.assertEquals(1, providers.size) - Assert.assertEquals(1, providers[0].numOfAlignedBound) - Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, providers[0].alignedBounds[0]) - } - - @Test - fun testGetBottomCutoutProviderOnLandscape() { - setupFillCutout(true) - setupDisplayInfo( - getCutout( - safeInsets = Insets.of(0, 0, 0, 1), - cutoutBounds = arrayOf(null, null, null, Rect(45, 199, 55, 200)), - rotation = Surface.ROTATION_90 - ), - Surface.ROTATION_90 - ) - - Assert.assertTrue(factory.hasProviders) - - val providers = factory.providers - Assert.assertEquals(1, providers.size) - Assert.assertEquals(1, providers[0].numOfAlignedBound) - Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_BOTTOM, providers[0].alignedBounds[0]) - } - - @Test - fun testGetLeftCutoutProviderOnSeascape() { - setupFillCutout(true) - setupDisplayInfo( - getCutout( - safeInsets = Insets.of(1, 0, 0, 0), - cutoutBounds = arrayOf(Rect(0, 20, 1, 40), null, null, null), - rotation = Surface.ROTATION_270 - ), - Surface.ROTATION_270 - ) - - Assert.assertTrue(factory.hasProviders) - - val providers = factory.providers - Assert.assertEquals(1, providers.size) - Assert.assertEquals(1, providers[0].numOfAlignedBound) - Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_LEFT, providers[0].alignedBounds[0]) - } - - @Test - fun testGetTopRightCutoutProviderOnReverse() { - setupFillCutout(true) - setupDisplayInfo( - getCutout( - safeInsets = Insets.of(0, 1, 1, 0), - cutoutBounds = arrayOf( - null, - Rect(9, 0, 10, 1), - Rect(99, 40, 100, 60), - null - ), - rotation = Surface.ROTATION_180 - ), - Surface.ROTATION_180 - ) - - Assert.assertTrue(factory.hasProviders) - - val providers = factory.providers - Assert.assertEquals(2, providers.size) - Assert.assertEquals(1, providers[0].numOfAlignedBound) - Assert.assertEquals(1, providers[1].numOfAlignedBound) - providers.sortedBy { it.alignedBounds[0] }.let { - Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, it[0].alignedBounds[0]) - Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_RIGHT, it[1].alignedBounds[0]) - } - } -} |