From 88f50dbc5bdba2dd54d7a9a90f384aae33278267 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Sat, 25 Mar 2023 01:41:25 +0800 Subject: [PATCH] Use blast sync for changing screen resolution Windows with PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY will be put on top layer and by default it is excluded from screenshot. So before the animation starts, their drawn result should not be shown immediately. In other words, make them sync with the start of animation. Also - Fix typo for scale of resolution change animation. - Clear blast sync timeout from draw handler because Navbar may remove and add again while InsetsSourceProvider called applyWithNextDraw for it. Bug: 273874648 Test: Change screen resolution in settings. The cutout won't be flickering. Change-Id: I5c56ee362fe915e16870b4c15c958e19f0504abe --- .../transition/ScreenRotationAnimation.java | 2 +- .../com/android/server/wm/DisplayContent.java | 9 +++++- .../server/wm/TransitionController.java | 30 +++++++++++++++---- .../com/android/server/wm/WindowState.java | 3 ++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java index e643170273dee..670e2467e2e19 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java @@ -230,7 +230,7 @@ class ScreenRotationAnimation { } else if ((mEndWidth > mStartWidth) == (mEndHeight > mStartHeight) && (mEndWidth != mStartWidth || mEndHeight != mStartHeight)) { // Display resizes without rotation change. - final float scale = Math.max((float) mEndWidth / mStartHeight, + final float scale = Math.max((float) mEndWidth / mStartWidth, (float) mEndHeight / mStartHeight); matrix.setScale(scale, scale); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1344788d0314e..f61d88b82fd2e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1567,7 +1567,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (configChanged) { mWaitingForConfig = true; if (mTransitionController.isShellTransitionsEnabled()) { - requestChangeTransitionIfNeeded(changes, null /* displayChange */); + final TransitionRequestInfo.DisplayChange change = + mTransitionController.isCollecting() + ? null : new TransitionRequestInfo.DisplayChange(mDisplayId); + if (change != null) { + change.setStartAbsBounds(currentDisplayConfig.windowConfiguration.getBounds()); + change.setEndAbsBounds(mTmpConfiguration.windowConfiguration.getBounds()); + } + requestChangeTransitionIfNeeded(changes, change); } else if (mLastHasContent) { mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this); } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index f314b21a0d726..7e267e47ede30 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IApplicationThread; import android.app.WindowConfiguration; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; @@ -465,6 +466,28 @@ class TransitionController { return type == TRANSIT_OPEN || type == TRANSIT_CLOSE; } + /** Whether the display change should run with blast sync. */ + private static boolean shouldSync(@NonNull TransitionRequestInfo.DisplayChange displayChange) { + if ((displayChange.getStartRotation() + displayChange.getEndRotation()) % 2 == 0) { + // 180 degrees rotation change may not change screen size. So the clients may draw + // some frames before and after the display projection transaction is applied by the + // remote player. That may cause some buffers to show in different rotation. So use + // sync method to pause clients drawing until the projection transaction is applied. + return true; + } + final Rect startBounds = displayChange.getStartAbsBounds(); + final Rect endBounds = displayChange.getEndAbsBounds(); + if (startBounds == null || endBounds == null) return false; + final int startWidth = startBounds.width(); + final int startHeight = startBounds.height(); + final int endWidth = endBounds.width(); + final int endHeight = endBounds.height(); + // This is changing screen resolution. Because the screen decor layers are excluded from + // screenshot, their draw transactions need to run with the start transaction. + return (endWidth > startWidth) == (endHeight > startHeight) + && (endWidth != startWidth || endHeight != startHeight); + } + /** * If a transition isn't requested yet, creates one and asks the TransitionPlayer (Shell) to * start it. Collection can start immediately. @@ -494,12 +517,7 @@ class TransitionController { } else { newTransition = requestStartTransition(createTransition(type, flags), trigger != null ? trigger.asTask() : null, remoteTransition, displayChange); - if (newTransition != null && displayChange != null && (displayChange.getStartRotation() - + displayChange.getEndRotation()) % 2 == 0) { - // 180 degrees rotation change may not change screen size. So the clients may draw - // some frames before and after the display projection transaction is applied by the - // remote player. That may cause some buffers to show in different rotation. So use - // sync method to pause clients drawing until the projection transaction is applied. + if (newTransition != null && displayChange != null && shouldSync(displayChange)) { mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(), BLASTSyncEngine.METHOD_BLAST); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d1bd06f7fa99c..232b817b83140 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2343,6 +2343,9 @@ class WindowState extends WindowContainer implements WindowManagerP // to be removed before the parent (so that the sync-engine tracking works). Since // WindowStateAnimator is a "virtual" child, we have to do it manually here. mWinAnimator.destroySurfaceLocked(getSyncTransaction()); + if (!mDrawHandlers.isEmpty()) { + mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); + } super.removeImmediately(); final DisplayContent dc = getDisplayContent();