Merge "Fix cutout flicker while switch screen resolution" into tm-dev am: 842704d45a

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

Change-Id: If3cfedc1b10402ad2dd4eb610c5944f304d579fe
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Shawn Lin
2022-05-12 07:05:30 +00:00
committed by Automerger Merge Worker
3 changed files with 77 additions and 30 deletions

View File

@@ -54,7 +54,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@JvmField val displayInfo = DisplayInfo() @JvmField val displayInfo = DisplayInfo()
@JvmField protected var pendingRotationChange = false @JvmField protected var pendingConfigChange = false
@JvmField protected val paint = Paint() @JvmField protected val paint = Paint()
@JvmField protected val cutoutPath = Path() @JvmField protected val cutoutPath = Path()
@@ -145,7 +145,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
open fun updateCutout() { open fun updateCutout() {
if (pendingRotationChange) { if (pendingConfigChange) {
return return
} }
cutoutPath.reset() cutoutPath.reset()
@@ -225,7 +225,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
} }
protected open fun updateProtectionBoundingPath() { protected open fun updateProtectionBoundingPath() {
if (pendingRotationChange) { if (pendingConfigChange) {
return return
} }
val m = Matrix() val m = Matrix()

View File

@@ -53,6 +53,7 @@ import android.provider.Settings.Secure;
import android.util.DisplayUtils; import android.util.DisplayUtils;
import android.util.Log; import android.util.Log;
import android.util.Size; import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout; import android.view.DisplayCutout;
import android.view.DisplayCutout.BoundsPosition; import android.view.DisplayCutout.BoundsPosition;
import android.view.DisplayInfo; import android.view.DisplayInfo;
@@ -151,12 +152,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
private SettingObserver mColorInversionSetting; private SettingObserver mColorInversionSetting;
private DelayableExecutor mExecutor; private DelayableExecutor mExecutor;
private Handler mHandler; private Handler mHandler;
boolean mPendingRotationChange; boolean mPendingConfigChange;
@VisibleForTesting @VisibleForTesting
String mDisplayUniqueId; String mDisplayUniqueId;
private int mTintColor = Color.BLACK; private int mTintColor = Color.BLACK;
@VisibleForTesting @VisibleForTesting
protected DisplayDecorationSupport mHwcScreenDecorationSupport; protected DisplayDecorationSupport mHwcScreenDecorationSupport;
private Display.Mode mDisplayMode;
private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback = private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
new CameraAvailabilityListener.CameraTransitionCallback() { new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -324,6 +326,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mWindowManager = mContext.getSystemService(WindowManager.class); mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class);
mRotation = mContext.getDisplay().getRotation(); mRotation = mContext.getDisplay().getRotation();
mDisplayMode = mContext.getDisplay().getMode();
mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mDisplayUniqueId = mContext.getDisplay().getUniqueId();
mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(), mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
mDisplayUniqueId); mDisplayUniqueId);
@@ -349,8 +352,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
@Override @Override
public void onDisplayChanged(int displayId) { public void onDisplayChanged(int displayId) {
final int newRotation = mContext.getDisplay().getRotation(); final int newRotation = mContext.getDisplay().getRotation();
final Display.Mode newDisplayMode = mContext.getDisplay().getMode();
if ((mOverlays != null || mScreenDecorHwcWindow != null) if ((mOverlays != null || mScreenDecorHwcWindow != null)
&& mRotation != newRotation) { && (mRotation != newRotation
|| displayModeChanged(mDisplayMode, newDisplayMode))) {
// We cannot immediately update the orientation. Otherwise // We cannot immediately update the orientation. Otherwise
// WindowManager is still deferring layout until it has finished dispatching // WindowManager is still deferring layout until it has finished dispatching
// the config changes, which may cause divergence between what we draw // the config changes, which may cause divergence between what we draw
@@ -358,10 +363,16 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
// Instead we wait until either: // Instead we wait until either:
// - we are trying to redraw. This because WM resized our window and told us to. // - we are trying to redraw. This because WM resized our window and told us to.
// - the config change has been dispatched, so WM is no longer deferring layout. // - the config change has been dispatched, so WM is no longer deferring layout.
mPendingRotationChange = true; mPendingConfigChange = true;
if (DEBUG) { if (DEBUG) {
Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " if (mRotation != newRotation) {
+ mRotation); Log.i(TAG, "Rotation changed, deferring " + newRotation
+ ", staying at " + mRotation);
}
if (displayModeChanged(mDisplayMode, newDisplayMode)) {
Log.i(TAG, "Resolution changed, deferring " + newDisplayMode
+ ", staying at " + mDisplayMode);
}
} }
if (mOverlays != null) { if (mOverlays != null) {
@@ -369,7 +380,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (mOverlays[i] != null) { if (mOverlays[i] != null) {
final ViewGroup overlayView = mOverlays[i].getRootView(); final ViewGroup overlayView = mOverlays[i].getRootView();
overlayView.getViewTreeObserver().addOnPreDrawListener( overlayView.getViewTreeObserver().addOnPreDrawListener(
new RestartingPreDrawListener(overlayView, i, newRotation)); new RestartingPreDrawListener(
overlayView, i, newRotation, newDisplayMode));
} }
} }
} }
@@ -379,7 +391,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
new RestartingPreDrawListener( new RestartingPreDrawListener(
mScreenDecorHwcWindow, mScreenDecorHwcWindow,
-1, // Pass -1 for views with no specific position. -1, // Pass -1 for views with no specific position.
newRotation)); newRotation, newDisplayMode));
}
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.pendingConfigChange = true;
} }
} }
@@ -435,7 +450,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}; };
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
updateOrientation(); updateConfiguration();
} }
@Nullable @Nullable
@@ -807,6 +822,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
} }
private static boolean displayModeChanged(Display.Mode oldMode, Display.Mode newMode) {
if (oldMode == null) {
return true;
}
// 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
return oldMode.getPhysicalWidth() != newMode.getPhysicalWidth()
|| oldMode.getPhysicalHeight() != newMode.getPhysicalHeight();
}
private int getOverlayWindowGravity(@BoundsPosition int pos) { private int getOverlayWindowGravity(@BoundsPosition int pos) {
final int rotated = getBoundPositionFromRotation(pos, mRotation); final int rotated = getBoundPositionFromRotation(pos, mRotation);
switch (rotated) { switch (rotated) {
@@ -913,8 +939,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mExecutor.execute(() -> { mExecutor.execute(() -> {
int oldRotation = mRotation; int oldRotation = mRotation;
mPendingRotationChange = false; mPendingConfigChange = false;
updateOrientation(); updateConfiguration();
if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation); if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
setupDecorations(); setupDecorations();
if (mOverlays != null) { if (mOverlays != null) {
@@ -941,7 +967,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
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(" isOnlyPrivacyDotInSwLayer:" + isOnlyPrivacyDotInSwLayer());
pw.println(" mPendingRotationChange:" + mPendingRotationChange); pw.println(" mPendingConfigChange:" + mPendingConfigChange);
if (mHwcScreenDecorationSupport != null) { if (mHwcScreenDecorationSupport != null) {
pw.println(" mHwcScreenDecorationSupport:"); pw.println(" mHwcScreenDecorationSupport:");
pw.println(" format=" pw.println(" format="
@@ -973,7 +999,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mRoundedCornerResDelegate.dump(pw, args); mRoundedCornerResDelegate.dump(pw, args);
} }
private void updateOrientation() { private void updateConfiguration() {
Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(), Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
"must call on " + mHandler.getLooper().getThread() "must call on " + mHandler.getLooper().getThread()
+ ", but was " + Thread.currentThread()); + ", but was " + Thread.currentThread());
@@ -982,11 +1008,14 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (mRotation != newRotation) { if (mRotation != newRotation) {
mDotViewController.setNewRotation(newRotation); mDotViewController.setNewRotation(newRotation);
} }
final Display.Mode newMod = mContext.getDisplay().getMode();
if (!mPendingRotationChange && newRotation != mRotation) { if (!mPendingConfigChange
&& (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) {
mRotation = newRotation; mRotation = newRotation;
mDisplayMode = newMod;
if (mScreenDecorHwcLayer != null) { if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.pendingRotationChange = false; mScreenDecorHwcLayer.pendingConfigChange = false;
mScreenDecorHwcLayer.updateRotation(mRotation); mScreenDecorHwcLayer.updateRotation(mRotation);
updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerExistAndSize();
updateHwLayerRoundedCornerDrawable(); updateHwLayerRoundedCornerDrawable();
@@ -1197,7 +1226,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@Override @Override
public void updateCutout() { public void updateCutout() {
if (!isAttachedToWindow() || pendingRotationChange) { if (!isAttachedToWindow() || pendingConfigChange) {
return; return;
} }
mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation); mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation);
@@ -1338,40 +1367,47 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
private final View mView; private final View mView;
private final int mTargetRotation; private final int mTargetRotation;
private final Display.Mode mTargetDisplayMode;
// Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific // Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific
// position. // position.
private final int mPosition; private final int mPosition;
private RestartingPreDrawListener(View view, @BoundsPosition int position, private RestartingPreDrawListener(View view, @BoundsPosition int position,
int targetRotation) { int targetRotation, Display.Mode targetDisplayMode) {
mView = view; mView = view;
mTargetRotation = targetRotation; mTargetRotation = targetRotation;
mTargetDisplayMode = targetDisplayMode;
mPosition = position; mPosition = position;
} }
@Override @Override
public boolean onPreDraw() { public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this); mView.getViewTreeObserver().removeOnPreDrawListener(this);
if (mTargetRotation == mRotation
if (mTargetRotation == mRotation) { && !displayModeChanged(mDisplayMode, mTargetDisplayMode)) {
if (DEBUG) { if (DEBUG) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer" final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition); : getWindowTitleByPos(mPosition);
Log.i(TAG, title + " already in target rot " Log.i(TAG, title + " already in target rot "
+ mTargetRotation + ", allow draw without restarting it"); + mTargetRotation + " and in target resolution "
+ mTargetDisplayMode.getPhysicalWidth() + "x"
+ mTargetDisplayMode.getPhysicalHeight()
+ ", allow draw without restarting it");
} }
return true; return true;
} }
mPendingRotationChange = false; mPendingConfigChange = false;
// This changes the window attributes - we need to restart the traversal for them to // This changes the window attributes - we need to restart the traversal for them to
// take effect. // take effect.
updateOrientation(); updateConfiguration();
if (DEBUG) { if (DEBUG) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer" final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition); : getWindowTitleByPos(mPosition);
Log.i(TAG, title Log.i(TAG, title
+ " restarting listener fired, restarting draw for rot " + mRotation); + " restarting listener fired, restarting draw for rot " + mRotation
+ ", resolution " + mDisplayMode.getPhysicalWidth() + "x"
+ mDisplayMode.getPhysicalHeight());
} }
mView.invalidate(); mView.invalidate();
return false; return false;
@@ -1379,8 +1415,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} }
/** /**
* A pre-draw listener, that validates that the rotation we draw in matches the displays * A pre-draw listener, that validates that the rotation and display resolution we draw in
* rotation before continuing the draw. * matches the display's rotation and resolution before continuing the draw.
* *
* This is to prevent a race condition, where we have not received the display changed event * This is to prevent a race condition, where we have not received the display changed event
* yet, and would thus draw in an old orientation. * yet, and would thus draw in an old orientation.
@@ -1396,10 +1432,20 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
@Override @Override
public boolean onPreDraw() { public boolean onPreDraw() {
final int displayRotation = mContext.getDisplay().getRotation(); final int displayRotation = mContext.getDisplay().getRotation();
if (displayRotation != mRotation && !mPendingRotationChange) { final Display.Mode displayMode = mContext.getDisplay().getMode();
if (displayRotation != mRotation && displayModeChanged(mDisplayMode, displayMode)
&& !mPendingConfigChange) {
if (DEBUG) { if (DEBUG) {
Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot " if (displayRotation != mRotation) {
+ displayRotation + ". Restarting draw"); Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ displayRotation + ". Restarting draw");
}
if (displayModeChanged(mDisplayMode, displayMode)) {
Log.i(TAG, "Drawing at " + mDisplayMode.getPhysicalWidth()
+ "x" + mDisplayMode.getPhysicalHeight() + ", but display is at "
+ displayMode.getPhysicalWidth() + "x"
+ displayMode.getPhysicalHeight() + ". Restarting draw");
}
} }
mView.invalidate(); mView.invalidate();
return false; return false;

View File

@@ -159,6 +159,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
when(mContext.getDisplay()).thenReturn(mDisplay); when(mContext.getDisplay()).thenReturn(mDisplay);
// Not support hwc layer by default // Not support hwc layer by default
doReturn(null).when(mDisplay).getDisplayDecorationSupport(); doReturn(null).when(mDisplay).getDisplayDecorationSupport();
doReturn(mDisplayMode).when(mDisplay).getMode();
when(mMockTypedArray.length()).thenReturn(0); when(mMockTypedArray.length()).thenReturn(0);
mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl( mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(