Loading services/core/java/com/android/server/wm/ActivityRecord.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -6337,7 +6337,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } } else if (w.isDrawn()) { } else if (w.isDrawn()) { // The starting window for this container is drawn. // The starting window for this container is drawn. mTaskSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this); startingDisplayed = true; startingDisplayed = true; } } } } Loading services/core/java/com/android/server/wm/FadeRotationAnimationController.java +53 −9 Original line number Original line 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. */ /** The list to store the drawn tokens before the rotation animation starts. */ private ArrayList<WindowToken> mPendingShowTokens; 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 int mOriginalRotation; private final boolean mHasScreenRotationAnimation; private final boolean mHasScreenRotationAnimation; Loading Loading @@ -110,16 +115,36 @@ public class FadeRotationAnimationController extends FadeAnimationController { mTargetWindowTokens.put(w.mToken, null); mTargetWindowTokens.put(w.mToken, null); } } }, true /* traverseTopToBottom */); }, 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 @Override public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { if (show) { if (show) { final SurfaceControl leash = mTargetWindowTokens.remove(windowToken); // The previous animation leash will be dropped when preparing fade-in animation, so if (leash != null && mRotator != null) { // simply remove it without restoring the transformation. // The leash was unrotated by start transaction of transition. Clear the transform mTargetWindowTokens.remove(windowToken); // to reshow the window in current rotation. if (mCapturedDrawTransactions != null) { mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash); // 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); 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 // 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 // fade out in previous rotation while display has rotated to the new rotation, so // their leashes are unrotated with the start transaction. // their leashes are unrotated with the start transaction. mRotator = new SeamlessRotator(mOriginalRotation, final SeamlessRotator rotator = new SeamlessRotator(mOriginalRotation, mDisplayContent.getWindowConfiguration().getRotation(), mDisplayContent.getWindowConfiguration().getRotation(), mDisplayContent.getDisplayInfo(), mDisplayContent.getDisplayInfo(), false /* applyFixedTransformationHint */); false /* applyFixedTransformationHint */); for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { final SurfaceControl leash = mTargetWindowTokens.valueAt(i); final SurfaceControl leash = mTargetWindowTokens.valueAt(i); if (leash != null) { if (leash != null) { mRotator.applyTransform(t, leash); rotator.applyTransform(t, leash); } } } } return; 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 @Override public Animation getFadeInAnimation() { public Animation getFadeInAnimation() { if (mHasScreenRotationAnimation) { if (mHasScreenRotationAnimation) { Loading services/core/java/com/android/server/wm/WindowContainer.java +5 −1 Original line number Original line 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) { for (int i = mChildren.size() - 1; i >= 0; --i) { mChildren.get(i).finishSync(outMergedTransaction, cancel); mChildren.get(i).finishSync(outMergedTransaction, cancel); } } mSyncState = SYNC_STATE_NONE; if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); clearSyncState(); } void clearSyncState() { mSyncState = SYNC_STATE_NONE; mSyncGroup = null; mSyncGroup = null; } } Loading services/core/java/com/android/server/wm/WindowState.java +22 −15 Original line number Original line 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"); Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms"); mActivityRecord.mRelaunchStartTime = 0; mActivityRecord.mRelaunchStartTime = 0; } } if (mActivityRecord != null && mAttrs.type == TYPE_APPLICATION_STARTING) { 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) { mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger() mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger() .notifyStartingWindowDrawn(mActivityRecord); .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); 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. // We always want to force a traversal after a finish draw for blast sync. return true; return !skipLayout && (hasSyncHandlers || layoutNeeded); } } void immediatelyNotifyBlastSync() { void immediatelyNotifyBlastSync() { Loading services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +8 −1 Original line number Original line 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 // 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. // 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(); 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()); assertNull(mDisplayContent.getFadeRotationAnimationController()); } } Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -6337,7 +6337,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } } else if (w.isDrawn()) { } else if (w.isDrawn()) { // The starting window for this container is drawn. // The starting window for this container is drawn. mTaskSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this); startingDisplayed = true; startingDisplayed = true; } } } } Loading
services/core/java/com/android/server/wm/FadeRotationAnimationController.java +53 −9 Original line number Original line 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. */ /** The list to store the drawn tokens before the rotation animation starts. */ private ArrayList<WindowToken> mPendingShowTokens; 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 int mOriginalRotation; private final boolean mHasScreenRotationAnimation; private final boolean mHasScreenRotationAnimation; Loading Loading @@ -110,16 +115,36 @@ public class FadeRotationAnimationController extends FadeAnimationController { mTargetWindowTokens.put(w.mToken, null); mTargetWindowTokens.put(w.mToken, null); } } }, true /* traverseTopToBottom */); }, 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 @Override public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { if (show) { if (show) { final SurfaceControl leash = mTargetWindowTokens.remove(windowToken); // The previous animation leash will be dropped when preparing fade-in animation, so if (leash != null && mRotator != null) { // simply remove it without restoring the transformation. // The leash was unrotated by start transaction of transition. Clear the transform mTargetWindowTokens.remove(windowToken); // to reshow the window in current rotation. if (mCapturedDrawTransactions != null) { mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash); // 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); 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 // 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 // fade out in previous rotation while display has rotated to the new rotation, so // their leashes are unrotated with the start transaction. // their leashes are unrotated with the start transaction. mRotator = new SeamlessRotator(mOriginalRotation, final SeamlessRotator rotator = new SeamlessRotator(mOriginalRotation, mDisplayContent.getWindowConfiguration().getRotation(), mDisplayContent.getWindowConfiguration().getRotation(), mDisplayContent.getDisplayInfo(), mDisplayContent.getDisplayInfo(), false /* applyFixedTransformationHint */); false /* applyFixedTransformationHint */); for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { final SurfaceControl leash = mTargetWindowTokens.valueAt(i); final SurfaceControl leash = mTargetWindowTokens.valueAt(i); if (leash != null) { if (leash != null) { mRotator.applyTransform(t, leash); rotator.applyTransform(t, leash); } } } } return; 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 @Override public Animation getFadeInAnimation() { public Animation getFadeInAnimation() { if (mHasScreenRotationAnimation) { if (mHasScreenRotationAnimation) { Loading
services/core/java/com/android/server/wm/WindowContainer.java +5 −1 Original line number Original line 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) { for (int i = mChildren.size() - 1; i >= 0; --i) { mChildren.get(i).finishSync(outMergedTransaction, cancel); mChildren.get(i).finishSync(outMergedTransaction, cancel); } } mSyncState = SYNC_STATE_NONE; if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); clearSyncState(); } void clearSyncState() { mSyncState = SYNC_STATE_NONE; mSyncGroup = null; mSyncGroup = null; } } Loading
services/core/java/com/android/server/wm/WindowState.java +22 −15 Original line number Original line 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"); Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms"); mActivityRecord.mRelaunchStartTime = 0; mActivityRecord.mRelaunchStartTime = 0; } } if (mActivityRecord != null && mAttrs.type == TYPE_APPLICATION_STARTING) { 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) { mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger() mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger() .notifyStartingWindowDrawn(mActivityRecord); .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); 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. // We always want to force a traversal after a finish draw for blast sync. return true; return !skipLayout && (hasSyncHandlers || layoutNeeded); } } void immediatelyNotifyBlastSync() { void immediatelyNotifyBlastSync() { Loading
services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +8 −1 Original line number Original line 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 // 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. // 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(); 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()); assertNull(mDisplayContent.getFadeRotationAnimationController()); } } Loading