Merge changes from topic "cutoutProvider" into tm-qpr-dev am: 41001681e7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19569436

Change-Id: I3ca5474a08ff00e98c80512fb3c96dcd17636041
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Milton Wu
2022-08-31 09:42:40 +00:00
committed by Automerger Merge Worker
8 changed files with 557 additions and 327 deletions

View File

@@ -131,7 +131,11 @@
<!-- For StatusIconContainer to tag its icon views --> <!-- For StatusIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" /> <item type="id" name="status_bar_view_state_tag" />
<!-- Default display cutout on the physical top of screen -->
<item type="id" name="display_cutout" /> <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" /> <item type="id" name="row_tag_for_content_view" />

View File

@@ -72,6 +72,7 @@ import com.android.settingslib.Utils;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.decor.CutoutDecorProviderFactory;
import com.android.systemui.decor.DecorProvider; import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory; import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.DecorProviderKt; import com.android.systemui.decor.DecorProviderKt;
@@ -118,6 +119,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
private static final boolean VERBOSE = false; private static final boolean VERBOSE = false;
static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS; static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private static final int[] DISPLAY_CUTOUT_IDS = {
R.id.display_cutout,
R.id.display_cutout_left,
R.id.display_cutout_right,
R.id.display_cutout_bottom
};
private DisplayManager mDisplayManager; private DisplayManager mDisplayManager;
@VisibleForTesting @VisibleForTesting
protected boolean mIsRegistered; protected boolean mIsRegistered;
@@ -139,13 +147,11 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
protected RoundedCornerResDelegate mRoundedCornerResDelegate; protected RoundedCornerResDelegate mRoundedCornerResDelegate;
@VisibleForTesting @VisibleForTesting
protected DecorProviderFactory mRoundedCornerFactory; protected DecorProviderFactory mRoundedCornerFactory;
private CutoutDecorProviderFactory mCutoutFactory;
private int mProviderRefreshToken = 0; private int mProviderRefreshToken = 0;
@VisibleForTesting @VisibleForTesting
protected OverlayWindow[] mOverlays = null; protected OverlayWindow[] mOverlays = null;
@VisibleForTesting @VisibleForTesting
@Nullable
DisplayCutoutView[] mCutoutViews;
@VisibleForTesting
ViewGroup mScreenDecorHwcWindow; ViewGroup mScreenDecorHwcWindow;
@VisibleForTesting @VisibleForTesting
ScreenDecorHwcLayer mScreenDecorHwcLayer; ScreenDecorHwcLayer mScreenDecorHwcLayer;
@@ -187,18 +193,19 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return; return;
} }
if (mCutoutViews == null) { int setProtectionCnt = 0;
Log.w(TAG, "DisplayCutoutView not initialized onApplyCameraProtection"); for (int id: DISPLAY_CUTOUT_IDS) {
return; final View view = getOverlayView(id);
if (!(view instanceof DisplayCutoutView)) {
continue;
} }
++setProtectionCnt;
// Show the extra protection around the front facing camera if necessary final DisplayCutoutView dcv = (DisplayCutoutView) view;
for (DisplayCutoutView dcv : mCutoutViews) {
// Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
if (dcv != null) {
dcv.setProtection(protectionPath, bounds); dcv.setProtection(protectionPath, bounds);
dcv.enableShowProtection(true); dcv.enableShowProtection(true);
} }
if (setProtectionCnt == 0) {
Log.e(TAG, "CutoutView not initialized showCameraProtection");
} }
} }
@@ -219,16 +226,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return; return;
} }
if (mCutoutViews == null) { int setProtectionCnt = 0;
Log.w(TAG, "DisplayCutoutView not initialized onHideCameraProtection"); for (int id: DISPLAY_CUTOUT_IDS) {
return; final View view = getOverlayView(id);
if (!(view instanceof DisplayCutoutView)) {
continue;
} }
// Go back to the regular anti-aliasing ++setProtectionCnt;
for (DisplayCutoutView dcv : mCutoutViews) { ((DisplayCutoutView) view).enableShowProtection(false);
// Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
if (dcv != null) {
dcv.enableShowProtection(false);
} }
if (setProtectionCnt == 0) {
Log.e(TAG, "CutoutView not initialized hideCameraProtection");
} }
} }
@@ -335,6 +343,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
decorProviders.addAll(mFaceScanningFactory.getProviders()); decorProviders.addAll(mFaceScanningFactory.getProviders());
if (!hasHwLayer) { if (!hasHwLayer) {
decorProviders.addAll(mRoundedCornerFactory.getProviders()); decorProviders.addAll(mRoundedCornerFactory.getProviders());
decorProviders.addAll(mCutoutFactory.getProviders());
} }
return decorProviders; return decorProviders;
} }
@@ -379,6 +388,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio( mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
getPhysicalPixelDisplaySizeRatio()); getPhysicalPixelDisplaySizeRatio());
mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate); mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
mCutoutFactory = getCutoutFactory();
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport(); mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
updateHwLayerRoundedCornerDrawable(); updateHwLayerRoundedCornerDrawable();
setupDecorations(); setupDecorations();
@@ -483,18 +493,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (needToUpdateProviderViews) { if (needToUpdateProviderViews) {
updateOverlayProviderViews(null); updateOverlayProviderViews(null);
} else { } else {
updateOverlayProviderViews(new Integer[] { mFaceScanningViewId }); updateOverlayProviderViews(new Integer[] {
} mFaceScanningViewId,
R.id.display_cutout,
if (mCutoutViews != null) { R.id.display_cutout_left,
final int size = mCutoutViews.length; R.id.display_cutout_right,
for (int i = 0; i < size; i++) { R.id.display_cutout_bottom,
final DisplayCutoutView cutoutView = mCutoutViews[i]; });
if (cutoutView == null) {
continue;
}
cutoutView.onDisplayChanged(newUniqueId);
}
} }
if (mScreenDecorHwcLayer != null) { if (mScreenDecorHwcLayer != null) {
@@ -507,8 +512,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
updateConfiguration(); updateConfiguration();
} }
@VisibleForTesting
@Nullable @Nullable
private View getOverlayView(@IdRes int id) { View getOverlayView(@IdRes int id) {
if (mOverlays == null) { if (mOverlays == null) {
return null; return null;
} }
@@ -565,18 +571,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
removeHwcOverlay(); removeHwcOverlay();
} }
final DisplayCutout cutout = getCutout(); boolean[] hasCreatedOverlay = new boolean[BOUNDS_POSITION_LENGTH];
final boolean shouldOptimizeVisibility = shouldOptimizeVisibility(); final boolean shouldOptimizeVisibility = shouldOptimizeVisibility();
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { Integer bound;
if (shouldShowSwLayerCutout(i, cutout) while ((bound = DecorProviderKt.getProperBound(decorProviders)) != null) {
|| shouldShowSwLayerFaceScan(i, cutout) hasCreatedOverlay[bound] = true;
|| shouldShowSwLayerRoundedCorner(i, cutout)
|| shouldShowSwLayerPrivacyDot(i, cutout)) {
Pair<List<DecorProvider>, List<DecorProvider>> pair = Pair<List<DecorProvider>, List<DecorProvider>> pair =
DecorProviderKt.partitionAlignedBound(decorProviders, i); DecorProviderKt.partitionAlignedBound(decorProviders, bound);
decorProviders = pair.getSecond(); decorProviders = pair.getSecond();
createOverlay(i, pair.getFirst(), shouldOptimizeVisibility); createOverlay(bound, pair.getFirst(), shouldOptimizeVisibility);
} else { }
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (!hasCreatedOverlay[i]) {
removeOverlay(i); removeOverlay(i);
} }
} }
@@ -639,9 +645,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
} }
@VisibleForTesting // For unit test to override
DisplayCutout getCutout() { protected CutoutDecorProviderFactory getCutoutFactory() {
return mContext.getDisplay().getCutout(); return new CutoutDecorProviderFactory(mContext.getResources(),
mContext.getDisplay());
} }
@VisibleForTesting @VisibleForTesting
@@ -731,16 +738,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
overlayView.setAlpha(0); overlayView.setAlpha(0);
overlayView.setForceDarkAllowed(false); 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)); mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
overlayView.addOnLayoutChangeListener(new OnLayoutChangeListener() { overlayView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -920,6 +917,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
private void setupCameraListener() { private void setupCameraListener() {
// TODO(b/238143614) Support dual screen camera protection
Resources res = mContext.getResources(); Resources res = mContext.getResources();
boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection); boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection);
if (enabled) { if (enabled) {
@@ -948,27 +946,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mTintColor = Color.RED; 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[] { updateOverlayProviderViews(new Integer[] {
mFaceScanningViewId, 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_left,
R.id.rounded_corner_top_right, R.id.rounded_corner_top_right,
R.id.rounded_corner_bottom_left, R.id.rounded_corner_bottom_left,
@@ -1093,15 +1076,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
updateHwLayerRoundedCornerDrawable(); updateHwLayerRoundedCornerDrawable();
} }
updateLayoutParams(); 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 // update all provider views inside overlay
updateOverlayProviderViews(null); updateOverlayProviderViews(null);
@@ -1120,46 +1094,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return mRoundedCornerFactory.getHasProviders(); 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() { private boolean shouldOptimizeVisibility() {
return (isPrivacyDotEnabled() || mFaceScanningFactory.getHasProviders()) return (isPrivacyDotEnabled() || mFaceScanningFactory.getHasProviders())
&& (mHwcScreenDecorationSupport != null && (mHwcScreenDecorationSupport != null
@@ -1168,7 +1102,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
private boolean shouldDrawCutout() { private boolean shouldDrawCutout() {
return shouldDrawCutout(mContext); return mCutoutFactory.getHasProviders();
} }
static boolean shouldDrawCutout(Context context) { static boolean shouldDrawCutout(Context context) {
@@ -1284,7 +1218,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
paint.setColor(mColor); paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL); paint.setStyle(Paint.Style.FILL);
setId(R.id.display_cutout);
if (DEBUG) { if (DEBUG) {
getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG, getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
getWindowTitleByPos(pos) + " drawn in rot " + mRotation)); getWindowTitleByPos(pos) + " drawn in rot " + mRotation));
@@ -1292,6 +1225,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
public void setColor(int color) { public void setColor(int color) {
if (color == mColor) {
return;
}
mColor = color; mColor = color;
paint.setColor(mColor); paint.setColor(mColor);
invalidate(); invalidate();
@@ -1299,6 +1235,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
@Override @Override
public void updateRotation(int rotation) { public void updateRotation(int rotation) {
// updateRotation() is called inside CutoutDecorProviderImpl::onReloadResAndMeasure()
// during onDisplayChanged. In order to prevent reloading cutout info in super class,
// check mRotation at first
if (rotation == mRotation) {
return;
}
mRotation = rotation; mRotation = rotation;
super.updateRotation(rotation); super.updateRotation(rotation);
} }

View File

@@ -0,0 +1,60 @@
/*
* 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"

View File

@@ -0,0 +1,65 @@
/*
* 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)
}
}
}

View File

@@ -32,7 +32,7 @@ abstract class DecorProvider {
abstract val viewId: Int abstract val viewId: Int
/** The number of total aligned bounds */ /** The number of total aligned bounds */
val numOfAlignedEdge: Int val numOfAlignedBound: Int
get() = alignedBounds.size get() = alignedBounds.size
/** The aligned bounds for the view which is created through inflateView() */ /** The aligned bounds for the view which is created through inflateView() */
@@ -57,16 +57,8 @@ abstract class DecorProvider {
@Surface.Rotation rotation: Int, @Surface.Rotation rotation: Int,
tintColor: Int tintColor: Int
): View ): 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) }
} }
/** /**
@@ -94,3 +86,61 @@ abstract class BoundDecorProvider : DecorProvider() {
listOf(alignedBound) listOf(alignedBound)
} }
} }
/**
* Split list to 2 sub-lists, 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
}

View File

@@ -114,7 +114,8 @@ class OverlayWindow(private val context: Context) {
pw.println(" rootView=$rootView") pw.println(" rootView=$rootView")
for (i in 0 until rootView.childCount) { for (i in 0 until rootView.childCount) {
val child = rootView.getChildAt(i) val child = rootView.getChildAt(i)
pw.println(" child[$i]=$child") val provider = viewProviderMap[child.id]?.second
pw.println(" child[$i]=$child $provider")
} }
} }
} }

View File

@@ -16,7 +16,6 @@ package com.android.systemui;
import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; 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_RIGHT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -36,6 +35,7 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -49,7 +49,6 @@ import android.annotation.IdRes;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
@@ -60,7 +59,6 @@ import android.os.Handler;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
import android.util.RotationUtils;
import android.util.Size; import android.util.Size;
import android.view.Display; import android.view.Display;
import android.view.DisplayCutout; import android.view.DisplayCutout;
@@ -80,6 +78,8 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.decor.CornerDecorProvider; 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.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory; import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.FaceScanningOverlayProviderImpl; import com.android.systemui.decor.FaceScanningOverlayProviderImpl;
@@ -157,6 +157,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
@Mock @Mock
private DisplayInfo mDisplayInfo; private DisplayInfo mDisplayInfo;
private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener; private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
@Mock
private CutoutDecorProviderFactory mCutoutFactory;
private List<DecorProvider> mMockCutoutList;
@Before @Before
public void setup() { public void setup() {
@@ -206,6 +209,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
DisplayCutout.BOUNDS_POSITION_RIGHT, DisplayCutout.BOUNDS_POSITION_RIGHT,
R.layout.privacy_dot_bottom_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( mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl(
BOUNDS_POSITION_TOP, BOUNDS_POSITION_TOP,
mAuthController, mAuthController,
@@ -239,6 +247,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
super.updateOverlayWindowVisibilityIfViewExists(view); super.updateOverlayWindowVisibilityIfViewExists(view);
mExecutor.runAllReady(); mExecutor.runAllReady();
} }
@Override
protected CutoutDecorProviderFactory getCutoutFactory() {
return ScreenDecorationsTest.this.mCutoutFactory;
}
}); });
mScreenDecorations.mDisplayInfo = mDisplayInfo; mScreenDecorations.mDisplayInfo = mDisplayInfo;
doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio(); doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
@@ -429,11 +442,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() { public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// No views added. // No views added.
@@ -448,11 +459,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() { public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -484,11 +493,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() { public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -516,11 +523,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() { public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -555,10 +560,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Size of corner view should same as rounded_corner_radius{_top|_bottom} // Size of corner view should same as rounded_corner_radius{_top|_bottom}
@@ -574,11 +578,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView() View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
@@ -611,13 +613,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// left cutout // left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
@@ -647,13 +646,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutShortEdge_NoPrivacyDot() { public void testNoRounding_CutoutShortEdge_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for top cutout. // Top window is created for top cutout.
@@ -671,13 +667,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutShortEdge_PrivacyDot() { public void testNoRounding_CutoutShortEdge_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for top cutout. // Top window is created for top cutout.
@@ -706,13 +699,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutLongEdge_NoPrivacyDot() { public void testNoRounding_CutoutLongEdge_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// left cutout // left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Left window is created for left cutout. // Left window is created for left cutout.
@@ -734,13 +724,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutLongEdge_PrivacyDot() { public void testNoRounding_CutoutLongEdge_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// left cutout // left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Left window is created for left cutout. // Left window is created for left cutout.
@@ -762,13 +749,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortEdge_NoPrivacyDot() { public void testRounding_CutoutShortEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
@@ -791,13 +775,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortEdge_PrivacyDot() { public void testRounding_CutoutShortEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
@@ -823,13 +804,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutLongEdge_NoPrivacyDot() { public void testRounding_CutoutLongEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// left cutout // left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Left window is created for rounded corner and left cutout. // Left window is created for rounded corner and left cutout.
@@ -842,13 +820,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutLongEdge_PrivacyDot() { public void testRounding_CutoutLongEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// left cutout // left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Left window is created for rounded corner, left cutout, and privacy. // Left window is created for rounded corner, left cutout, and privacy.
@@ -863,13 +838,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() { public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top and left cutout // top and left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds)) mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
@@ -883,13 +856,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortAndLongEdge_PrivacyDot() { public void testRounding_CutoutShortAndLongEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top and left cutout // top and left cutout
final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds)) mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
@@ -905,21 +876,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() { public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// Set to short edge cutout(top). // Set to short edge cutout(top).
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE); verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
// Switch to long edge cutout(left). // Switch to long edge cutout(left).
final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE); verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
@@ -929,13 +895,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() { public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// Set to short edge cutout(top). // Set to short edge cutout(top).
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
@@ -943,9 +906,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verify(mDotViewController, times(1)).setShowingListener(null); verify(mDotViewController, times(1)).setShowingListener(null);
// Switch to long edge cutout(left). // Switch to long edge cutout(left).
final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE); verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
@@ -973,20 +934,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testDelayedCutout_NoPrivacyDot() { public void testDelayedCutout_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // No cutout (default)
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(); mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, false, false, false, null); verifyOverlaysExistAndAdded(false, false, false, false, null);
when(mContext.getResources().getBoolean( // top cutout
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
.thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
// Only top windows should be added. // Only top windows should be added.
@@ -997,13 +954,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testDelayedCutout_PrivacyDot() { public void testDelayedCutout_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // no cutout (default)
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(); mScreenDecorations.start();
// Both top and bottom windows should be added with INVISIBLE because of only privacy dot, // Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
@@ -1015,9 +968,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verify(mDotViewController, times(1)).setShowingListener( verify(mDotViewController, times(1)).setShowingListener(
mScreenDecorations.mPrivacyDotShowingListener); mScreenDecorations.mPrivacyDotShowingListener);
when(mContext.getResources().getBoolean( // top cutout
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
.thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
// Both top and bottom windows should be added with VISIBLE because of privacy dot and // Both top and bottom windows should be added with VISIBLE because of privacy dot and
@@ -1043,8 +996,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
false /* faceScanning*/);
mDisplayInfo.rotation = Surface.ROTATION_0; mDisplayInfo.rotation = Surface.ROTATION_0;
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1058,8 +1010,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
false /* faceScanning*/);
mDisplayInfo.rotation = Surface.ROTATION_270; mDisplayInfo.rotation = Surface.ROTATION_270;
mScreenDecorations.onConfigurationChanged(null); mScreenDecorations.onConfigurationChanged(null);
@@ -1072,8 +1023,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnlyRoundedCornerRadiusTop() { public void testOnlyRoundedCornerRadiusTop() {
setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1094,8 +1044,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnlyRoundedCornerRadiusBottom() { public void testOnlyRoundedCornerRadiusBottom() {
setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1166,13 +1115,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testSupportHwcLayer_SwitchFrom_NotSupport() { public void testSupportHwcLayer_SwitchFrom_NotSupport() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// should only inflate mOverlays when the hwc doesn't support screen decoration // should only inflate mOverlays when the hwc doesn't support screen decoration
@@ -1195,16 +1141,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNotSupportHwcLayer_SwitchFrom_Support() { public void testNotSupportHwcLayer_SwitchFrom_Support() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// should only inflate hwc layer when the hwc supports screen decoration // should only inflate hwc layer when the hwc supports screen decoration
@@ -1234,16 +1177,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */, /* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
/* roundedBottomDrawable */, /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
true /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1277,11 +1217,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() { public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
true /* faceScanning */);
// no cutout // no cutout (default)
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1315,16 +1253,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHwcLayer_noPrivacyDot_noFaceScanning() { public void testHwcLayer_noPrivacyDot_noFaceScanning() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1337,16 +1272,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHwcLayer_PrivacyDot_FaceScanning() { public void testHwcLayer_PrivacyDot_FaceScanning() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */, setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
true /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1364,16 +1296,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnDisplayChanged_hwcLayer() { public void testOnDisplayChanged_hwcLayer() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1390,18 +1319,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnDisplayChanged_nonHwcLayer() { public void testOnDisplayChanged_nonHwcLayer() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
// top cutout // top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
final ScreenDecorations.DisplayCutoutView cutoutView = final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView)
mScreenDecorations.mCutoutViews[BOUNDS_POSITION_TOP]; mScreenDecorations.getOverlayView(R.id.display_cutout);
assertNotNull(cutoutView);
spyOn(cutoutView); spyOn(cutoutView);
doReturn(mDisplay).when(cutoutView).getDisplay(); doReturn(mDisplay).when(cutoutView).getDisplay();
@@ -1414,8 +1341,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHasSameProvidersWithNullOverlays() { public void testHasSameProvidersWithNullOverlays() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */, 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1433,8 +1359,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHasSameProvidersWithPrivacyDots() { public void testHasSameProvidersWithPrivacyDots() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */, 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
false /* faceScanning */);
mScreenDecorations.start(); mScreenDecorations.start();
@@ -1471,7 +1396,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
private void setupResources(int radius, int radiusTop, int radiusBottom, private void setupResources(int radius, int radiusTop, int radiusBottom,
@Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable, @Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable,
int roundedPadding, boolean fillCutout, boolean privacyDot, boolean faceScanning) { int roundedPadding, boolean privacyDot, boolean faceScanning) {
mContext.getOrCreateTestableResources().addOverride( mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.array.config_displayUniqueIdArray, com.android.internal.R.array.config_displayUniqueIdArray,
new String[]{}); new String[]{});
@@ -1511,8 +1436,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
} }
mContext.getOrCreateTestableResources().addOverride( mContext.getOrCreateTestableResources().addOverride(
R.dimen.rounded_corner_content_padding, roundedPadding); R.dimen.rounded_corner_content_padding, roundedPadding);
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
mPrivacyDecorProviders = new ArrayList<>(); mPrivacyDecorProviders = new ArrayList<>();
if (privacyDot) { if (privacyDot) {
@@ -1531,19 +1454,4 @@ public class ScreenDecorationsTest extends SysuiTestCase {
when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders); when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(faceScanning); 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]);
}
} }

View File

@@ -0,0 +1,200 @@
/*
* 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])
}
}
}