diff options
9 files changed, 82 insertions, 32 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 4ba6acaba025..b673d48f3d15 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -141,8 +141,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { static boolean isRotationSeamless(@NonNull TransitionInfo info, DisplayController displayController) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, - "Display is rotating, check if it should be seamless."); + "Display is changing, check if it should be seamless."); boolean checkedDisplayLayout = false; + boolean hasTask = false; for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); @@ -166,6 +167,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { return false; } } else if (change.getTaskInfo() != null) { + hasTask = true; // We only enable seamless rotation if all the visible task windows requested it. if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, @@ -209,8 +211,12 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Rotation IS seamless."); - return true; + // ROTATION_ANIMATION_SEAMLESS can only be requested by task. + if (hasTask) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Rotation IS seamless."); + return true; + } + return false; } /** @@ -280,7 +286,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final TransitionInfo.Change change = info.getChanges().get(i); if (info.getType() == TRANSIT_CHANGE && change.getMode() == TRANSIT_CHANGE - && (change.getEndRotation() != change.getStartRotation()) && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { boolean isSeamless = isRotationSeamless(info, mDisplayController); final int anim = getRotationAnimation(info); 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 ada2ed27c114..13c670a1ab1e 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 @@ -186,11 +186,11 @@ class ScreenRotationAnimation { t.setAlpha(mBackColorSurface, 1); t.show(mBackColorSurface); + t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE); t.setPosition(mAnimLeash, 0, 0); t.setAlpha(mAnimLeash, 1); t.show(mAnimLeash); - t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE); t.setBuffer(mScreenshotLayer, buffer); t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace()); t.show(mScreenshotLayer); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index b0f0d71c2638..e39171343bb9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -583,6 +583,13 @@ public class ShellTransitionTests { .setRotate(ROTATION_ANIMATION_SEAMLESS).build()) .build(); assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessButAlert, displays)); + + // Not seamless if there is no changed task. + final TransitionInfo noTask = new TransitionInfoBuilder(TRANSIT_CHANGE) + .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY) + .setRotate().build()) + .build(); + assertFalse(DefaultTransitionHandler.isRotationSeamless(noTask, displays)); } class TransitionInfoBuilder { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c45b661f06fb..b107ff8a6b7b 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5943,6 +5943,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void startFreezingScreen(int overrideOriginalDisplayRotation) { + if (mAtmService.getTransitionController().isShellTransitionsEnabled()) { + return; + } ProtoLog.i(WM_DEBUG_ORIENTATION, "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", appToken, isVisible(), mFreezingScreen, mVisibleRequested, @@ -8443,9 +8446,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { // Aha, the activity isn't handling the change, so DIE DIE DIE. configChangeFlags |= changes; - if (!mAtmService.getTransitionController().isShellTransitionsEnabled()) { - startFreezingScreenLocked(globalChanges); - } + startFreezingScreenLocked(globalChanges); forceNewConfig = false; // Do not preserve window if it is freezing screen because the original window won't be // able to update drawn state that causes freeze timeout. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 63f6387c87ae..f800f0e395de 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -76,6 +76,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; @@ -1389,11 +1390,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final Configuration currentDisplayConfig = getConfiguration(); mTmpConfiguration.setTo(currentDisplayConfig); computeScreenConfiguration(mTmpConfiguration); - configChanged |= currentDisplayConfig.diff(mTmpConfiguration) != 0; + final int changes = currentDisplayConfig.diff(mTmpConfiguration); + configChanged |= changes != 0; if (configChanged) { mWaitingForConfig = true; - mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this); + if (mAtmService.getTransitionController().isShellTransitionsEnabled()) { + requestChangeTransitionIfNeeded(changes); + } else { + mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this); + } sendNewConfiguration(); } @@ -3165,6 +3171,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mScreenRotationAnimation; } + /** + * Requests to start a transition for the display configuration change. The given changes must + * be non-zero. This method is no-op if the display has been collected. + */ + void requestChangeTransitionIfNeeded(@ActivityInfo.Config int changes) { + final TransitionController controller = mAtmService.getTransitionController(); + if (controller.isCollecting()) { + if (!controller.isCollecting(this)) { + controller.collect(this); + } + return; + } + final Transition t = controller.requestTransitionIfNeeded(TRANSIT_CHANGE, this); + if (t != null) { + t.setKnownConfigChanges(this, changes); + } + } + /** If the display is in transition, there should be a screenshot covering it. */ @Override boolean inTransition() { @@ -5724,6 +5748,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mWmService.mDisplayNotificationController.dispatchDisplayChanged( this, getConfiguration()); + if (isReady() && mAtmService.getTransitionController().isShellTransitionsEnabled()) { + requestChangeTransitionIfNeeded(changes); + } } return changes; } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index c9db14de507c..971bebd8c486 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -22,7 +22,6 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFA import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; -import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; @@ -492,12 +491,6 @@ public class DisplayRotation { recentsAnimationController.cancelAnimationForDisplayChange(); } - final Transition t = (useShellTransitions - && !mService.mAtmService.getTransitionController().isCollecting()) - ? mService.mAtmService.getTransitionController().createTransition(TRANSIT_CHANGE) - : null; - mService.mAtmService.getTransitionController().collect(mDisplayContent); - ProtoLog.v(WM_DEBUG_ORIENTATION, "Display id=%d rotation changed to %d from %d, lastOrientation=%d", displayId, rotation, oldRotation, lastOrientation); @@ -511,11 +504,10 @@ public class DisplayRotation { mDisplayContent.setLayoutNeeded(); if (useShellTransitions) { - if (t != null) { - // This created its own transition, so send a start request. - mService.mAtmService.getTransitionController().requestStartTransition( - t, null /* trigger */, null /* remote */); - } else { + final boolean wasInTransition = mDisplayContent.inTransition(); + mDisplayContent.requestChangeTransitionIfNeeded( + ActivityInfo.CONFIG_WINDOW_CONFIGURATION); + if (wasInTransition) { // Use remote-rotation infra since the transition has already been requested // TODO(shell-transitions): Remove this once lifecycle management can cover all // rotation cases. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 1a46d0f9a877..1909875565f6 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -58,6 +58,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; @@ -269,6 +270,18 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mChanges.get(wc).mExistenceChanged = true; } + /** + * Specifies configuration change explicitly for the window container, so it can be chosen as + * transition target. This is usually used with transition mode + * {@link android.view.WindowManager#TRANSIT_CHANGE}. + */ + void setKnownConfigChanges(WindowContainer<?> wc, @ActivityInfo.Config int changes) { + final ChangeInfo changeInfo = mChanges.get(wc); + if (changeInfo != null) { + changeInfo.mKnownConfigChanges = changes; + } + } + private void sendRemoteCallback(@Nullable IRemoteCallback callback) { if (callback == null) return; mController.mAtm.mH.sendMessage(PooledLambda.obtainMessage(cb -> { @@ -1218,6 +1231,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final Rect mAbsoluteBounds = new Rect(); boolean mShowWallpaper; int mRotation = ROTATION_UNDEFINED; + @ActivityInfo.Config int mKnownConfigChanges; ChangeInfo(@NonNull WindowContainer origState) { mVisible = origState.isVisibleRequested(); @@ -1240,6 +1254,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final boolean currVisible = newState.isVisibleRequested(); if (currVisible == mVisible && !mVisible) return false; return currVisible != mVisible + || mKnownConfigChanges != 0 // if mWindowingMode is 0, this container wasn't attached at collect time, so // assume no change in windowing-mode. || (mWindowingMode != 0 && newState.getWindowingMode() != mWindowingMode) diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index c1d0f80adbb7..fc5423942dc3 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -71,15 +71,7 @@ class TransitionController { final Lock mRunningLock = new Lock(); - private final IBinder.DeathRecipient mTransitionPlayerDeath = () -> { - // clean-up/finish any playing transitions. - for (int i = 0; i < mPlayingTransitions.size(); ++i) { - mPlayingTransitions.get(i).cleanUpOnFailure(); - } - mPlayingTransitions.clear(); - mTransitionPlayer = null; - mRunningLock.doNotifyLocked(); - }; + private final IBinder.DeathRecipient mTransitionPlayerDeath; /** The transition currently being constructed (collecting participants). */ private Transition mCollectingTransition = null; @@ -90,6 +82,17 @@ class TransitionController { TransitionController(ActivityTaskManagerService atm) { mAtm = atm; mStatusBar = LocalServices.getService(StatusBarManagerInternal.class); + mTransitionPlayerDeath = () -> { + synchronized (mAtm.mGlobalLock) { + // Clean-up/finish any playing transitions. + for (int i = 0; i < mPlayingTransitions.size(); ++i) { + mPlayingTransitions.get(i).cleanUpOnFailure(); + } + mPlayingTransitions.clear(); + mTransitionPlayer = null; + mRunningLock.doNotifyLocked(); + } + }; } /** @see #createTransition(int, int) */ diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 0b2b05054e60..4cc764ac33ca 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -327,7 +327,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (transition != null) { // First check if we have a display rotation transition and if so, update it. final DisplayContent dc = DisplayRotation.getDisplayFromTransition(transition); - if (dc != null && transition.mChanges.get(dc).mRotation != dc.getRotation()) { + if (dc != null && transition.mChanges.get(dc).hasChanged(dc)) { // Go through all tasks and collect them before the rotation // TODO(shell-transitions): move collect() to onConfigurationChange once // wallpaper handling is synchronized. |