Merge "Synchronize rotating non-app windows with fade animation"

This commit is contained in:
Riddle Hsu
2022-01-03 06:14:05 +00:00
committed by Android (Google) Code Review
5 changed files with 88 additions and 27 deletions

View File

@@ -6337,7 +6337,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
} else if (w.isDrawn()) {
// The starting window for this container is drawn.
mTaskSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
}
}

View File

@@ -59,8 +59,13 @@ public class FadeRotationAnimationController extends FadeAnimationController {
/** The list to store the drawn tokens before the rotation animation starts. */
private ArrayList<WindowToken> mPendingShowTokens;
/** It is used when the display has rotated, but some windows fade out in old rotation. */
private SeamlessRotator mRotator;
/**
* The sync transactions of the target windows. It is used when the display has rotated but
* the windows need to fade out in previous rotation. These transactions will be applied with
* fade-in animation, so there won't be a flickering such as the windows have redrawn during
* fading out.
*/
private ArrayMap<WindowState, SurfaceControl.Transaction> mCapturedDrawTransactions;
private final int mOriginalRotation;
private final boolean mHasScreenRotationAnimation;
@@ -110,16 +115,36 @@ public class FadeRotationAnimationController extends FadeAnimationController {
mTargetWindowTokens.put(w.mToken, null);
}
}, true /* traverseTopToBottom */);
// The transition sync group may be finished earlier because it doesn't wait for these
// target windows. But the windows still need to use sync transaction to keep the appearance
// in previous rotation, so request a no-op sync to keep the state.
if (!mIsChangeTransition && transitionType != WindowManager.TRANSIT_NONE) {
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
final WindowToken token = mTargetWindowTokens.keyAt(i);
for (int j = token.getChildCount() - 1; j >= 0; j--) {
token.getChildAt(j).applyWithNextDraw(t -> {});
}
}
}
}
@Override
public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
if (show) {
final SurfaceControl leash = mTargetWindowTokens.remove(windowToken);
if (leash != null && mRotator != null) {
// The leash was unrotated by start transaction of transition. Clear the transform
// to reshow the window in current rotation.
mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash);
// The previous animation leash will be dropped when preparing fade-in animation, so
// simply remove it without restoring the transformation.
mTargetWindowTokens.remove(windowToken);
if (mCapturedDrawTransactions != null) {
// Unblock the window to draw its latest content with fade-in animation.
final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
for (int i = windowToken.getChildCount() - 1; i >= 0; i--) {
final SurfaceControl.Transaction drawT =
mCapturedDrawTransactions.remove(windowToken.getChildAt(i));
if (drawT != null) {
t.merge(drawT);
}
}
}
}
super.fadeWindowToken(show, windowToken, animationType);
@@ -225,14 +250,14 @@ public class FadeRotationAnimationController extends FadeAnimationController {
// Take OPEN/CLOSE transition type as the example, the non-activity windows need to
// fade out in previous rotation while display has rotated to the new rotation, so
// their leashes are unrotated with the start transaction.
mRotator = new SeamlessRotator(mOriginalRotation,
final SeamlessRotator rotator = new SeamlessRotator(mOriginalRotation,
mDisplayContent.getWindowConfiguration().getRotation(),
mDisplayContent.getDisplayInfo(),
false /* applyFixedTransformationHint */);
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
if (leash != null) {
mRotator.applyTransform(t, leash);
rotator.applyTransform(t, leash);
}
}
return;
@@ -280,6 +305,25 @@ public class FadeRotationAnimationController extends FadeAnimationController {
}
}
/** Captures the post draw transaction if the window should update with fade-in animation. */
boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) {
if (mIsChangeTransition || !isTargetToken(w.mToken)) return false;
if (postDrawTransaction != null && w.mTransitionController.inTransition()) {
if (mCapturedDrawTransactions == null) {
mCapturedDrawTransactions = new ArrayMap<>();
}
final SurfaceControl.Transaction t = mCapturedDrawTransactions.get(w);
if (t == null) {
mCapturedDrawTransactions.put(w, postDrawTransaction);
} else {
t.merge(postDrawTransaction);
}
return true;
}
mDisplayContent.finishFadeRotationAnimation(w.mToken);
return false;
}
@Override
public Animation getFadeInAnimation() {
if (mHasScreenRotationAnimation) {

View File

@@ -3354,8 +3354,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
for (int i = mChildren.size() - 1; i >= 0; --i) {
mChildren.get(i).finishSync(outMergedTransaction, cancel);
}
mSyncState = SYNC_STATE_NONE;
if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);
clearSyncState();
}
void clearSyncState() {
mSyncState = SYNC_STATE_NONE;
mSyncGroup = null;
}

View File

@@ -5747,29 +5747,36 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");
mActivityRecord.mRelaunchStartTime = 0;
}
executeDrawHandlers(postDrawTransaction);
final boolean applyPostDrawNow = mClientWasDrawingForSync && postDrawTransaction != null;
mClientWasDrawingForSync = false;
if (!onSyncFinishedDrawing()) {
return mWinAnimator.finishDrawingLocked(postDrawTransaction, applyPostDrawNow);
}
if (mActivityRecord != null
&& mTransitionController.isShellTransitionsEnabled()
&& mAttrs.type == TYPE_APPLICATION_STARTING) {
if (mActivityRecord != null && mAttrs.type == TYPE_APPLICATION_STARTING) {
mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger()
.notifyStartingWindowDrawn(mActivityRecord);
}
if (postDrawTransaction != null) {
final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction);
boolean skipLayout = false;
// Control the timing to switch the appearance of window with different rotations.
final FadeRotationAnimationController fadeRotationController =
mDisplayContent.getFadeRotationAnimationController();
if (fadeRotationController != null
&& fadeRotationController.handleFinishDrawing(this, postDrawTransaction)) {
// Consume the transaction because the controller will apply it with fade animation.
// Layout is not needed because the window will be hidden by the fade leash. Clear
// sync state because its sync transaction doesn't need to be merged to sync group.
postDrawTransaction = null;
skipLayout = true;
clearSyncState();
} else if (onSyncFinishedDrawing() && postDrawTransaction != null) {
mSyncTransaction.merge(postDrawTransaction);
// Consume the transaction because the sync group will merge it.
postDrawTransaction = null;
}
mWinAnimator.finishDrawingLocked(null, false /* forceApplyNow */);
final boolean layoutNeeded =
mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
mClientWasDrawingForSync = false;
// We always want to force a traversal after a finish draw for blast sync.
return true;
return !skipLayout && (hasSyncHandlers || layoutNeeded);
}
void immediatelyNotifyBlastSync() {

View File

@@ -556,8 +556,15 @@ public class TransitionTests extends WindowTestsBase {
// The redrawn window will be faded in when the transition finishes. And because this test
// only use one non-activity window, the fade rotation controller should also be cleared.
statusBar.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
final SurfaceControl.Transaction postDrawTransaction =
mock(SurfaceControl.Transaction.class);
final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
assertFalse(layoutNeeded);
player.finish();
// The controller should capture the draw transaction and merge it when preparing to run
// fade-in animation.
verify(mDisplayContent.getPendingTransaction()).merge(eq(postDrawTransaction));
assertNull(mDisplayContent.getFadeRotationAnimationController());
}