am 9ef471f7: Don\'t remove Activities and Tasks until animation done

* commit '9ef471f7f2f59de032d7cb9c3c7241486109979e':
  Don't remove Activities and Tasks until animation done
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a7442c6..f609e7e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1150,7 +1150,11 @@
         if (err == ActivityManager.START_SUCCESS) {
             final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
             Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
-                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)
+                    + " on display " + (container == null ? (mFocusedStack == null ?
+                            Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
+                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+                                    container.mActivityDisplay.mDisplayId)));
         }
 
         ActivityRecord sourceRecord = null;
@@ -3068,10 +3072,6 @@
             init(mDisplayManager.getDisplay(displayId));
         }
 
-        ActivityDisplay(Display display) {
-            init(display);
-        }
-
         ActivityDisplay(Surface surface, int width, int height, int density) {
             DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
             long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e98014b..ca4ad8a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -105,6 +105,8 @@
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
+    boolean mDeferRemoval;
+
     AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
         super(_service, _token.asBinder(),
                 WindowManager.LayoutParams.TYPE_APPLICATION, true);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9f72663..036804c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -25,6 +25,7 @@
     final AppTokenList mAppTokens = new AppTokenList();
     final int taskId;
     final int mUserId;
+    boolean mDeferRemoval = false;
 
     Task(AppWindowToken wtoken, TaskStack stack, int userId) {
         taskId = wtoken.groupId;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0941c76..7d8cff4 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -366,7 +366,7 @@
         mAnimationBackgroundSurface.mDimSurface.destroy();
     }
 
-    void checkForDeferredDetach() {
+    void checkForDeferredActions() {
         if (mDisplayContent != null &&
                 (mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 &&
                 !isAnimating()) {
@@ -377,6 +377,21 @@
                 mService.onDisplayRemoved(mDisplayContent.getDisplayId());
             }
         }
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.get(taskNdx);
+            AppTokenList tokens = task.mAppTokens;
+            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                AppWindowToken wtoken = tokens.get(tokenNdx);
+                if (wtoken.mDeferRemoval) {
+                    wtoken.mDeferRemoval = false;
+                    mService.removeAppFromTaskLocked(wtoken);
+                }
+            }
+            if (task.mDeferRemoval) {
+                task.mDeferRemoval = false;
+                mService.removeTaskLocked(task);
+            }
+        }
     }
 
     public void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 94f998c..cf249dd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
 import android.app.AppOpsManager;
+import android.util.ArraySet;
 import android.util.TimeUtils;
 import android.view.IWindowId;
 
@@ -366,6 +367,11 @@
     final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
 
     /**
+     * Stacks whose animations have ended and whose tasks, apps, selves may now be removed.
+     */
+    final ArraySet<TaskStack> mPendingStacksRemove = new ArraySet<TaskStack>();
+
+    /**
      * Used when processing mPendingRemove to avoid working on the original array.
      */
     WindowState[] mPendingRemoveTmp = new WindowState[20];
@@ -3425,6 +3431,8 @@
     }
 
     private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) {
+        if (DEBUG_STACK) Slog.i(TAG, "createTask: taskId=" + taskId + " stackId=" + stackId
+                + " atoken=" + atoken);
         final TaskStack stack = mStackIdToStack.get(stackId);
         if (stack == null) {
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
@@ -3507,7 +3515,7 @@
                 return;
             }
             final Task oldTask = mTaskIdToTask.get(atoken.groupId);
-            removeAppFromTask(atoken);
+            removeAppFromTaskLocked(atoken);
 
             atoken.groupId = groupId;
             Task newTask = mTaskIdToTask.get(groupId);
@@ -4517,11 +4525,10 @@
         }
     }
 
-    void removeAppFromTask(AppWindowToken wtoken) {
+    void removeAppFromTaskLocked(AppWindowToken wtoken) {
         final Task task = mTaskIdToTask.get(wtoken.groupId);
-        if (task != null && task.removeAppToken(wtoken)) {
-            task.mStack.removeTask(task);
-            mTaskIdToTask.delete(wtoken.groupId);
+        if (!wtoken.mDeferRemoval && task != null && task.removeAppToken(wtoken)) {
+            removeTaskLocked(task);
         }
     }
 
@@ -4563,17 +4570,18 @@
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
                     stack.mExitingAppTokens.add(wtoken);
+                    wtoken.mDeferRemoval = true;
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
+                    removeAppFromTaskLocked(wtoken);
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
 
-                removeAppFromTask(wtoken);
 
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
@@ -4928,6 +4936,21 @@
         }
     }
 
+    void removeTaskLocked(Task task) {
+        final int taskId = task.taskId;
+        final TaskStack stack = task.mStack;
+        if (stack.isAnimating()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
+            task.mDeferRemoval = true;
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
+        task.mDeferRemoval = false;
+        task.mStack.removeTask(task);
+        mTaskIdToTask.delete(task.taskId);
+    }
+
     public void removeTask(int taskId) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -4935,14 +4958,14 @@
                 if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
                 return;
             }
-            final TaskStack stack = task.mStack;
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
-            stack.removeTask(task);
+            removeTaskLocked(task);
         }
     }
 
     public void addTask(int taskId, int stackId, boolean toTop) {
         synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId
+                    + " to " + (toTop ? "top" : "bottom"));
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
                 return;
@@ -9367,7 +9390,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    removeAppFromTask(token);
+                    removeAppFromTaskLocked(token);
                     exitingAppTokens.remove(i);
                 }
             }
@@ -9460,6 +9483,11 @@
             }
         }
 
+        // Remove all deferred Stacks, tasks, and activities.
+        for (int stackNdx = mPendingStacksRemove.size() - 1; stackNdx >= 0; --stackNdx) {
+            mPendingStacksRemove.removeAt(stackNdx).checkForDeferredActions();
+        }
+
         setFocusedStackFrame();
 
         // Check to see if we are now in a state where the screen should
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5cff319..ffb17f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -416,7 +416,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
-        mWin.getStack().checkForDeferredDetach();
+        mService.mPendingStacksRemove.add(mWin.getStack());
         mAnimator.hideWallpapersLocked(mWin);
     }