Merge "Clean up surfaces when app is resumed without being stopped." into nyc-mr1-dev
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9bc0bb4..0601219 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -173,7 +173,8 @@
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 eb02dc3..752dbd9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1249,7 +1249,7 @@
r.stopped = true;
r.state = ActivityState.STOPPED;
- mWindowManager.notifyAppStopped(r.appToken, true);
+ mWindowManager.notifyAppStopped(r.appToken);
if (getVisibleBehindActivity() == r) {
mStackSupervisor.requestVisibleBehindLocked(r, false);
@@ -2490,7 +2490,7 @@
// 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 66e9fd86..eac72b0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -337,21 +337,41 @@
}
}
- // 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<WindowState> allWindows = (ArrayList<WindowState>) 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;
}
@@ -361,7 +381,9 @@
+ " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
+ " win.mRemoveOnExit=" + win.mRemoveOnExit);
- win.destroyOrSaveSurface();
+ if (!cleanupOnResume || win.mRemoveOnExit) {
+ win.destroyOrSaveSurface();
+ }
if (win.mRemoveOnExit) {
service.removeWindowInnerLocked(win);
}
@@ -379,21 +401,30 @@
}
/**
- * 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.
*
* @return true if the surfaces should be saved, false otherwise.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d8a4538..8c5481d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4476,7 +4476,25 @@
}
@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");
@@ -4486,10 +4504,10 @@
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 49ab9f9..5a9860d 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -351,7 +351,12 @@
}
@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
}