summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2021-09-17 02:49:22 +0800
committer Riddle Hsu <riddlehsu@google.com> 2021-09-23 12:36:27 +0000
commit570b2eb491155c222d452f6342c6efa0951b021b (patch)
treee4a2d37e826a038bef3dab56580658d179ad763d
parent9fbadb5a3bbcb5f34cb2c9e1a14098a6b4e3d206 (diff)
Use rotation transition to handle display config change
1. Support fade animation with rotation delta 0. Rotation animation is also used to cover display configuration change, e.g. density, font size. 2. Use normal rotation animation when app requests orientation, e.g. from Activity#setRequestedOrientation. 3. Fix flickering of rotation animation The layers are: Transition Root - Animation leash - RotationLayer - Windowing layer So the higher layer should be leash instead of RotationLayer. Bug: 199836343 Test: ShellTransitionTests Test: setprop persist.debug.shell_transit 1; reboot Change font size in Settings, there should be a fade out animation for transiting to new configuration. Toggle portrait and landscape from app without specifying rotation animation type, seamless rotation should not be used. Change-Id: I7ec9553cc8df2b98f89b6fbda67c3834d018883b
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java31
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java16
-rw-r--r--services/core/java/com/android/server/wm/Transition.java15
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java2
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 834b6e62305d..0f2d058907fb 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -326,7 +326,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.