Merge "Auto show-hide overlay window if only privacy dot" into tm-dev am: 32d70dbe1a am: df23d3faa2

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

Change-Id: I6f230fbbdec8f26440208fc181ec58844ca44deb
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2022-04-09 07:06:00 +00:00
committed by Automerger Merge Worker
3 changed files with 263 additions and 110 deletions

View File

@@ -200,48 +200,44 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
}; };
private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener = @VisibleForTesting
PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener =
new PrivacyDotViewController.ShowingListener() { new PrivacyDotViewController.ShowingListener() {
@Override @Override
public void onPrivacyDotShown(@Nullable View v) { public void onPrivacyDotShown(@Nullable View v) {
// We don't need to control the window visibility when the hwc doesn't support screen setOverlayWindowVisibilityIfViewExist(v, View.VISIBLE);
// decoration since the overlay windows are always visible in this case.
if (mHwcScreenDecorationSupport == null || v == null) {
return;
}
mExecutor.execute(() -> {
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (mOverlays[i] == null) {
continue;
}
final ViewGroup overlayView = mOverlays[i].getRootView();
if (overlayView.findViewById(v.getId()) != null) {
overlayView.setVisibility(View.VISIBLE);
}
}
});
} }
@Override @Override
public void onPrivacyDotHidden(@Nullable View v) { public void onPrivacyDotHidden(@Nullable View v) {
// We don't need to control the window visibility when the hwc doesn't support screen setOverlayWindowVisibilityIfViewExist(v, View.INVISIBLE);
// decoration since the overlay windows are always visible in this case. }
if (mHwcScreenDecorationSupport == null || v == null) { };
@VisibleForTesting
protected void setOverlayWindowVisibilityIfViewExist(@Nullable View view,
@View.Visibility int visibility) {
if (view == null) {
return; return;
} }
mExecutor.execute(() -> { mExecutor.execute(() -> {
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { // We don't need to control the window visibility if rounded corners or cutout is drawn
if (mOverlays[i] == null) { // on sw layer since the overlay windows are always visible in this case.
if (mOverlays == null || !isOnlyPrivacyDotInSwLayer()) {
return;
}
for (final OverlayWindow overlay : mOverlays) {
if (overlay == null) {
continue; continue;
} }
final ViewGroup overlayView = mOverlays[i].getRootView(); if (overlay.getView(view.getId()) != null) {
if (overlayView.findViewById(v.getId()) != null) { overlay.getRootView().setVisibility(visibility);
overlayView.setVisibility(View.INVISIBLE); return;
} }
} }
}); });
} }
};
private static boolean eq(DisplayDecorationSupport a, DisplayDecorationSupport b) { private static boolean eq(DisplayDecorationSupport a, DisplayDecorationSupport b) {
if (a == null) return (b == null); if (a == null) return (b == null);
@@ -268,7 +264,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mDotViewController = dotViewController; mDotViewController = dotViewController;
mThreadFactory = threadFactory; mThreadFactory = threadFactory;
mDotFactory = dotFactory; mDotFactory = dotFactory;
dotViewController.setShowingListener(mPrivacyDotShowingListener);
} }
@Override @Override
@@ -425,18 +420,24 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
removeHwcOverlay(); removeHwcOverlay();
} }
final DisplayCutout cutout = getCutout(); final DisplayCutout cutout = getCutout();
final boolean isOnlyPrivacyDotInSwLayer = isOnlyPrivacyDotInSwLayer();
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout) if (shouldShowSwLayerCutout(i, cutout) || shouldShowSwLayerRoundedCorner(i, cutout)
|| shouldShowPrivacyDot(i, cutout)) { || shouldShowSwLayerPrivacyDot(i, cutout)) {
Pair<List<DecorProvider>, List<DecorProvider>> pair = Pair<List<DecorProvider>, List<DecorProvider>> pair =
DecorProviderKt.partitionAlignedBound(decorProviders, i); DecorProviderKt.partitionAlignedBound(decorProviders, i);
decorProviders = pair.getSecond(); decorProviders = pair.getSecond();
createOverlay(i, cutout, pair.getFirst()); createOverlay(i, cutout, pair.getFirst(), isOnlyPrivacyDotInSwLayer);
} else { } else {
removeOverlay(i); removeOverlay(i);
} }
} }
if (isOnlyPrivacyDotInSwLayer) {
mDotViewController.setShowingListener(mPrivacyDotShowingListener);
} else {
mDotViewController.setShowingListener(null);
}
final View tl, tr, bl, br; final View tl, tr, bl, br;
if ((tl = getOverlayView(R.id.privacy_dot_top_left_container)) != null if ((tl = getOverlayView(R.id.privacy_dot_top_left_container)) != null
&& (tr = getOverlayView(R.id.privacy_dot_top_right_container)) != null && (tr = getOverlayView(R.id.privacy_dot_top_right_container)) != null
@@ -530,19 +531,51 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mOverlays[pos] = null; mOverlays[pos] = null;
} }
@View.Visibility
private int getWindowVisibility(@NonNull OverlayWindow overlay,
boolean isOnlyPrivacyDotInSwLayer) {
if (!isOnlyPrivacyDotInSwLayer) {
// Multiple views inside overlay, no need to optimize
return View.VISIBLE;
}
int[] ids = {
R.id.privacy_dot_top_left_container,
R.id.privacy_dot_top_right_container,
R.id.privacy_dot_bottom_left_container,
R.id.privacy_dot_bottom_right_container
};
for (int id: ids) {
final View view = overlay.getView(id);
if (view != null && view.getVisibility() == View.VISIBLE) {
// Only privacy dot in sw layers, overlay shall be VISIBLE if one of privacy dot
// views inside this overlay is VISIBLE
return View.VISIBLE;
}
}
// Only privacy dot in sw layers, overlay shall be INVISIBLE like default if no privacy dot
// view inside this overlay is VISIBLE.
return View.INVISIBLE;
}
private void createOverlay( private void createOverlay(
@BoundsPosition int pos, @BoundsPosition int pos,
@Nullable DisplayCutout cutout, @Nullable DisplayCutout cutout,
@NonNull List<DecorProvider> decorProviders) { @NonNull List<DecorProvider> decorProviders,
boolean isOnlyPrivacyDotInSwLayer) {
if (mOverlays == null) { if (mOverlays == null) {
mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH]; mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH];
} }
if (mOverlays[pos] != null) { if (mOverlays[pos] != null) {
// When mOverlay[pos] is not null and only privacy dot in sw layer, use privacy dot
// view's visibility
mOverlays[pos].getRootView().setVisibility(
getWindowVisibility(mOverlays[pos], isOnlyPrivacyDotInSwLayer));
return; return;
} }
mOverlays[pos] = overlayForPosition(pos, decorProviders); mOverlays[pos] = overlayForPosition(pos, decorProviders, isOnlyPrivacyDotInSwLayer);
final ViewGroup overlayView = mOverlays[pos].getRootView(); final ViewGroup overlayView = mOverlays[pos].getRootView();
overlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); overlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
overlayView.setAlpha(0); overlayView.setAlpha(0);
@@ -612,18 +645,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
*/ */
private OverlayWindow overlayForPosition( private OverlayWindow overlayForPosition(
@BoundsPosition int pos, @BoundsPosition int pos,
@NonNull List<DecorProvider> decorProviders) { @NonNull List<DecorProvider> decorProviders,
boolean isOnlyPrivacyDotInSwLayer) {
final OverlayWindow currentOverlay = new OverlayWindow(LayoutInflater.from(mContext), pos); final OverlayWindow currentOverlay = new OverlayWindow(LayoutInflater.from(mContext), pos);
decorProviders.forEach(provider -> { decorProviders.forEach(provider -> {
removeOverlayView(provider.getViewId()); removeOverlayView(provider.getViewId());
currentOverlay.addDecorProvider(provider, mRotation); currentOverlay.addDecorProvider(provider, mRotation);
// If the hwc supports screen decoration and privacy dot is enabled, it means there will });
// be only privacy dot in mOverlay. So set the initial visibility of mOverlays to // When only privacy dot in mOverlay, set the initial visibility of mOverlays to
// INVISIBLE and will only set it to VISIBLE when the privacy dot is showing. // INVISIBLE and set it to VISIBLE when the privacy dot is showing.
if (mHwcScreenDecorationSupport != null) { if (isOnlyPrivacyDotInSwLayer) {
currentOverlay.getRootView().setVisibility(View.INVISIBLE); currentOverlay.getRootView().setVisibility(View.INVISIBLE);
} }
});
return currentOverlay; return currentOverlay;
} }
@@ -842,6 +875,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
pw.println("ScreenDecorations state:"); pw.println("ScreenDecorations state:");
pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS); pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS);
pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled()); pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
pw.println(" isOnlyPrivacyDotInSwLayer:" + isOnlyPrivacyDotInSwLayer());
pw.println(" mPendingRotationChange:" + mPendingRotationChange); pw.println(" mPendingRotationChange:" + mPendingRotationChange);
if (mHwcScreenDecorationSupport != null) { if (mHwcScreenDecorationSupport != null) {
pw.println(" mHwcScreenDecorationSupport:"); pw.println(" mHwcScreenDecorationSupport:");
@@ -923,7 +957,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return; return;
} }
rounded.setVisibility(View.GONE); rounded.setVisibility(View.GONE);
if (shouldShowRoundedCorner(pos, cutout)) { if (shouldShowSwLayerRoundedCorner(pos, cutout)) {
final int gravity = getRoundedCornerGravity(pos, id == R.id.left); final int gravity = getRoundedCornerGravity(pos, id == R.id.left);
((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity; ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity;
setRoundedCornerOrientation(rounded, gravity); setRoundedCornerOrientation(rounded, gravity);
@@ -997,23 +1031,32 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
} }
private boolean shouldShowRoundedCorner(@BoundsPosition int pos, private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos,
@Nullable DisplayCutout cutout) { @Nullable DisplayCutout cutout) {
return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout) return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
&& mHwcScreenDecorationSupport == null; && mHwcScreenDecorationSupport == null;
} }
private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos,
@Nullable DisplayCutout cutout) {
return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout); return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout);
} }
private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { private boolean shouldShowSwLayerCutout(@BoundsPosition int pos,
@Nullable DisplayCutout cutout) {
final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
return (bounds != null && !bounds[rotatedPos].isEmpty() return (bounds != null && !bounds[rotatedPos].isEmpty()
&& mHwcScreenDecorationSupport == null); && mHwcScreenDecorationSupport == null);
} }
private boolean isOnlyPrivacyDotInSwLayer() {
return isPrivacyDotEnabled()
&& (mHwcScreenDecorationSupport != null
|| (!hasRoundedCorners() && !shouldDrawCutout())
);
}
private boolean shouldDrawCutout() { private boolean shouldDrawCutout() {
return shouldDrawCutout(mContext); return shouldDrawCutout(mContext);
} }

View File

@@ -134,7 +134,7 @@ class PrivacyDotViewController @Inject constructor(
uiExecutor = e uiExecutor = e
} }
fun setShowingListener(l: ShowingListener) { fun setShowingListener(l: ShowingListener?) {
showingListener = l showingListener = l
} }
@@ -573,7 +573,7 @@ class PrivacyDotViewController @Inject constructor(
} }
} }
public interface ShowingListener { interface ShowingListener {
fun onPrivacyDotShown(v: View?) fun onPrivacyDotShown(v: View?)
fun onPrivacyDotHidden(v: View?) fun onPrivacyDotHidden(v: View?)
} }

View File

@@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
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;
@@ -127,6 +128,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
private CornerDecorProvider mPrivacyDotBottomRightDecorProvider; private CornerDecorProvider mPrivacyDotBottomRightDecorProvider;
@Mock @Mock
private Display.Mode mDisplayMode; private Display.Mode mDisplayMode;
private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
@Before @Before
public void setup() { public void setup() {
@@ -195,10 +197,24 @@ public class ScreenDecorationsTest extends SysuiTestCase {
super.onTuningChanged(key, newValue); super.onTuningChanged(key, newValue);
mExecutor.runAllReady(); mExecutor.runAllReady();
} }
@Override
protected void setOverlayWindowVisibilityIfViewExist(@Nullable View view,
@View.Visibility int visibility) {
super.setOverlayWindowVisibilityIfViewExist(view, visibility);
mExecutor.runAllReady();
}
}); });
reset(mTunerService); reset(mTunerService);
}
try {
mPrivacyDotShowingListener = mScreenDecorations.mPrivacyDotShowingListener.getClass()
.getDeclaredConstructor(ScreenDecorations.class)
.newInstance(mScreenDecorations);
} catch (Exception e) {
fail(e.getMessage());
}
}
private void verifyRoundedCornerViewsVisibility( private void verifyRoundedCornerViewsVisibility(
@DisplayCutout.BoundsPosition final int overlayId, @DisplayCutout.BoundsPosition final int overlayId,
@@ -277,43 +293,59 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verifyBottomDotViewsVisibility(visibility); verifyBottomDotViewsVisibility(visibility);
} }
private void verifyOverlaysExistAndAdded(final boolean left, final boolean top, private void verifyOverlaysExistAndAdded(boolean left, boolean top, boolean right,
final boolean right, final boolean bottom) { boolean bottom, @Nullable Integer visibilityIfExist) {
if (left || top || right || bottom) { if (left || top || right || bottom) {
assertNotNull(mScreenDecorations.mOverlays); assertNotNull(mScreenDecorations.mOverlays);
} else { } else {
verify(mWindowManager, never()).addView(any(), any()); assertNull(mScreenDecorations.mOverlays);
return; return;
} }
if (left) { if (left) {
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT];
assertNotNull(overlay);
verify(mWindowManager, times(1)).addView( verify(mWindowManager, times(1)).addView(
eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()), any()); eq(overlay.getRootView()), any());
if (visibilityIfExist != null) {
assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
}
} else { } else {
assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]);
} }
if (top) { if (top) {
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP];
assertNotNull(overlay);
verify(mWindowManager, times(1)).addView( verify(mWindowManager, times(1)).addView(
eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()), any()); eq(overlay.getRootView()), any());
if (visibilityIfExist != null) {
assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
}
} else { } else {
assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]);
} }
if (right) { if (right) {
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT];
assertNotNull(overlay);
verify(mWindowManager, times(1)).addView( verify(mWindowManager, times(1)).addView(
eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()), any()); eq(overlay.getRootView()), any());
if (visibilityIfExist != null) {
assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
}
} else { } else {
assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]);
} }
if (bottom) { if (bottom) {
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM];
assertNotNull(overlay);
verify(mWindowManager, times(1)).addView( verify(mWindowManager, times(1)).addView(
eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()), any()); eq(overlay.getRootView()), any());
if (visibilityIfExist != null) {
assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
}
} else { } else {
assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
} }
@@ -330,7 +362,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// No views added. // No views added.
verifyOverlaysExistAndAdded(false, false, false, false); verifyOverlaysExistAndAdded(false, false, false, false, null);
// No Tuners tuned. // No Tuners tuned.
verify(mTunerService, never()).addTunable(any(), any()); verify(mTunerService, never()).addTunable(any(), any());
// No dot controller init // No dot controller init
@@ -348,9 +380,12 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// Top and bottom windows are created for privacy dot. // Top and bottom windows are created with INVISIBLE because of privacy dot only
// Left and right window should be null. // Left and right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(
mScreenDecorations.mPrivacyDotShowingListener);
// Rounded corner views shall not exist // Rounded corner views shall not exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
@@ -379,7 +414,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Top and bottom windows are created for rounded corners. // Top and bottom windows are created for rounded corners.
// Left and right window should be null. // Left and right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -407,7 +442,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Top and bottom windows are created for rounded corners. // Top and bottom windows are created for rounded corners.
// Left and right window should be null. // Left and right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -522,7 +559,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// Top and bottom windows are created for rounded corners. // Top and bottom windows are created for rounded corners.
// Left and right window should be null. // Left and right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -556,7 +593,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// Top and bottom windows are created for rounded corners. // Top and bottom windows are created for rounded corners.
// Left and right window should be null. // Left and right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -591,7 +630,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// Top window is created for top cutout. // Top window is created for top cutout.
// Bottom, left, or right window should be null. // Bottom, left, or right window should be null.
verifyOverlaysExistAndAdded(false, true, false, false); verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
// Privacy dots shall not exist because of no privacy // Privacy dots shall not exist because of no privacy
verifyDotViewsNullable(true); verifyDotViewsNullable(true);
@@ -615,7 +654,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Top window is created for top cutout. // Top window is created for top cutout.
// Bottom window is created for privacy dot. // Bottom window is created for privacy dot.
// Left or right window should be null. // Left or right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
// Top rounded corner views shall exist because of cutout // Top rounded corner views shall exist because of cutout
// but be gone because of no rounded corner // but be gone because of no rounded corner
@@ -646,7 +687,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
// Left window is created for left cutout. // Left window is created for left cutout.
// Bottom, top, or right window should be null. // Bottom, top, or right window should be null.
verifyOverlaysExistAndAdded(true, false, false, false); verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
// Left rounded corner views shall exist because of cutout // Left rounded corner views shall exist because of cutout
// but be gone because of no rounded corner // but be gone because of no rounded corner
@@ -674,7 +715,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Left window is created for left cutout. // Left window is created for left cutout.
// Right window is created for privacy. // Right window is created for privacy.
// Bottom, or top window should be null. // Bottom, or top window should be null.
verifyOverlaysExistAndAdded(true, false, true, false); verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
// Privacy dots shall exist but invisible // Privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE); verifyDotViewsVisibility(View.INVISIBLE);
@@ -699,7 +742,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
// Bottom window is created for rounded corner. // Bottom window is created for rounded corner.
// Left, or right window should be null. // Left, or right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -727,7 +770,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Top window is created for rounded corner and top cutout. // Top window is created for rounded corner and top cutout.
// Bottom window is created for rounded corner. // Bottom window is created for rounded corner.
// Left, or right window should be null. // Left, or right window should be null.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist // Rounded corner views shall exist
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
@@ -756,7 +801,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Left window is created for rounded corner and left cutout. // Left window is created for rounded corner and left cutout.
// Right window is created for rounded corner. // Right window is created for rounded corner.
// Top, or bottom window should be null. // Top, or bottom window should be null.
verifyOverlaysExistAndAdded(true, false, true, false); verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
} }
@Test @Test
@@ -774,7 +819,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Left window is created for rounded corner, left cutout, and privacy. // Left window is created for rounded corner, left cutout, and privacy.
// Right window is created for rounded corner and privacy dot. // Right window is created for rounded corner and privacy dot.
// Top, or bottom window should be null. // Top, or bottom window should be null.
verifyOverlaysExistAndAdded(true, false, true, false); verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
} }
@Test @Test
@@ -793,7 +840,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Bottom window is created for rounded corner. // Bottom window is created for rounded corner.
// Left window is created for left cutout. // Left window is created for left cutout.
// Right window should be null. // Right window should be null.
verifyOverlaysExistAndAdded(true, true, false, true); verifyOverlaysExistAndAdded(true, true, false, true, View.VISIBLE);
} }
@Test @Test
@@ -812,7 +859,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Bottom window is created for rounded corner. // Bottom window is created for rounded corner.
// Left window is created for left cutout. // Left window is created for left cutout.
// Right window should be null. // Right window should be null.
verifyOverlaysExistAndAdded(true, true, false, true); verifyOverlaysExistAndAdded(true, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
} }
@Test @Test
@@ -827,7 +876,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, false); 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}; final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
@@ -835,7 +884,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, false, false); verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
} }
@Test @Test
@@ -850,7 +899,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
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}; final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
@@ -858,7 +909,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, true, false); verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
verify(mDotViewController, times(2)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(2)).setShowingListener(null);
// Verify each privacy dot id appears only once // Verify each privacy dot id appears only once
mDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> { mDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
@@ -889,7 +942,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
assertNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, false, false, false, null);
when(mContext.getResources().getBoolean( when(mContext.getResources().getBoolean(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
@@ -897,7 +950,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
// Only top windows should be added. // Only top windows should be added.
verifyOverlaysExistAndAdded(false, true, false, false); verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
} }
@Test @Test
@@ -912,23 +965,27 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout(); .when(mScreenDecorations).getCutout();
mScreenDecorations.start(); mScreenDecorations.start();
// Both top and bottom windows should be added because of privacy dot, // Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
// but their visibility shall be gone because of no rounding. // but rounded corners visibility shall be gone because of no rounding.
verifyOverlaysExistAndAdded(false, true, false, true); verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(
mScreenDecorations.mPrivacyDotShowingListener);
when(mContext.getResources().getBoolean( when(mContext.getResources().getBoolean(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
.thenReturn(true); .thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration()); mScreenDecorations.onConfigurationChanged(new Configuration());
assertNotNull(mScreenDecorations.mOverlays); // Both top and bottom windows should be added with VISIBLE because of privacy dot and
// Both top and bottom windows should be added because of privacy dot, // cutout, but rounded corners visibility shall be gone because of no rounding.
// but their visibility shall be gone because of no rounding. verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
verifyOverlaysExistAndAdded(false, true, false, true);
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
verify(mDotViewController, times(2)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
} }
@Test @Test
@@ -1043,9 +1100,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
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
assertNull(mScreenDecorations.mScreenDecorHwcWindow); assertNull(mScreenDecorations.mScreenDecorHwcWindow);
assertNotNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]);
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8; decorationSupport.format = PixelFormat.R_8;
@@ -1056,7 +1111,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// should only inflate hwc layer when the hwc supports screen decoration // should only inflate hwc layer when the hwc supports screen decoration
assertNotNull(mScreenDecorations.mScreenDecorHwcWindow); assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
assertNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, false, false, false, null);
} }
@Test @Test
@@ -1076,7 +1131,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
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
assertNotNull(mScreenDecorations.mScreenDecorHwcWindow); assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
assertNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, false, false, false, null);
doReturn(null).when(mDisplay).getDisplayDecorationSupport(); doReturn(null).when(mDisplay).getDisplayDecorationSupport();
// Trigger the support hwc screen decoration change by changing the display unique id // Trigger the support hwc screen decoration change by changing the display unique id
@@ -1085,9 +1140,66 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// should only inflate mOverlays when the hwc doesn't support screen decoration // should only inflate mOverlays when the hwc doesn't support screen decoration
assertNull(mScreenDecorations.mScreenDecorHwcWindow); assertNull(mScreenDecorations.mScreenDecorHwcWindow);
assertNotNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); }
assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
@Test
public void testPrivacyDotShowingListenerWorkWellWithNullParameter() {
mPrivacyDotShowingListener.onPrivacyDotShown(null);
mPrivacyDotShowingListener.onPrivacyDotHidden(null);
}
@Test
public void testAutoShowHideOverlayWindowWhenSupportHwcLayer() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
0 /* roundedPadding */, false /* multipleRadius */,
true /* fillCutout */, true /* privacyDot */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
.when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
// Make sure view found and window visibility changed as well
final View view = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
.findViewById(R.id.privacy_dot_bottom_right_container);
mPrivacyDotShowingListener.onPrivacyDotShown(view);
assertEquals(View.VISIBLE,
mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
mPrivacyDotShowingListener.onPrivacyDotHidden(view);
assertEquals(View.INVISIBLE,
mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
}
@Test
public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
0 /* roundedPadding */, false /* multipleRadius */,
false /* fillCutout */, true /* privacyDot */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
// Make sure view found and window visibility changed as well
final View view = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
.findViewById(R.id.privacy_dot_bottom_right_container);
mPrivacyDotShowingListener.onPrivacyDotShown(view);
assertEquals(View.VISIBLE,
mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
mPrivacyDotShowingListener.onPrivacyDotHidden(view);
assertEquals(View.INVISIBLE,
mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
} }
@Test @Test
@@ -1108,7 +1220,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Should only inflate hwc layer. // Should only inflate hwc layer.
assertNotNull(mScreenDecorations.mScreenDecorHwcWindow); assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
assertNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, false, false, false, null);
} }
@Test @Test
@@ -1128,13 +1240,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start(); mScreenDecorations.start();
assertNotNull(mScreenDecorations.mScreenDecorHwcWindow); assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
// mOverlays are inflated but the visibility should be GONE. // mOverlays are inflated but the visibility should be INVISIBLE.
assertNotNull(mScreenDecorations.mOverlays); verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
final View topOverlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView(); verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
final View botOverlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView(); verify(mDotViewController, times(1)).setShowingListener(
assertEquals(topOverlay.getVisibility(), View.INVISIBLE); mScreenDecorations.mPrivacyDotShowingListener);
assertEquals(botOverlay.getVisibility(), View.INVISIBLE);
} }
@Test @Test