From f58631a6a265a12a64a5c697178e0f4784f562ac Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 24 May 2016 16:02:10 -0700 Subject: Destroy saved surfaces if one of the last visible windows gets removed Also, if by the time the app is closing, a window is still invisible in layout (or is already removed), mark the window as mAnimatingExit, so that the surface is destroyed (or saved again). If it's marked for removal, the window gets removed as well. bug: 28913302 Change-Id: Ifa3dc0742f9c8c09d741fd64dcdc01b49075628c --- .../java/com/android/server/wm/AppWindowToken.java | 10 +++++++ .../android/server/wm/WindowManagerService.java | 31 +++++++++++----------- .../java/com/android/server/wm/WindowState.java | 4 ++- .../com/android/server/wm/WindowSurfacePlacer.java | 8 ++++++ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index b773a4e016bd..f57e83aa1e0d 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -451,6 +451,16 @@ class AppWindowToken extends WindowToken { destroySurfaces(); } + void markSavedSurfaceExiting() { + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + if (w.isAnimatingInvisibleWithSavedSurface()) { + w.mAnimatingExit = true; + w.mWinAnimator.mAnimating = true; + } + } + } + void restoreSavedSurfaces() { if (!canRestoreSurfaces()) { clearVisibleBeforeClientHidden(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index aaed8ca9181d..d36371219ac0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2277,6 +2277,19 @@ public class WindowManagerService extends IWindowManager.Stub } } + private void setupWindowForRemoveOnExit(WindowState win) { + win.mRemoveOnExit = true; + win.setDisplayLayoutNeeded(); + // Request a focus update as this window's input channel is already gone. Otherwise + // we could have no focused window in input manager. + final boolean focusChanged = updateFocusedWindowLocked( + UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); + mWindowPlacerLocked.performSurfacePlacement(); + if (focusChanged) { + mInputMonitor.updateInputWindowsLw(false /*force*/); + } + } + public void removeWindow(Session session, IWindow client) { synchronized(mWindowMap) { WindowState win = windowForClientLocked(session, client, false); @@ -2358,14 +2371,7 @@ public class WindowManagerService extends IWindowManager.Stub // Do not set mAnimatingExit to true here, it will cause the surface to be hidden // immediately after the enter animation is done. If the app is not yet drawn then // it will show up as a flicker. - win.mRemoveOnExit = true; - // Request a focus update as this window's input channel is already gone. Otherwise - // we could have no focused window in input manager. - final boolean focusChanged = updateFocusedWindowLocked( - UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); - if (focusChanged) { - mInputMonitor.updateInputWindowsLw(false /*force*/); - } + setupWindowForRemoveOnExit(win); Binder.restoreCallingIdentity(origId); return; } @@ -2417,17 +2423,10 @@ public class WindowManagerService extends IWindowManager.Stub // The exit animation is running or should run... wait for it! if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Not removing " + win + " due to exit animation "); - win.mRemoveOnExit = true; - win.setDisplayLayoutNeeded(); - final boolean focusChanged = updateFocusedWindowLocked( - UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); - mWindowPlacerLocked.performSurfacePlacement(); + setupWindowForRemoveOnExit(win); if (appToken != null) { appToken.updateReportedVisibilityLocked(); } - if (focusChanged) { - mInputMonitor.updateInputWindowsLw(false /*force*/); - } Binder.restoreCallingIdentity(origId); return; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c15afb339646..be27c82d61fc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2111,7 +2111,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { void clearHasSavedSurface() { mSurfaceSaved = false; mAnimatingWithSavedSurface = false; - mWasVisibleBeforeClientHidden = false; + if (mWasVisibleBeforeClientHidden) { + mAppToken.destroySavedSurfaces(); + } } boolean clearAnimatingWithSavedSurface() { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 308b24dd8dd6..4148cd07681f 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -1301,6 +1301,14 @@ class WindowSurfacePlacer { appsCount = mService.mClosingApps.size(); for (int i = 0; i < appsCount; i++) { AppWindowToken wtoken = mService.mClosingApps.valueAt(i); + + // If we still have some windows animating with saved surfaces that's + // either invisible or already removed, mark them exiting so that they + // are disposed of after the exit animation. These are not supposed to + // be shown, or are delayed removal until app is actually drawn (in which + // case the window will be removed after the animation). + wtoken.markSavedSurfaceExiting(); + final AppWindowAnimator appAnimator = wtoken.mAppAnimator; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken); appAnimator.clearThumbnail(); -- cgit v1.2.3-59-g8ed1b