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
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class CutoutDecorProviderImpl(
|
||||
(view as? DisplayCutoutView)?.let { cutoutView ->
|
||||
cutoutView.setColor(tintColor)
|
||||
cutoutView.updateRotation(rotation)
|
||||
cutoutView.onDisplayChanged(displayUniqueId)
|
||||
cutoutView.updateConfiguration(displayUniqueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ class FaceScanningOverlayProviderImpl(
|
||||
view.layoutParams = it
|
||||
(view as? FaceScanningOverlay)?.let { overlay ->
|
||||
overlay.setColor(tintColor)
|
||||
overlay.onDisplayChanged(displayUniqueId)
|
||||
overlay.updateConfiguration(displayUniqueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user