From 18b51c91fbbae544a79d3d2fadb51cd974b65cce Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 6 Jun 2022 18:42:58 +0800 Subject: [PATCH] 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 --- .../com/android/server/wm/ActivityRecord.java | 3 +-- .../server/wm/ActivityTaskSupervisor.java | 8 +------- .../com/android/server/wm/DisplayContent.java | 7 +++---- .../com/android/server/wm/TaskFragment.java | 2 +- .../com/android/server/wm/WindowContainer.java | 17 ++++++++++++++++- .../java/com/android/server/wm/WindowState.java | 12 ------------ .../java/com/android/server/wm/WindowToken.java | 4 +--- .../android/server/wm/DisplayContentTests.java | 6 +++--- .../com/android/server/wm/TransitionTests.java | 4 ++++ 9 files changed, 30 insertions(+), 33 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f1f091a665e42..b4234c1022432 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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } 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 bd2ce95a814f3..863faa190692c 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 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 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { ArrayList 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 7eeda3f9a695f..2ea6ce53caa29 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 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 d77e9b397ef9c..391077636654c 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 @@ class TaskFragment extends WindowContainer { 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 b579a9d825683..51adb162e329e 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.TITLE; 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; @@ -1158,6 +1159,19 @@ class WindowContainer extends ConfigurationContainer< return getActivity(app -> app.isAnimating(PARENTS | TRANSITION)) != null; } + /** + * 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. */ @@ -1180,7 +1194,8 @@ class WindowContainer extends ConfigurationContainer< 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 70499603801cc..02f95348dc790 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 @@ class WindowState extends WindowContainer implements WindowManagerP 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 6c82a791bb6fb..ab72e49f1e4f3 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_ADD_REMOVE; 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 @@ class WindowToken extends WindowContainer { 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 8f5da44212800..a19b19ec6af90 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 @@ public class DisplayContentTests extends WindowTestsBase { 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 84e94ff271c30..ab72a0f726715 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 @@ public class TransitionTests extends WindowTestsBase { 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.