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
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 e643170..670e246 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 @@
} 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 1344788..f61d88b 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 @@
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 f314b21..7e267e4 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.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 @@
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 @@
} 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 d1bd06f..232b817 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 @@
// 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();