From ab9fcb2197796ab80cbfb226c443e4eb3ffbc15b Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Thu, 15 Mar 2018 23:46:12 +0100 Subject: [PATCH] Fix stuck exiting windows When a window was marked as exiting because in WS.removeIfPossible applyAnimationLocked returned true just because AWT was in mClosing/OpeningApps for the transition, the window wasn't removed if there was no animation running for the app transition. Fix this by also calling the animation finished callback when not running an animation, because other code parts rely on that being called. Test: Change language, swipe up, make sure no stuck window Test: AppWindowTokenTests Change-Id: I9cfd0c4090a258bc90ba5cf7d71795b6fce7f8ef Fixes: 72811863 --- .../com/android/server/wm/AppWindowToken.java | 6 ++++++ .../server/wm/WindowSurfacePlacer.java | 2 +- .../server/wm/AppWindowTokenTests.java | 21 ++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) 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); + } }