diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 551e06df3bb0f..b35e3e41afd7f 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -131,6 +131,7 @@ import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS; import static com.android.server.wm.MoveAnimationSpecProto.FROM; import static com.android.server.wm.MoveAnimationSpecProto.TO; 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_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -2281,7 +2282,8 @@ class WindowState extends WindowContainer implements WindowManagerP mWmService.mAccessibilityController.onWindowTransitionLocked(this, transit); } } - final boolean isAnimating = isAnimating(TRANSITION | PARENTS) + final boolean isAnimating = mAnimatingExit || isAnimating(TRANSITION | PARENTS, + ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION) && (mActivityRecord == null || !mActivityRecord.isWaitingForTransitionStart()); final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null && mActivityRecord.isLastWindow(this); @@ -2290,8 +2292,10 @@ class WindowState extends WindowContainer implements WindowManagerP // Also, If isn't the an animating starting window that is the last window in the app. // We allow the removal of the non-animating starting window now as there is no // additional window or animation that will trigger its removal. - if (mWinAnimator.getShown() && mAnimatingExit - && (!lastWindowIsStartingWindow || isAnimating)) { + if (mWinAnimator.getShown() && !lastWindowIsStartingWindow && isAnimating) { + // Make isSelfOrAncestorWindowAnimatingExit return true so onExitAnimationDone + // can proceed to remove this window. + mAnimatingExit = true; // The exit animation is running or should run... wait for it! ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Not removing %s due to exit animation", this); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 7db2fc9a899f9..263aa194a1080 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -447,6 +447,26 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(child2.isSelfOrAncestorWindowAnimatingExit()); } + @Test + public void testDeferredRemovalByAnimating() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + makeWindowVisible(appWindow); + spyOn(appWindow.mWinAnimator); + doReturn(true).when(appWindow.mWinAnimator).getShown(); + final AnimationAdapter animation = mock(AnimationAdapter.class); + final ActivityRecord activity = appWindow.mActivityRecord; + activity.startAnimation(appWindow.getPendingTransaction(), + animation, false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION); + + appWindow.removeIfPossible(); + assertTrue(appWindow.mAnimatingExit); + assertFalse(appWindow.mRemoved); + + activity.cancelAnimation(); + assertFalse(appWindow.mAnimatingExit); + assertTrue(appWindow.mRemoved); + } + @Test public void testLayoutSeqResetOnReparent() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app");