Merge changes from topic "cutoutProvider" into tm-qpr-dev

* changes:
  Re-land ScreenDecorations Cutout Provider
  Move color and display info into DecorProvider
This commit is contained in:
Milton Wu
2022-08-31 09:18:33 +00:00
committed by Android (Google) Code Review
14 changed files with 748 additions and 485 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

@@ -47,7 +47,8 @@ import com.android.systemui.animation.Interpolators
open class DisplayCutoutBaseView : View, RegionInterceptableView { open class DisplayCutoutBaseView : View, RegionInterceptableView {
private var shouldDrawCutout: Boolean = DisplayCutout.getFillBuiltInDisplayCutout( private var shouldDrawCutout: Boolean = DisplayCutout.getFillBuiltInDisplayCutout(
context.resources, context.display?.uniqueId) context.resources, context.display?.uniqueId
)
private var displayUniqueId: String? = null private var displayUniqueId: String? = null
private var displayMode: Display.Mode? = null private var displayMode: Display.Mode? = null
protected val location = IntArray(2) protected val location = IntArray(2)
@@ -74,8 +75,8 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
: super(context, attrs, defStyleAttr) super(context, attrs, defStyleAttr)
override fun onAttachedToWindow() { override fun onAttachedToWindow() {
super.onAttachedToWindow() super.onAttachedToWindow()
@@ -85,7 +86,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
onUpdate() onUpdate()
} }
fun onDisplayChanged(displayId: Int) { fun onDisplayChanged(newDisplayUniqueId: String?) {
val oldMode: Display.Mode? = displayMode val oldMode: Display.Mode? = displayMode
val display: Display? = context.display val display: Display? = context.display
displayMode = display?.mode displayMode = display?.mode
@@ -93,7 +94,8 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
if (displayUniqueId != display?.uniqueId) { if (displayUniqueId != display?.uniqueId) {
displayUniqueId = display?.uniqueId displayUniqueId = display?.uniqueId
shouldDrawCutout = DisplayCutout.getFillBuiltInDisplayCutout( shouldDrawCutout = DisplayCutout.getFillBuiltInDisplayCutout(
context.resources, displayUniqueId) context.resources, displayUniqueId
)
} }
// Skip if display mode or cutout hasn't changed. // Skip if display mode or cutout hasn't changed.
@@ -101,7 +103,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
display?.cutout == displayInfo.displayCutout) { display?.cutout == displayInfo.displayCutout) {
return return
} }
if (displayId == display?.displayId) { if (newDisplayUniqueId == display?.uniqueId) {
updateCutout() updateCutout()
updateProtectionBoundingPath() updateProtectionBoundingPath()
onUpdate() onUpdate()
@@ -147,8 +149,9 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
cutoutBounds.translate(-location[0], -location[1]) cutoutBounds.translate(-location[0], -location[1])
// Intersect with window's frame // Intersect with window's frame
cutoutBounds.op(rootView.left, rootView.top, rootView.right, rootView.bottom, cutoutBounds.op(
Region.Op.INTERSECT) rootView.left, rootView.top, rootView.right, rootView.bottom, Region.Op.INTERSECT
)
return cutoutBounds return cutoutBounds
} }
@@ -171,9 +174,12 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
protected open fun drawCutoutProtection(canvas: Canvas) { protected open fun drawCutoutProtection(canvas: Canvas) {
if (cameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE && if (cameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE &&
!protectionRect.isEmpty) { !protectionRect.isEmpty
canvas.scale(cameraProtectionProgress, cameraProtectionProgress, ) {
protectionRect.centerX(), protectionRect.centerY()) canvas.scale(
cameraProtectionProgress, cameraProtectionProgress, protectionRect.centerX(),
protectionRect.centerY()
)
canvas.drawPath(protectionPath, paint) canvas.drawPath(protectionPath, paint)
} }
} }
@@ -205,14 +211,17 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
requestLayout() requestLayout()
} }
cameraProtectionAnimator?.cancel() cameraProtectionAnimator?.cancel()
cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress, cameraProtectionAnimator = ValueAnimator.ofFloat(
if (showProtection) 1.0f else HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750) cameraProtectionProgress,
if (showProtection) 1.0f else HIDDEN_CAMERA_PROTECTION_SCALE
).setDuration(750)
cameraProtectionAnimator?.interpolator = Interpolators.DECELERATE_QUINT cameraProtectionAnimator?.interpolator = Interpolators.DECELERATE_QUINT
cameraProtectionAnimator?.addUpdateListener(ValueAnimator.AnimatorUpdateListener { cameraProtectionAnimator?.addUpdateListener(
animation: ValueAnimator -> ValueAnimator.AnimatorUpdateListener { animation: ValueAnimator ->
cameraProtectionProgress = animation.animatedValue as Float cameraProtectionProgress = animation.animatedValue as Float
invalidate() invalidate()
}) }
)
cameraProtectionAnimator?.addListener(object : AnimatorListenerAdapter() { cameraProtectionAnimator?.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
cameraProtectionAnimator = null cameraProtectionAnimator = null
@@ -245,8 +254,10 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
// Apply rotation. // Apply rotation.
val lw: Int = displayInfo.logicalWidth val lw: Int = displayInfo.logicalWidth
val lh: Int = displayInfo.logicalHeight val lh: Int = displayInfo.logicalHeight
val flipped = (displayInfo.rotation == Surface.ROTATION_90 || val flipped = (
displayInfo.rotation == Surface.ROTATION_270) displayInfo.rotation == Surface.ROTATION_90 ||
displayInfo.rotation == Surface.ROTATION_270
)
val dw = if (flipped) lh else lw val dw = if (flipped) lh else lw
val dh = if (flipped) lw else lh val dh = if (flipped) lw else lh
transformPhysicalToLogicalCoordinates(displayInfo.rotation, dw, dh, m) transformPhysicalToLogicalCoordinates(displayInfo.rotation, dw, dh, m)
@@ -275,7 +286,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
// We purposely ignore refresh rate and id changes here, because we don't need to // We purposely ignore refresh rate and id changes here, because we don't need to
// invalidate for those, and they can trigger the refresh rate to increase // invalidate for those, and they can trigger the refresh rate to increase
return oldMode?.physicalHeight != newMode?.physicalHeight || return oldMode?.physicalHeight != newMode?.physicalHeight ||
oldMode?.physicalWidth != newMode?.physicalWidth oldMode?.physicalWidth != newMode?.physicalWidth
} }
companion object { companion object {

View File

@@ -32,7 +32,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
@@ -73,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;
@@ -92,10 +92,8 @@ import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
@@ -121,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;
@@ -142,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;
@@ -190,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;
// 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);
} }
++setProtectionCnt;
final DisplayCutoutView dcv = (DisplayCutoutView) view;
dcv.setProtection(protectionPath, bounds);
dcv.enableShowProtection(true);
}
if (setProtectionCnt == 0) {
Log.e(TAG, "CutoutView not initialized showCameraProtection");
} }
} }
@@ -222,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)) {
// Go back to the regular anti-aliasing continue;
for (DisplayCutoutView dcv : mCutoutViews) {
// Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
if (dcv != null) {
dcv.enableShowProtection(false);
} }
++setProtectionCnt;
((DisplayCutoutView) view).enableShowProtection(false);
}
if (setProtectionCnt == 0) {
Log.e(TAG, "CutoutView not initialized hideCameraProtection");
} }
} }
@@ -338,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;
} }
@@ -382,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();
@@ -448,6 +455,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
} }
boolean needToUpdateProviderViews = false;
final String newUniqueId = mDisplayInfo.uniqueId; final String newUniqueId = mDisplayInfo.uniqueId;
if (!Objects.equals(newUniqueId, mDisplayUniqueId)) { if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
mDisplayUniqueId = newUniqueId; mDisplayUniqueId = newUniqueId;
@@ -470,8 +478,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
updateHwLayerRoundedCornerDrawable(); updateHwLayerRoundedCornerDrawable();
updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerExistAndSize();
} }
needToUpdateProviderViews = true;
updateOverlayProviderViews();
} }
final float newRatio = getPhysicalPixelDisplaySizeRatio(); final float newRatio = getPhysicalPixelDisplaySizeRatio();
@@ -480,28 +487,23 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (mScreenDecorHwcLayer != null) { if (mScreenDecorHwcLayer != null) {
updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerExistAndSize();
} }
updateOverlayProviderViews(); needToUpdateProviderViews = true;
} }
if (mCutoutViews != null) { if (needToUpdateProviderViews) {
final int size = mCutoutViews.length; updateOverlayProviderViews(null);
for (int i = 0; i < size; i++) { } else {
final DisplayCutoutView cutoutView = mCutoutViews[i]; updateOverlayProviderViews(new Integer[] {
if (cutoutView == null) { mFaceScanningViewId,
continue; R.id.display_cutout,
} R.id.display_cutout_left,
cutoutView.onDisplayChanged(displayId); R.id.display_cutout_right,
} R.id.display_cutout_bottom,
} });
DisplayCutoutView overlay = (DisplayCutoutView) getOverlayView(mFaceScanningViewId);
if (overlay != null) {
// handle display resolution changes
overlay.onDisplayChanged(displayId);
} }
if (mScreenDecorHwcLayer != null) { if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.onDisplayChanged(displayId); mScreenDecorHwcLayer.onDisplayChanged(newUniqueId);
} }
} }
}; };
@@ -510,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;
} }
@@ -568,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();
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++) { for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (shouldShowSwLayerCutout(i, cutout) if (!hasCreatedOverlay[i]) {
|| 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); removeOverlay(i);
} }
} }
@@ -642,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
@@ -734,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() {
@@ -804,7 +798,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return; return;
} }
removeOverlayView(provider.getViewId()); removeOverlayView(provider.getViewId());
overlay.addDecorProvider(provider, mRotation); overlay.addDecorProvider(provider, mRotation, mTintColor);
}); });
} }
// Use visibility of privacy dot views & face scanning view to determine the overlay's // Use visibility of privacy dot views & face scanning view to determine the overlay's
@@ -923,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) {
@@ -951,45 +946,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mTintColor = Color.RED; mTintColor = Color.RED;
} }
if (mOverlays == null) { updateOverlayProviderViews(new Integer[] {
return; mFaceScanningViewId,
} R.id.display_cutout,
R.id.display_cutout_left,
// When the hwc supports screen decorations, the layer will use the A8 color mode which R.id.display_cutout_right,
// won't be affected by the color inversion. If the composition goes the client composition R.id.display_cutout_bottom,
// route, the color inversion will be handled by the RenderEngine. R.id.rounded_corner_top_left,
final Set<Integer> viewsMayNeedColorUpdate = new HashSet<>(); R.id.rounded_corner_top_right,
if (mHwcScreenDecorationSupport == null) { R.id.rounded_corner_bottom_left,
ColorStateList tintList = ColorStateList.valueOf(mTintColor); R.id.rounded_corner_bottom_right
mRoundedCornerResDelegate.setColorTintList(tintList); });
viewsMayNeedColorUpdate.add(R.id.rounded_corner_top_left);
viewsMayNeedColorUpdate.add(R.id.rounded_corner_top_right);
viewsMayNeedColorUpdate.add(R.id.rounded_corner_bottom_left);
viewsMayNeedColorUpdate.add(R.id.rounded_corner_bottom_right);
viewsMayNeedColorUpdate.add(R.id.display_cutout);
}
if (getOverlayView(mFaceScanningViewId) != null) {
viewsMayNeedColorUpdate.add(mFaceScanningViewId);
}
final Integer[] views = new Integer[viewsMayNeedColorUpdate.size()];
viewsMayNeedColorUpdate.toArray(views);
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 (viewsMayNeedColorUpdate.contains(child.getId())
&& child instanceof DisplayCutoutView) {
((DisplayCutoutView) child).setColor(mTintColor);
}
}
mOverlays[i].onReloadResAndMeasure(views, mProviderRefreshToken,
mRotation, mDisplayUniqueId);
}
} }
@VisibleForTesting @VisibleForTesting
@@ -1109,18 +1076,9 @@ 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(); updateOverlayProviderViews(null);
} }
FaceScanningOverlay faceScanningOverlay = FaceScanningOverlay faceScanningOverlay =
@@ -1136,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
@@ -1184,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) {
@@ -1192,7 +1110,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
context.getResources(), context.getDisplay().getUniqueId()); context.getResources(), context.getDisplay().getUniqueId());
} }
private void updateOverlayProviderViews() { private void updateOverlayProviderViews(@Nullable Integer[] filterIds) {
if (mOverlays == null) { if (mOverlays == null) {
return; return;
} }
@@ -1201,7 +1119,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (overlay == null) { if (overlay == null) {
continue; continue;
} }
overlay.onReloadResAndMeasure(null, mProviderRefreshToken, mRotation, mDisplayUniqueId); overlay.onReloadResAndMeasure(filterIds, mProviderRefreshToken, mRotation, mTintColor,
mDisplayUniqueId);
} }
} }
@@ -1240,19 +1159,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
mRoundedCornerResDelegate.setTuningSizeFactor(null); mRoundedCornerResDelegate.setTuningSizeFactor(null);
} }
Integer[] filterIds = { updateOverlayProviderViews(new Integer[] {
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,
R.id.rounded_corner_bottom_right R.id.rounded_corner_bottom_right
}; });
for (final OverlayWindow overlay: mOverlays) {
if (overlay == null) {
continue;
}
overlay.onReloadResAndMeasure(filterIds, mProviderRefreshToken, mRotation,
mDisplayUniqueId);
}
updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerExistAndSize();
}); });
} }
@@ -1306,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));
@@ -1314,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();
@@ -1321,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,8 +32,8 @@ 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() */
abstract val alignedBounds: List<Int> abstract val alignedBounds: List<Int>
@@ -46,25 +46,19 @@ abstract class DecorProvider {
view: View, view: View,
reloadToken: Int, reloadToken: Int,
@Surface.Rotation rotation: Int, @Surface.Rotation rotation: Int,
displayUniqueId: String? = null tintColor: Int,
displayUniqueId: String?
) )
/** Inflate view into parent as current rotation */ /** Inflate view into parent as current rotation */
abstract fun inflateView( abstract fun inflateView(
context: Context, context: Context,
parent: ViewGroup, parent: ViewGroup,
@Surface.Rotation rotation: Int @Surface.Rotation rotation: 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) }
} }
/** /**
@@ -92,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

@@ -115,19 +115,25 @@ class FaceScanningOverlayProviderImpl(
override fun onReloadResAndMeasure( override fun onReloadResAndMeasure(
view: View, view: View,
reloadToken: Int, reloadToken: Int,
rotation: Int, @Surface.Rotation rotation: Int,
tintColor: Int,
displayUniqueId: String? displayUniqueId: String?
) { ) {
(view.layoutParams as FrameLayout.LayoutParams).let { (view.layoutParams as FrameLayout.LayoutParams).let {
updateLayoutParams(it, rotation) updateLayoutParams(it, rotation)
view.layoutParams = it view.layoutParams = it
(view as? FaceScanningOverlay)?.let { overlay ->
overlay.setColor(tintColor)
overlay.onDisplayChanged(displayUniqueId)
}
} }
} }
override fun inflateView( override fun inflateView(
context: Context, context: Context,
parent: ViewGroup, parent: ViewGroup,
@Surface.Rotation rotation: Int @Surface.Rotation rotation: Int,
tintColor: Int
): View { ): View {
val view = FaceScanningOverlay( val view = FaceScanningOverlay(
context, context,
@@ -137,6 +143,7 @@ class FaceScanningOverlayProviderImpl(
mainExecutor mainExecutor
) )
view.id = viewId view.id = viewId
view.setColor(tintColor)
FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT).let { ViewGroup.LayoutParams.MATCH_PARENT).let {
updateLayoutParams(it, rotation) updateLayoutParams(it, rotation)

View File

@@ -34,9 +34,10 @@ class OverlayWindow(private val context: Context) {
fun addDecorProvider( fun addDecorProvider(
decorProvider: DecorProvider, decorProvider: DecorProvider,
@Surface.Rotation rotation: Int @Surface.Rotation rotation: Int,
tintColor: Int
) { ) {
val view = decorProvider.inflateView(context, rootView, rotation) val view = decorProvider.inflateView(context, rootView, rotation, tintColor)
viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider) viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider)
} }
@@ -69,7 +70,7 @@ class OverlayWindow(private val context: Context) {
*/ */
fun hasSameProviders(newProviders: List<DecorProvider>): Boolean { fun hasSameProviders(newProviders: List<DecorProvider>): Boolean {
return (newProviders.size == viewProviderMap.size) && return (newProviders.size == viewProviderMap.size) &&
newProviders.all { getView(it.viewId) != null } newProviders.all { getView(it.viewId) != null }
} }
/** /**
@@ -82,23 +83,28 @@ class OverlayWindow(private val context: Context) {
filterIds: Array<Int>? = null, filterIds: Array<Int>? = null,
reloadToken: Int, reloadToken: Int,
@Surface.Rotation rotation: Int, @Surface.Rotation rotation: Int,
tintColor: Int,
displayUniqueId: String? = null displayUniqueId: String? = null
) { ) {
filterIds?.forEach { id -> filterIds?.forEach { id ->
viewProviderMap[id]?.let { viewProviderMap[id]?.let {
it.second.onReloadResAndMeasure( it.second.onReloadResAndMeasure(
view = it.first, view = it.first,
reloadToken = reloadToken, reloadToken = reloadToken,
displayUniqueId = displayUniqueId, rotation = rotation,
rotation = rotation) tintColor = tintColor,
displayUniqueId = displayUniqueId
)
} }
} ?: run { } ?: run {
viewProviderMap.values.forEach { viewProviderMap.values.forEach {
it.second.onReloadResAndMeasure( it.second.onReloadResAndMeasure(
view = it.first, view = it.first,
reloadToken = reloadToken, reloadToken = reloadToken,
displayUniqueId = displayUniqueId, rotation = rotation,
rotation = rotation) tintColor = tintColor,
displayUniqueId = displayUniqueId
)
} }
} }
} }
@@ -108,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

@@ -20,9 +20,9 @@ import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.view.DisplayCutout import android.view.DisplayCutout
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Surface
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Surface
import com.android.systemui.R import com.android.systemui.R
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
@@ -85,6 +85,7 @@ class PrivacyDotCornerDecorProviderImpl(
view: View, view: View,
reloadToken: Int, reloadToken: Int,
rotation: Int, rotation: Int,
tintColor: Int,
displayUniqueId: String? displayUniqueId: String?
) { ) {
// Do nothing here because it is handled inside PrivacyDotViewController // Do nothing here because it is handled inside PrivacyDotViewController
@@ -93,7 +94,8 @@ class PrivacyDotCornerDecorProviderImpl(
override fun inflateView( override fun inflateView(
context: Context, context: Context,
parent: ViewGroup, parent: ViewGroup,
@Surface.Rotation rotation: Int @Surface.Rotation rotation: Int,
tintColor: Int
): View { ): View {
LayoutInflater.from(context).inflate(layoutId, parent, true) LayoutInflater.from(context).inflate(layoutId, parent, true)
return parent.getChildAt(parent.childCount - 1 /* latest new added child */) return parent.getChildAt(parent.childCount - 1 /* latest new added child */)

View File

@@ -17,6 +17,7 @@
package com.android.systemui.decor package com.android.systemui.decor
import android.content.Context import android.content.Context
import android.content.res.ColorStateList
import android.view.DisplayCutout import android.view.DisplayCutout
import android.view.Gravity import android.view.Gravity
import android.view.Surface import android.view.Surface
@@ -38,12 +39,13 @@ class RoundedCornerDecorProviderImpl(
override fun inflateView( override fun inflateView(
context: Context, context: Context,
parent: ViewGroup, parent: ViewGroup,
@Surface.Rotation rotation: Int @Surface.Rotation rotation: Int,
tintColor: Int
): View { ): View {
return ImageView(context).also { view -> return ImageView(context).also { view ->
// View // View
view.id = viewId view.id = viewId
initView(view, rotation) initView(view, rotation, tintColor)
// LayoutParams // LayoutParams
val layoutSize = if (isTop) { val layoutSize = if (isTop) {
@@ -52,31 +54,36 @@ class RoundedCornerDecorProviderImpl(
roundedCornerResDelegate.bottomRoundedSize roundedCornerResDelegate.bottomRoundedSize
} }
val params = FrameLayout.LayoutParams( val params = FrameLayout.LayoutParams(
layoutSize.width, layoutSize.width,
layoutSize.height, layoutSize.height,
alignedBound1.toLayoutGravity(rotation) or alignedBound1.toLayoutGravity(rotation) or alignedBound2.toLayoutGravity(rotation)
alignedBound2.toLayoutGravity(rotation)) )
// AddView // AddView
parent.addView(view, params) parent.addView(view, params)
} }
} }
private fun initView(view: ImageView, @Surface.Rotation rotation: Int) { private fun initView(
view: ImageView,
@Surface.Rotation rotation: Int,
tintColor: Int
) {
view.setRoundedCornerImage(roundedCornerResDelegate, isTop) view.setRoundedCornerImage(roundedCornerResDelegate, isTop)
view.adjustRotation(alignedBounds, rotation) view.adjustRotation(alignedBounds, rotation)
view.imageTintList = roundedCornerResDelegate.colorTintList view.imageTintList = ColorStateList.valueOf(tintColor)
} }
override fun onReloadResAndMeasure( override fun onReloadResAndMeasure(
view: View, view: View,
reloadToken: Int, reloadToken: Int,
@Surface.Rotation rotation: Int, @Surface.Rotation rotation: Int,
tintColor: Int,
displayUniqueId: String? displayUniqueId: String?
) { ) {
roundedCornerResDelegate.updateDisplayUniqueId(displayUniqueId, reloadToken) roundedCornerResDelegate.updateDisplayUniqueId(displayUniqueId, reloadToken)
initView((view as ImageView), rotation) initView((view as ImageView), rotation, tintColor)
val layoutSize = if (isTop) { val layoutSize = if (isTop) {
roundedCornerResDelegate.topRoundedSize roundedCornerResDelegate.topRoundedSize
@@ -87,7 +94,7 @@ class RoundedCornerDecorProviderImpl(
it.width = layoutSize.width it.width = layoutSize.width
it.height = layoutSize.height it.height = layoutSize.height
it.gravity = alignedBound1.toLayoutGravity(rotation) or it.gravity = alignedBound1.toLayoutGravity(rotation) or
alignedBound2.toLayoutGravity(rotation) alignedBound2.toLayoutGravity(rotation)
view.setLayoutParams(it) view.setLayoutParams(it)
} }
} }
@@ -134,10 +141,10 @@ private fun ImageView.setRoundedCornerImage(
setImageDrawable(drawable) setImageDrawable(drawable)
} else { } else {
setImageResource( setImageResource(
if (isTop) if (isTop)
R.drawable.rounded_corner_top R.drawable.rounded_corner_top
else else
R.drawable.rounded_corner_bottom R.drawable.rounded_corner_bottom
) )
} }
} }

View File

@@ -18,9 +18,7 @@ package com.android.systemui.decor
import android.annotation.ArrayRes import android.annotation.ArrayRes
import android.annotation.DrawableRes import android.annotation.DrawableRes
import android.content.res.ColorStateList
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.DisplayUtils import android.util.DisplayUtils
import android.util.Size import android.util.Size
@@ -57,8 +55,6 @@ class RoundedCornerResDelegate(
var bottomRoundedSize = Size(0, 0) var bottomRoundedSize = Size(0, 0)
private set private set
var colorTintList = ColorStateList.valueOf(Color.BLACK)
var tuningSizeFactor: Int? = null var tuningSizeFactor: Int? = null
set(value) { set(value) {
if (field == value) { if (field == value) {
@@ -107,19 +103,19 @@ class RoundedCornerResDelegate(
val hasDefaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId) > 0 val hasDefaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId) > 0
hasTop = hasDefaultRadius || hasTop = hasDefaultRadius ||
(RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId) > 0) (RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId) > 0)
hasBottom = hasDefaultRadius || hasBottom = hasDefaultRadius ||
(RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId) > 0) (RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId) > 0)
topRoundedDrawable = getDrawable( topRoundedDrawable = getDrawable(
displayConfigIndex = configIdx, displayConfigIndex = configIdx,
arrayResId = R.array.config_roundedCornerTopDrawableArray, arrayResId = R.array.config_roundedCornerTopDrawableArray,
backupDrawableId = R.drawable.rounded_corner_top backupDrawableId = R.drawable.rounded_corner_top
) )
bottomRoundedDrawable = getDrawable( bottomRoundedDrawable = getDrawable(
displayConfigIndex = configIdx, displayConfigIndex = configIdx,
arrayResId = R.array.config_roundedCornerBottomDrawableArray, arrayResId = R.array.config_roundedCornerBottomDrawableArray,
backupDrawableId = R.drawable.rounded_corner_bottom backupDrawableId = R.drawable.rounded_corner_bottom
) )
} }
@@ -147,13 +143,15 @@ class RoundedCornerResDelegate(
if (physicalPixelDisplaySizeRatio != 1f) { if (physicalPixelDisplaySizeRatio != 1f) {
if (topRoundedSize.width != 0) { if (topRoundedSize.width != 0) {
topRoundedSize = Size( topRoundedSize = Size(
(physicalPixelDisplaySizeRatio * topRoundedSize.width + 0.5f).toInt(), (physicalPixelDisplaySizeRatio * topRoundedSize.width + 0.5f).toInt(),
(physicalPixelDisplaySizeRatio * topRoundedSize.height + 0.5f).toInt()) (physicalPixelDisplaySizeRatio * topRoundedSize.height + 0.5f).toInt()
)
} }
if (bottomRoundedSize.width != 0) { if (bottomRoundedSize.width != 0) {
bottomRoundedSize = Size( bottomRoundedSize = Size(
(physicalPixelDisplaySizeRatio * bottomRoundedSize.width + 0.5f).toInt(), (physicalPixelDisplaySizeRatio * bottomRoundedSize.width + 0.5f).toInt(),
(physicalPixelDisplaySizeRatio * bottomRoundedSize.height + 0.5f).toInt()) (physicalPixelDisplaySizeRatio * bottomRoundedSize.height + 0.5f).toInt()
)
} }
} }
} }
@@ -180,8 +178,9 @@ class RoundedCornerResDelegate(
pw.println(" hasTop=$hasTop") pw.println(" hasTop=$hasTop")
pw.println(" hasBottom=$hasBottom") pw.println(" hasBottom=$hasBottom")
pw.println(" topRoundedSize(w,h)=(${topRoundedSize.width},${topRoundedSize.height})") pw.println(" topRoundedSize(w,h)=(${topRoundedSize.width},${topRoundedSize.height})")
pw.println(" bottomRoundedSize(w,h)=(${bottomRoundedSize.width}," + pw.println(
"${bottomRoundedSize.height})") " bottomRoundedSize(w,h)=(${bottomRoundedSize.width},${bottomRoundedSize.height})"
)
pw.println(" physicalPixelDisplaySizeRatio=$physicalPixelDisplaySizeRatio") pw.println(" physicalPixelDisplaySizeRatio=$physicalPixelDisplaySizeRatio")
} }
} }

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();
@@ -1383,39 +1312,36 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.mDisplayListener.onDisplayChanged(1); mScreenDecorations.mDisplayListener.onDisplayChanged(1);
verify(hwcLayer, times(1)).onDisplayChanged(1); verify(hwcLayer, times(1)).onDisplayChanged(any());
} }
@Test @Test
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();
mScreenDecorations.mDisplayListener.onDisplayChanged(1); mScreenDecorations.mDisplayListener.onDisplayChanged(1);
verify(cutoutView, times(1)).onDisplayChanged(1); verify(cutoutView, times(1)).onDisplayChanged(any());
} }
@Test @Test
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])
}
}
}

View File

@@ -16,6 +16,7 @@
package com.android.systemui.decor package com.android.systemui.decor
import android.graphics.Color
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper
import android.view.DisplayCutout import android.view.DisplayCutout
@@ -51,35 +52,45 @@ class OverlayWindowTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
decorProvider1 = spy(PrivacyDotCornerDecorProviderImpl( decorProvider1 = spy(
PrivacyDotCornerDecorProviderImpl(
viewId = TEST_DECOR_VIEW_ID_1, viewId = TEST_DECOR_VIEW_ID_1,
alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
layoutId = R.layout.privacy_dot_top_left)) layoutId = R.layout.privacy_dot_top_left
decorProvider2 = spy(PrivacyDotCornerDecorProviderImpl( )
)
decorProvider2 = spy(
PrivacyDotCornerDecorProviderImpl(
viewId = TEST_DECOR_VIEW_ID_2, viewId = TEST_DECOR_VIEW_ID_2,
alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
layoutId = R.layout.privacy_dot_bottom_left)) layoutId = R.layout.privacy_dot_bottom_left
decorProvider3 = spy(PrivacyDotCornerDecorProviderImpl( )
)
decorProvider3 = spy(
PrivacyDotCornerDecorProviderImpl(
viewId = TEST_DECOR_VIEW_ID_3, viewId = TEST_DECOR_VIEW_ID_3,
alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
layoutId = R.layout.privacy_dot_bottom_right)) layoutId = R.layout.privacy_dot_bottom_right
)
)
overlay = OverlayWindow(mContext) overlay = OverlayWindow(mContext)
} }
@Test @Test
fun testAddProvider() { fun testAddProvider() {
@Surface.Rotation val rotation = Surface.ROTATION_270 @Surface.Rotation val rotation = Surface.ROTATION_270
overlay.addDecorProvider(decorProvider1, rotation) overlay.addDecorProvider(decorProvider1, rotation, Color.BLACK)
overlay.addDecorProvider(decorProvider2, rotation) overlay.addDecorProvider(decorProvider2, rotation, Color.YELLOW)
verify(decorProvider1, times(1)).inflateView( verify(decorProvider1, times(1)).inflateView(
mContext, overlay.rootView, rotation) mContext, overlay.rootView, rotation, Color.BLACK
)
verify(decorProvider2, times(1)).inflateView( verify(decorProvider2, times(1)).inflateView(
mContext, overlay.rootView, rotation) mContext, overlay.rootView, rotation, Color.YELLOW
)
val view1FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1) val view1FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1)
Assert.assertNotNull(view1FoundFromRootView) Assert.assertNotNull(view1FoundFromRootView)
@@ -91,8 +102,8 @@ class OverlayWindowTest : SysuiTestCase() {
@Test @Test
fun testRemoveView() { fun testRemoveView() {
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270, Color.BLACK)
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270, Color.BLACK)
overlay.removeView(TEST_DECOR_VIEW_ID_1) overlay.removeView(TEST_DECOR_VIEW_ID_1)
val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1) val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1)
@@ -102,39 +113,47 @@ class OverlayWindowTest : SysuiTestCase() {
@Test @Test
fun testOnReloadResAndMeasureWithoutIds() { fun testOnReloadResAndMeasureWithoutIds() {
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0, Color.BLACK)
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0, Color.BLACK)
overlay.onReloadResAndMeasure( overlay.onReloadResAndMeasure(
reloadToken = 1, reloadToken = 1,
rotation = Surface.ROTATION_90, rotation = Surface.ROTATION_90,
displayUniqueId = null) tintColor = Color.BLACK,
displayUniqueId = null
)
verify(decorProvider1, times(1)).onReloadResAndMeasure( verify(decorProvider1, times(1)).onReloadResAndMeasure(
overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null) overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, Color.BLACK, null
)
verify(decorProvider2, times(1)).onReloadResAndMeasure( verify(decorProvider2, times(1)).onReloadResAndMeasure(
overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null) overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, Color.BLACK, null
)
} }
@Test @Test
fun testOnReloadResAndMeasureWithIds() { fun testOnReloadResAndMeasureWithIds() {
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0, Color.BLACK)
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0, Color.BLACK)
overlay.onReloadResAndMeasure( overlay.onReloadResAndMeasure(
filterIds = arrayOf(TEST_DECOR_VIEW_ID_2), filterIds = arrayOf(TEST_DECOR_VIEW_ID_2),
reloadToken = 1, reloadToken = 1,
rotation = Surface.ROTATION_90, rotation = Surface.ROTATION_90,
displayUniqueId = null) tintColor = Color.BLACK,
displayUniqueId = null
)
verify(decorProvider1, never()).onReloadResAndMeasure( verify(decorProvider1, never()).onReloadResAndMeasure(
overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null) overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, Color.BLACK, null
)
verify(decorProvider2, times(1)).onReloadResAndMeasure( verify(decorProvider2, times(1)).onReloadResAndMeasure(
overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null) overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, Color.BLACK, null
)
} }
@Test @Test
fun testRemoveRedundantViewsWithNullParameter() { fun testRemoveRedundantViewsWithNullParameter() {
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270, Color.BLACK)
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270, Color.BLACK)
overlay.removeRedundantViews(null) overlay.removeRedundantViews(null)
@@ -146,13 +165,15 @@ class OverlayWindowTest : SysuiTestCase() {
@Test @Test
fun testRemoveRedundantViewsWith2Providers() { fun testRemoveRedundantViewsWith2Providers() {
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270, Color.BLACK)
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270, Color.BLACK)
overlay.removeRedundantViews(IntArray(2).apply { overlay.removeRedundantViews(
this[0] = TEST_DECOR_VIEW_ID_3 IntArray(2).apply {
this[1] = TEST_DECOR_VIEW_ID_1 this[0] = TEST_DECOR_VIEW_ID_3
}) this[1] = TEST_DECOR_VIEW_ID_1
}
)
Assert.assertNotNull(overlay.getView(TEST_DECOR_VIEW_ID_1)) Assert.assertNotNull(overlay.getView(TEST_DECOR_VIEW_ID_1))
Assert.assertNotNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_1)) Assert.assertNotNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_1))
@@ -167,13 +188,13 @@ class OverlayWindowTest : SysuiTestCase() {
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1)))
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0, Color.BLACK)
Assert.assertFalse(overlay.hasSameProviders(emptyList())) Assert.assertFalse(overlay.hasSameProviders(emptyList()))
Assert.assertTrue(overlay.hasSameProviders(listOf(decorProvider1))) Assert.assertTrue(overlay.hasSameProviders(listOf(decorProvider1)))
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1)))
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0) overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0, Color.BLACK)
Assert.assertFalse(overlay.hasSameProviders(emptyList())) Assert.assertFalse(overlay.hasSameProviders(emptyList()))
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider1))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider1)))
Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2))) Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))