Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +5 −2 Original line number Diff line number Diff line Loading @@ -348,12 +348,13 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final boolean isTask = change.getTaskInfo() != null; boolean isSeamlessDisplayChange = false; if (change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { if (info.getType() == TRANSIT_CHANGE) { boolean isSeamless = isRotationSeamless(info, mDisplayController); isSeamlessDisplayChange = isRotationSeamless(info, mDisplayController); final int anim = getRotationAnimation(info); if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) { if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) { mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession, mTransactionPool, startTransaction, change, info.getRootLeash(), anim); Loading Loading @@ -387,6 +388,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { startTransaction.setPosition(change.getLeash(), change.getEndAbsBounds().left - info.getRootOffset().x, change.getEndAbsBounds().top - info.getRootOffset().y); // Seamless display transition doesn't need to animate. if (isSeamlessDisplayChange) continue; if (isTask) { // Skip non-tasks since those usually have null bounds. startTransaction.setWindowCrop(change.getLeash(), Loading services/core/java/com/android/server/wm/AsyncRotationController.java +32 −17 Original line number Diff line number Diff line Loading @@ -94,6 +94,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume /** Whether the start transaction of the transition is committed (by shell). */ private boolean mIsStartTransactionCommitted; /** Whether the target windows have been requested to sync their draw transactions. */ private boolean mIsSyncDrawRequested; private SeamlessRotator mRotator; private final int mOriginalRotation; Loading Loading @@ -139,22 +142,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume displayContent.forAllWindows(this, true /* traverseTopToBottom */); // Legacy animation doesn't need to wait for the start transaction. mIsStartTransactionCommitted = mTransitionOp == OP_LEGACY; if (mIsStartTransactionCommitted) return; // 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. for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { if (mHasScreenRotationAnimation && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) { // The windows are hidden (leash is alpha 0) before finishing drawing so it is // unnecessary to request sync. continue; } final WindowToken token = mTargetWindowTokens.keyAt(i); for (int j = token.getChildCount() - 1; j >= 0; j--) { token.getChildAt(j).applyWithNextDraw(t -> {}); } if (mTransitionOp == OP_LEGACY) { mIsStartTransactionCommitted = true; } else if (displayContent.mTransitionController.useShellTransitionsRotation()) { keepAppearanceInPreviousRotation(); } } Loading Loading @@ -194,6 +185,30 @@ class AsyncRotationController extends FadeAnimationController implements Consume mTargetWindowTokens.put(w.mToken, new Operation(action)); } /** * Enables {@link #handleFinishDrawing(WindowState, SurfaceControl.Transaction)} to capture the * draw transactions of the target windows if needed. */ void keepAppearanceInPreviousRotation() { // 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. for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { if (mHasScreenRotationAnimation && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) { // The windows are hidden (leash is alpha 0) before finishing drawing so it is // unnecessary to request sync. continue; } final WindowToken token = mTargetWindowTokens.keyAt(i); for (int j = token.getChildCount() - 1; j >= 0; j--) { token.getChildAt(j).applyWithNextDraw(t -> {}); } } mIsSyncDrawRequested = true; if (DEBUG) Slog.d(TAG, "Requested to sync draw transaction"); } /** Lets the window fit in new rotation naturally. */ private void finishOp(WindowToken windowToken) { final Operation op = mTargetWindowTokens.remove(windowToken); Loading Loading @@ -433,7 +448,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume */ boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) { if (mTransitionOp == OP_LEGACY || postDrawTransaction == null || !w.mTransitionController.inTransition()) { || !mIsSyncDrawRequested || !w.mTransitionController.inTransition()) { return false; } final Operation op = mTargetWindowTokens.get(w.mToken); Loading services/core/java/com/android/server/wm/DisplayContent.java +19 −12 Original line number Diff line number Diff line Loading @@ -1735,19 +1735,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { final boolean useAsyncRotation = !mTransitionController.isShellTransitionsEnabled(); if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); if (useAsyncRotation) { startAsyncRotation( // Delay the hide animation to avoid blinking by clicking navigation bar // that may toggle fixed rotation in a short time. r == mFixedRotationTransitionListener.mAnimatingRecents); } mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); // Delay the hide animation to avoid blinking by clicking navigation bar that may // toggle fixed rotation in a short time. final boolean shouldDebounce = r == mFixedRotationTransitionListener.mAnimatingRecents || mTransitionController.isTransientLaunch(r); startAsyncRotation(shouldDebounce); } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); if (useAsyncRotation) finishAsyncRotationIfPossible(); // Keep async rotation controller if the next transition of display is requested. if (!mTransitionController.isCollecting(this)) { finishAsyncRotationIfPossible(); } } mFixedRotationLaunchingApp = r; } Loading Loading @@ -1805,7 +1805,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Update directly because the app which will change the orientation of display is ready. if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) { mTransitionController.setSeamlessRotation(this); sendNewConfiguration(); return; } Loading Loading @@ -3234,7 +3233,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp this, this, null /* remoteTransition */, displayChange); if (t != null) { mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY); if (isRotationChanging()) { if (mFixedRotationLaunchingApp != null) { // A fixed-rotation transition is done, then continue to start a seamless display // transition. And be fore the start transaction is applied, the non-app windows // need to keep in previous rotation to avoid showing inconsistent content. t.setSeamlessRotation(this); if (mAsyncRotationController != null) { mAsyncRotationController.keepAppearanceInPreviousRotation(); } } else if (isRotationChanging()) { mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN); controller.mTransitionMetricsReporter.associate(t, startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN)); Loading services/core/java/com/android/server/wm/Transition.java +2 −2 Original line number Diff line number Diff line Loading @@ -548,7 +548,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe for (int i = 0; i < mTargetDisplays.size(); ++i) { final DisplayContent dc = mTargetDisplays.get(i); final AsyncRotationController asyncRotationController = dc.getAsyncRotationController(); if (asyncRotationController != null) { if (asyncRotationController != null && mTargets.contains(dc)) { asyncRotationController.onTransitionFinished(); } if (mTransientLaunches != null) { Loading Loading @@ -696,7 +696,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // This is non-null only if display has changes. It handles the visible windows that don't // need to be participated in the transition. final AsyncRotationController controller = dc.getAsyncRotationController(); if (controller != null) { if (controller != null && mTargets.contains(dc)) { controller.setupStartTransaction(transaction); } mStartTransaction = transaction; Loading services/core/java/com/android/server/wm/TransitionController.java +0 −5 Original line number Diff line number Diff line Loading @@ -519,11 +519,6 @@ class TransitionController { } } void setSeamlessRotation(@NonNull WindowContainer wc) { if (mCollectingTransition == null) return; mCollectingTransition.setSeamlessRotation(wc); } void legacyDetachNavigationBarFromApp(@NonNull IBinder token) { final Transition transition = Transition.fromBinder(token); if (transition == null || !mPlayingTransitions.contains(transition)) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +5 −2 Original line number Diff line number Diff line Loading @@ -348,12 +348,13 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final boolean isTask = change.getTaskInfo() != null; boolean isSeamlessDisplayChange = false; if (change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { if (info.getType() == TRANSIT_CHANGE) { boolean isSeamless = isRotationSeamless(info, mDisplayController); isSeamlessDisplayChange = isRotationSeamless(info, mDisplayController); final int anim = getRotationAnimation(info); if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) { if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) { mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession, mTransactionPool, startTransaction, change, info.getRootLeash(), anim); Loading Loading @@ -387,6 +388,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { startTransaction.setPosition(change.getLeash(), change.getEndAbsBounds().left - info.getRootOffset().x, change.getEndAbsBounds().top - info.getRootOffset().y); // Seamless display transition doesn't need to animate. if (isSeamlessDisplayChange) continue; if (isTask) { // Skip non-tasks since those usually have null bounds. startTransaction.setWindowCrop(change.getLeash(), Loading
services/core/java/com/android/server/wm/AsyncRotationController.java +32 −17 Original line number Diff line number Diff line Loading @@ -94,6 +94,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume /** Whether the start transaction of the transition is committed (by shell). */ private boolean mIsStartTransactionCommitted; /** Whether the target windows have been requested to sync their draw transactions. */ private boolean mIsSyncDrawRequested; private SeamlessRotator mRotator; private final int mOriginalRotation; Loading Loading @@ -139,22 +142,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume displayContent.forAllWindows(this, true /* traverseTopToBottom */); // Legacy animation doesn't need to wait for the start transaction. mIsStartTransactionCommitted = mTransitionOp == OP_LEGACY; if (mIsStartTransactionCommitted) return; // 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. for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { if (mHasScreenRotationAnimation && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) { // The windows are hidden (leash is alpha 0) before finishing drawing so it is // unnecessary to request sync. continue; } final WindowToken token = mTargetWindowTokens.keyAt(i); for (int j = token.getChildCount() - 1; j >= 0; j--) { token.getChildAt(j).applyWithNextDraw(t -> {}); } if (mTransitionOp == OP_LEGACY) { mIsStartTransactionCommitted = true; } else if (displayContent.mTransitionController.useShellTransitionsRotation()) { keepAppearanceInPreviousRotation(); } } Loading Loading @@ -194,6 +185,30 @@ class AsyncRotationController extends FadeAnimationController implements Consume mTargetWindowTokens.put(w.mToken, new Operation(action)); } /** * Enables {@link #handleFinishDrawing(WindowState, SurfaceControl.Transaction)} to capture the * draw transactions of the target windows if needed. */ void keepAppearanceInPreviousRotation() { // 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. for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { if (mHasScreenRotationAnimation && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) { // The windows are hidden (leash is alpha 0) before finishing drawing so it is // unnecessary to request sync. continue; } final WindowToken token = mTargetWindowTokens.keyAt(i); for (int j = token.getChildCount() - 1; j >= 0; j--) { token.getChildAt(j).applyWithNextDraw(t -> {}); } } mIsSyncDrawRequested = true; if (DEBUG) Slog.d(TAG, "Requested to sync draw transaction"); } /** Lets the window fit in new rotation naturally. */ private void finishOp(WindowToken windowToken) { final Operation op = mTargetWindowTokens.remove(windowToken); Loading Loading @@ -433,7 +448,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume */ boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) { if (mTransitionOp == OP_LEGACY || postDrawTransaction == null || !w.mTransitionController.inTransition()) { || !mIsSyncDrawRequested || !w.mTransitionController.inTransition()) { return false; } final Operation op = mTargetWindowTokens.get(w.mToken); Loading
services/core/java/com/android/server/wm/DisplayContent.java +19 −12 Original line number Diff line number Diff line Loading @@ -1735,19 +1735,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { final boolean useAsyncRotation = !mTransitionController.isShellTransitionsEnabled(); if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); if (useAsyncRotation) { startAsyncRotation( // Delay the hide animation to avoid blinking by clicking navigation bar // that may toggle fixed rotation in a short time. r == mFixedRotationTransitionListener.mAnimatingRecents); } mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); // Delay the hide animation to avoid blinking by clicking navigation bar that may // toggle fixed rotation in a short time. final boolean shouldDebounce = r == mFixedRotationTransitionListener.mAnimatingRecents || mTransitionController.isTransientLaunch(r); startAsyncRotation(shouldDebounce); } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); if (useAsyncRotation) finishAsyncRotationIfPossible(); // Keep async rotation controller if the next transition of display is requested. if (!mTransitionController.isCollecting(this)) { finishAsyncRotationIfPossible(); } } mFixedRotationLaunchingApp = r; } Loading Loading @@ -1805,7 +1805,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Update directly because the app which will change the orientation of display is ready. if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) { mTransitionController.setSeamlessRotation(this); sendNewConfiguration(); return; } Loading Loading @@ -3234,7 +3233,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp this, this, null /* remoteTransition */, displayChange); if (t != null) { mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY); if (isRotationChanging()) { if (mFixedRotationLaunchingApp != null) { // A fixed-rotation transition is done, then continue to start a seamless display // transition. And be fore the start transaction is applied, the non-app windows // need to keep in previous rotation to avoid showing inconsistent content. t.setSeamlessRotation(this); if (mAsyncRotationController != null) { mAsyncRotationController.keepAppearanceInPreviousRotation(); } } else if (isRotationChanging()) { mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN); controller.mTransitionMetricsReporter.associate(t, startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN)); Loading
services/core/java/com/android/server/wm/Transition.java +2 −2 Original line number Diff line number Diff line Loading @@ -548,7 +548,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe for (int i = 0; i < mTargetDisplays.size(); ++i) { final DisplayContent dc = mTargetDisplays.get(i); final AsyncRotationController asyncRotationController = dc.getAsyncRotationController(); if (asyncRotationController != null) { if (asyncRotationController != null && mTargets.contains(dc)) { asyncRotationController.onTransitionFinished(); } if (mTransientLaunches != null) { Loading Loading @@ -696,7 +696,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // This is non-null only if display has changes. It handles the visible windows that don't // need to be participated in the transition. final AsyncRotationController controller = dc.getAsyncRotationController(); if (controller != null) { if (controller != null && mTargets.contains(dc)) { controller.setupStartTransaction(transaction); } mStartTransaction = transaction; Loading
services/core/java/com/android/server/wm/TransitionController.java +0 −5 Original line number Diff line number Diff line Loading @@ -519,11 +519,6 @@ class TransitionController { } } void setSeamlessRotation(@NonNull WindowContainer wc) { if (mCollectingTransition == null) return; mCollectingTransition.setSeamlessRotation(wc); } void legacyDetachNavigationBarFromApp(@NonNull IBinder token) { final Transition transition = Transition.fromBinder(token); if (transition == null || !mPlayingTransitions.contains(transition)) { Loading