From 5b6bc36c6692faf2e4cfe2b6b3c48abf2ff5c44c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 17 Oct 2022 16:01:09 +0800 Subject: [PATCH] Reland - Fix flicker when swiching resolution change After the "Local Layout"[1] is enabled, the client can compute its layout on its own. If we update cutout in the Display callback(server side), it would have a timing issue that we draw the cutout(latest from server) in the old layout(not being updated yet in client) which would cause flicker. We should only update cutout in client side callback like configuration change to make sure it syncs with the current layout attributes in client side. For rounded corner part, we don't need to reload drawable everytime the config is changed. Only size update is needed. For face unlock animation placed in wrong position, update the rotation whenever the config is changed. [1]:If9488ffc84dc5e2af106acfae425a854fb7407a2 Bug: 228284551 Bug: 244693677 Test: 1. Go Settings-> Display-> Screen resolution 2. Switch between FHD <-> QHD and no flickering Test: atest ScreenDecorationsTest RoundedCornerResDelegateTest DisplayCutoutBaseViewTest Change-Id: Ia601d126ff7f5de01f4e5e659c62009233a66eb8 --- .../android/systemui/DisplayCutoutBaseView.kt | 30 ++++++---- .../android/systemui/ScreenDecorations.java | 39 ++----------- .../systemui/decor/CutoutDecorProviderImpl.kt | 2 +- .../decor/FaceScanningProviderFactory.kt | 2 +- .../decor/RoundedCornerResDelegate.kt | 17 ++---- .../systemui/ScreenDecorationsTest.java | 58 ++----------------- .../decor/RoundedCornerResDelegateTest.kt | 12 ++-- 7 files changed, 41 insertions(+), 119 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt index a3351e1a64400..5d52056d8b170 100644 --- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt +++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt @@ -86,30 +86,38 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { onUpdate() } - fun onDisplayChanged(newDisplayUniqueId: String?) { + fun updateConfiguration(newDisplayUniqueId: String?) { + val info = DisplayInfo() + context.display?.getDisplayInfo(info) val oldMode: Display.Mode? = displayMode - val display: Display? = context.display - displayMode = display?.mode + displayMode = info.mode - if (displayUniqueId != display?.uniqueId) { - displayUniqueId = display?.uniqueId - shouldDrawCutout = DisplayCutout.getFillBuiltInDisplayCutout( - context.resources, displayUniqueId - ) - } + updateDisplayUniqueId(info.uniqueId) // Skip if display mode or cutout hasn't changed. if (!displayModeChanged(oldMode, displayMode) && - display?.cutout == displayInfo.displayCutout) { + displayInfo.displayCutout == info.displayCutout && + displayRotation == info.rotation) { return } - if (newDisplayUniqueId == display?.uniqueId) { + if (newDisplayUniqueId == info.uniqueId) { + displayRotation = info.rotation updateCutout() updateProtectionBoundingPath() onUpdate() } } + open fun updateDisplayUniqueId(newDisplayUniqueId: String?) { + if (displayUniqueId != newDisplayUniqueId) { + displayUniqueId = newDisplayUniqueId + shouldDrawCutout = DisplayCutout.getFillBuiltInDisplayCutout( + context.resources, displayUniqueId + ) + invalidate() + } + } + open fun updateRotation(rotation: Int) { displayRotation = rotation updateCutout() diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 2e13903814a5e..632e11a16f849 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -455,7 +455,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } - boolean needToUpdateProviderViews = false; final String newUniqueId = mDisplayInfo.uniqueId; if (!Objects.equals(newUniqueId, mDisplayUniqueId)) { mDisplayUniqueId = newUniqueId; @@ -473,37 +472,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab setupDecorations(); return; } - - if (mScreenDecorHwcLayer != null) { - updateHwLayerRoundedCornerDrawable(); - updateHwLayerRoundedCornerExistAndSize(); - } - needToUpdateProviderViews = true; - } - - final float newRatio = getPhysicalPixelDisplaySizeRatio(); - if (mRoundedCornerResDelegate.getPhysicalPixelDisplaySizeRatio() != newRatio) { - mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(newRatio); - if (mScreenDecorHwcLayer != null) { - updateHwLayerRoundedCornerExistAndSize(); - } - needToUpdateProviderViews = true; - } - - if (needToUpdateProviderViews) { - updateOverlayProviderViews(null); - } else { - updateOverlayProviderViews(new Integer[] { - mFaceScanningViewId, - R.id.display_cutout, - R.id.display_cutout_left, - R.id.display_cutout_right, - R.id.display_cutout_bottom, - }); - } - - if (mScreenDecorHwcLayer != null) { - mScreenDecorHwcLayer.onDisplayChanged(newUniqueId); } } }; @@ -1069,9 +1037,11 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) { mRotation = newRotation; mDisplayMode = newMod; + mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio( + getPhysicalPixelDisplaySizeRatio()); if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingConfigChange = false; - mScreenDecorHwcLayer.updateRotation(mRotation); + mScreenDecorHwcLayer.updateConfiguration(mDisplayUniqueId); updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerDrawable(); } @@ -1110,7 +1080,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab context.getResources(), context.getDisplay().getUniqueId()); } - private void updateOverlayProviderViews(@Nullable Integer[] filterIds) { + @VisibleForTesting + void updateOverlayProviderViews(@Nullable Integer[] filterIds) { if (mOverlays == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt index 991b54e8035ea..ded0fb79cd6fe 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt @@ -59,7 +59,7 @@ class CutoutDecorProviderImpl( (view as? DisplayCutoutView)?.let { cutoutView -> cutoutView.setColor(tintColor) cutoutView.updateRotation(rotation) - cutoutView.onDisplayChanged(displayUniqueId) + cutoutView.updateConfiguration(displayUniqueId) } } } diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt index ec0013bb50006..5fdd198c19d76 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt @@ -124,7 +124,7 @@ class FaceScanningOverlayProviderImpl( view.layoutParams = it (view as? FaceScanningOverlay)?.let { overlay -> overlay.setColor(tintColor) - overlay.onDisplayChanged(displayUniqueId) + overlay.updateConfiguration(displayUniqueId) } } } diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt index a252864383876..8b4aeefb6ed43 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt @@ -78,23 +78,18 @@ class RoundedCornerResDelegate( reloadMeasures() } - private fun reloadAll(newReloadToken: Int) { - if (reloadToken == newReloadToken) { - return - } - reloadToken = newReloadToken - reloadRes() - reloadMeasures() - } - fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) { if (displayUniqueId != newDisplayUniqueId) { displayUniqueId = newDisplayUniqueId newReloadToken ?.let { reloadToken = it } reloadRes() reloadMeasures() - } else { - newReloadToken?.let { reloadAll(it) } + } else if (newReloadToken != null) { + if (reloadToken == newReloadToken) { + return + } + reloadToken = newReloadToken + reloadMeasures() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index df10dfe9f1603..e363f1744836e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -36,6 +36,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -255,6 +256,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { }); mScreenDecorations.mDisplayInfo = mDisplayInfo; doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio(); + doNothing().when(mScreenDecorations).updateOverlayProviderViews(any()); reset(mTunerService); try { @@ -1005,18 +1007,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertEquals(new Size(3, 3), resDelegate.getTopRoundedSize()); assertEquals(new Size(4, 4), resDelegate.getBottomRoundedSize()); - setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, - getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) - /* roundedTopDrawable */, - getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) - /* roundedBottomDrawable */, - 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/); + doReturn(2f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio(); mDisplayInfo.rotation = Surface.ROTATION_270; mScreenDecorations.onConfigurationChanged(null); - assertEquals(new Size(4, 4), resDelegate.getTopRoundedSize()); - assertEquals(new Size(5, 5), resDelegate.getBottomRoundedSize()); + assertEquals(new Size(6, 6), resDelegate.getTopRoundedSize()); + assertEquals(new Size(8, 8), resDelegate.getBottomRoundedSize()); } @Test @@ -1292,51 +1289,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyFaceScanningViewExists(true); } - @Test - public void testOnDisplayChanged_hwcLayer() { - setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, - null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); - final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); - decorationSupport.format = PixelFormat.R_8; - doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); - - // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); - - mScreenDecorations.start(); - - final ScreenDecorHwcLayer hwcLayer = mScreenDecorations.mScreenDecorHwcLayer; - spyOn(hwcLayer); - doReturn(mDisplay).when(hwcLayer).getDisplay(); - - mScreenDecorations.mDisplayListener.onDisplayChanged(1); - - verify(hwcLayer, times(1)).onDisplayChanged(any()); - } - - @Test - public void testOnDisplayChanged_nonHwcLayer() { - setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, - null /* roundedTopDrawable */, null /* roundedBottomDrawable */, - 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); - - // top cutout - mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); - - mScreenDecorations.start(); - - final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView) - mScreenDecorations.getOverlayView(R.id.display_cutout); - assertNotNull(cutoutView); - spyOn(cutoutView); - doReturn(mDisplay).when(cutoutView).getDisplay(); - - mScreenDecorations.mDisplayListener.onDisplayChanged(1); - - verify(cutoutView, times(1)).onDisplayChanged(any()); - } - @Test public void testHasSameProvidersWithNullOverlays() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt index f93336134900c..93a1868b72f51 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt @@ -24,12 +24,11 @@ import androidx.annotation.DrawableRes import androidx.test.filters.SmallTest import com.android.internal.R as InternalR import com.android.systemui.R as SystemUIR -import com.android.systemui.tests.R import com.android.systemui.SysuiTestCase +import com.android.systemui.tests.R import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test - import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations @@ -102,14 +101,11 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize) assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize) - setupResources(radius = 100, - roundedTopDrawable = getTestsDrawable(R.drawable.rounded4px), - roundedBottomDrawable = getTestsDrawable(R.drawable.rounded5px)) - + roundedCornerResDelegate.physicalPixelDisplaySizeRatio = 2f roundedCornerResDelegate.updateDisplayUniqueId(null, 1) - assertEquals(Size(4, 4), roundedCornerResDelegate.topRoundedSize) - assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize) + assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize) + assertEquals(Size(8, 8), roundedCornerResDelegate.bottomRoundedSize) } @Test