diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 9bc0bb4b38f77..06012198333c5 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -173,7 +173,8 @@ interface IWindowManager in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded); void setAppVisibility(IBinder token, boolean visible); - void notifyAppStopped(IBinder token, boolean stopped); + void notifyAppResumed(IBinder token, boolean wasStopped); + void notifyAppStopped(IBinder token); void startAppFreezingScreen(IBinder token, int configChanges); void stopAppFreezingScreen(IBinder token, boolean force); void removeAppToken(IBinder token); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 6b2f27f6059eb..99e3ebcbe91f2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1245,7 +1245,7 @@ final class ActivityStack { r.stopped = true; r.state = ActivityState.STOPPED; - mWindowManager.notifyAppStopped(r.appToken, true); + mWindowManager.notifyAppStopped(r.appToken); if (getVisibleBehindActivity() == r) { mStackSupervisor.requestVisibleBehindLocked(r, false); @@ -2495,7 +2495,7 @@ final class ActivityStack { // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. - mWindowManager.notifyAppStopped(next.appToken, false); + mWindowManager.notifyAppResumed(next.appToken, next.stopped); EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, System.identityHashCode(next), next.task.taskId, next.shortComponentName); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 10000434d5613..b7ee022a59851 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -336,21 +336,41 @@ class AppWindowToken extends WindowToken { } } - // Here we destroy surfaces which have been marked as eligible by the animator, taking care - // to ensure the client has finished with them. If the client could still be using them - // we will skip destruction and try again when the client has stopped. void destroySurfaces() { + destroySurfaces(false /*cleanupOnResume*/); + } + + /** + * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure + * the client has finished with them. + * + * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If + * set to true, destroy only surfaces of removed windows, and clear relevant flags of the + * others so that they are ready to be reused. If set to false (common case), destroy all + * surfaces that's eligible, if the app is already stopped. + */ + + private void destroySurfaces(boolean cleanupOnResume) { final ArrayList allWindows = (ArrayList) allAppWindows.clone(); final DisplayContentList displayList = new DisplayContentList(); for (int i = allWindows.size() - 1; i >= 0; i--) { final WindowState win = allWindows.get(i); - if (!(mAppStopped || win.mWindowRemovalAllowed)) { + if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) { continue; } win.mWinAnimator.destroyPreservedSurfaceLocked(); + if (cleanupOnResume) { + // If the window has an unfinished exit animation, consider that animation + // done and mark the window destroying so that it goes through the cleanup. + if (win.mAnimatingExit) { + win.mDestroying = true; + win.mAnimatingExit = false; + } + } + if (!win.mDestroying) { continue; } @@ -360,7 +380,9 @@ class AppWindowToken extends WindowToken { + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed + " win.mRemoveOnExit=" + win.mRemoveOnExit); - win.destroyOrSaveSurface(); + if (!cleanupOnResume || win.mRemoveOnExit) { + win.destroyOrSaveSurface(); + } if (win.mRemoveOnExit) { win.remove(); } @@ -378,20 +400,29 @@ class AppWindowToken extends WindowToken { } /** - * If the application has stopped it is okay to destroy any surfaces which were keeping alive - * in case they were still being used. + * Notify that the app is now resumed, and it was not stopped before, perform a clean + * up of the surfaces */ - void notifyAppStopped(boolean stopped) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this); - mAppStopped = stopped; - - if (stopped) { - destroySurfaces(); - // Remove any starting window that was added for this app if they are still around. - mTask.mService.scheduleRemoveStartingWindowLocked(this); + void notifyAppResumed(boolean wasStopped) { + if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped + " " + this); + mAppStopped = false; + if (!wasStopped) { + destroySurfaces(true /*cleanupOnResume*/); } } + /** + * Notify that the app has stopped, and it is okay to destroy any surfaces which were + * keeping alive in case they were still being used. + */ + void notifyAppStopped() { + if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); + mAppStopped = true; + destroySurfaces(); + // Remove any starting window that was added for this app if they are still around. + mTask.mService.scheduleRemoveStartingWindowLocked(this); + } + /** * Checks whether we should save surfaces for this app. * diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2a02bc5a0f898..08d42fbd145a9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4412,7 +4412,25 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void notifyAppStopped(IBinder token, boolean stopped) { + public void notifyAppResumed(IBinder token, boolean wasStopped) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "notifyAppResumed()")) { + throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); + } + + synchronized(mWindowMap) { + final AppWindowToken wtoken; + wtoken = findAppWindowToken(token); + if (wtoken == null) { + Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token); + return; + } + wtoken.notifyAppResumed(wasStopped); + } + } + + @Override + public void notifyAppStopped(IBinder token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "notifyAppStopped()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -4422,10 +4440,10 @@ public class WindowManagerService extends IWindowManager.Stub final AppWindowToken wtoken; wtoken = findAppWindowToken(token); if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token); + Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token); return; } - wtoken.notifyAppStopped(stopped); + wtoken.notifyAppStopped(); } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 49ab9f9118331..5a9860d5c80a6 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -351,7 +351,12 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void notifyAppStopped(IBinder token, boolean stopped) throws RemoteException { + public void notifyAppResumed(IBinder token, boolean wasStopped) throws RemoteException { + // TODO Auto-generated method stub + } + + @Override + public void notifyAppStopped(IBinder token) throws RemoteException { // TODO Auto-generated method stub }