Reuse common transition method used by both legacy and shell
To reduce scattered duplicated code of "isAnimating+inTransition"
when the places have the same condition to check either legacy or
shell transition.
The major fix is in WindowToken, which avoids clearing fixed
rotation too early when FixedRotationTransitionListener receives
onAppTransitionFinished for an activity which is still in transition.
E.g. launch landscape app from portrait home, and then swipe up
before the launch animation is finished. The closing animation should
still show the app in landscape.
Bug: 223397413
Bug: 212570341
Test: atest TransitionTests#testAppTransitionWithRotationChange
Change-Id: Ib954b390137ea11ccc45748b62e7b7d6812dceb7
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f1f091a6..b4234c1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7971,8 +7971,7 @@
}
boolean isInTransition() {
- return mTransitionController.inTransition(this) // Shell transitions.
- || isAnimating(PARENTS | TRANSITION); // Legacy transitions.
+ return inTransitionSelfOrParent();
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bd2ce95..863faa1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -74,13 +74,9 @@
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.Task.TAG_CLEANUP;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.Manifest;
@@ -1925,9 +1921,7 @@
ArrayList<ActivityRecord> readyToStopActivities = null;
for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
final ActivityRecord s = mStoppingActivities.get(i);
- final boolean animating = s.isAnimating(TRANSITION | PARENTS,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)
- || s.inTransition();
+ final boolean animating = s.isInTransition();
ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ "finishing=%s", s, s.nowVisible, animating, s.finishing);
if (!animating || mService.mShuttingDown) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7eeda3f..2ea6ce5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1782,7 +1782,7 @@
* rotation transform to it and indicate that the display may be rotated after it is launched.
*/
void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Rotation int rotation) {
- final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
+ final ActivityRecord prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
if (prevRotatedLaunchingApp == r
&& r.getWindowConfiguration().getRotation() == rotation) {
// The given launching app and target rotation are the same as the existing ones.
@@ -1791,8 +1791,7 @@
if (prevRotatedLaunchingApp != null
&& prevRotatedLaunchingApp.getWindowConfiguration().getRotation() == rotation
// It is animating so we can expect there will have a transition callback.
- && (prevRotatedLaunchingApp.isAnimating(TRANSITION | PARENTS)
- || mTransitionController.inTransition(prevRotatedLaunchingApp))) {
+ && (prevRotatedLaunchingApp.isInTransition())) {
// It may be the case that multiple activities launch consecutively. Because their
// rotation are the same, the transformed state can be shared to avoid duplicating
// the heavy operations. This also benefits that the states of multiple activities
@@ -6468,7 +6467,7 @@
// Different tasks won't be in one activity transition animation.
return;
}
- if (task.isAppTransitioning()) {
+ if (task.getActivity(ActivityRecord::isInTransition) != null) {
return;
// Continue to update orientation because the transition of the top rotated
// launching activity is done.
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d77e9b3..3910776 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2496,7 +2496,7 @@
if (!hasChild()) {
return false;
}
- return isExitAnimationRunningSelfOrChild() || inTransition();
+ return isExitAnimationRunningSelfOrChild();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b579a9d..51adb16 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -48,6 +48,7 @@
import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -1159,6 +1160,19 @@
}
/**
+ * Returns {@code true} if self or the parent container of the window is in transition, e.g.
+ * the app or recents transition. This method is only used when legacy and shell transition
+ * have the same condition to check the animation state.
+ */
+ boolean inTransitionSelfOrParent() {
+ if (!mTransitionController.isShellTransitionsEnabled()) {
+ return isAnimating(PARENTS | TRANSITION,
+ ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
+ }
+ return inTransition();
+ }
+
+ /**
* @return Whether our own container running an animation at the moment.
*/
final boolean isAnimating() {
@@ -1180,7 +1194,8 @@
if (!mTransitionController.isShellTransitionsEnabled()) {
return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES);
}
- if (mTransitionController.isCollecting(this)) {
+ // Only check leaf containers because inTransition() includes parent.
+ if (mChildren.isEmpty() && inTransition()) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7049960..02f9534 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4965,18 +4965,6 @@
return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
}
- /**
- * @return {@code true} if self or the parent container of the window is in transition.
- * (e.g. The app or recents transition)
- */
- boolean inTransitionSelfOrParent() {
- if (!mTransitionController.isShellTransitionsEnabled()) {
- return isAnimating(PARENTS | TRANSITION,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
- }
- return mTransitionController.inTransition(this);
- }
-
private boolean shouldFinishAnimatingExit() {
// Exit animation might be applied soon.
if (inTransition()) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 6c82a79..ab72e49 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -24,8 +24,6 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.WINDOW_TOKEN;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -501,7 +499,7 @@
for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) {
final ActivityRecord r =
mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord();
- if (r != null && r.isAnimating(TRANSITION | PARENTS)) {
+ if (r != null && r.isInTransition()) {
return true;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 8f5da44..a19b19e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1617,14 +1617,14 @@
final Task task = app.getTask();
final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
- doReturn(true).when(task).isAppTransitioning();
- // If the task is animating transition, this should be no-op.
+ doReturn(true).when(app).isInTransition();
+ // If the task contains a transition, this should be no-op.
mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
assertTrue(app2.hasFixedRotationTransform());
assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
- doReturn(false).when(task).isAppTransitioning();
+ doReturn(false).when(app).isInTransition();
// Although this notifies app instead of app2 that uses the fixed rotation, app2 should
// still finish the transform because there is no more transition event.
mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 84e94ff..ab72a0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -793,6 +793,10 @@
assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
assertNotNull(mDisplayContent.getAsyncRotationController());
+ // The app is still in transition, so the callback should be no-op.
+ mDisplayContent.mTransitionController.dispatchLegacyAppTransitionFinished(app);
+ assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
+
statusBar.setOrientationChanging(true);
player.startTransition();
// Non-app windows should not be collected.