diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index fef615d651b10..1f71b8fa74eca 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -450,6 +450,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (isReallyAnimating()) { delayed = true; + } else { + + // We aren't animating anything, but exiting windows rely on the animation finished + // callback being called in case the AppWindowToken was pretending to be animating, + // which we might have done because we were in closing/opening apps list. + onAnimationFinished(); } for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index fc5e33a7bc5a3..3256762971fc1 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -454,7 +454,7 @@ class WindowSurfacePlacer { AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); - if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)){ + if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) { // This token isn't going to be animating. Add it to the list of tokens to // be notified of app transition complete since the notification will not be // sent be the app window animator. diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 8d5214a86d847..0c63cd270d39e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -20,6 +20,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.Surface; @@ -29,12 +30,14 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.TRANSIT_UNSET; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -43,7 +46,7 @@ import static org.junit.Assert.assertTrue; * Tests for the {@link AppWindowToken} class. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests + * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests */ @SmallTest // TODO: b/68267650 @@ -231,4 +234,20 @@ public class AppWindowTokenTests extends WindowTestsBase { mToken.finishRelaunching(); assertFalse(mToken.containsShowWhenLockedWindow() || mToken.containsDismissKeyguardWindow()); } + + @Test + @FlakyTest(detail = "Promote once confirmed non-flaky") + public void testStuckExitingWindow() throws Exception { + final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, + "closingWindow"); + closingWindow.mAnimatingExit = true; + closingWindow.mRemoveOnExit = true; + closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + + // We pretended that we were running an exit animation, but that should have been cleared up + // by changing visibility of AppWindowToken + closingWindow.removeIfPossible(); + assertTrue(closingWindow.mRemoved); + } }