Loading services/core/java/com/android/server/wm/ActivityRecord.java +0 −1 Original line number Diff line number Diff line Loading @@ -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; } } Loading services/core/java/com/android/server/wm/FadeRotationAnimationController.java +53 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading services/core/java/com/android/server/wm/WindowContainer.java +5 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading services/core/java/com/android/server/wm/WindowState.java +22 −15 Original line number Diff line number Diff line Loading @@ -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() { Loading services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +8 −1 Original line number Diff line number Diff line Loading @@ -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()); } Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +0 −1 Original line number Diff line number Diff line Loading @@ -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; } } Loading
services/core/java/com/android/server/wm/FadeRotationAnimationController.java +53 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading
services/core/java/com/android/server/wm/WindowContainer.java +5 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading
services/core/java/com/android/server/wm/WindowState.java +22 −15 Original line number Diff line number Diff line Loading @@ -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() { Loading
services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +8 −1 Original line number Diff line number Diff line Loading @@ -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()); } Loading