Refactor removeApp and removeTask for last removals.

Move app token removal to the AppWindowToken class so cleanup can
be done locally. Move task removal to the Task class so cleanup can
be done locally. Call task removal when the last app is removed.
Merge actions done prior to method calls into methods.

Fixes bug 18088522 item #12.

Change-Id: I5ce85d2bb309ceb82bd7404e27a56a7c31cd7359
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2a8d64b..26a1c3a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,6 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
-import android.net.LinkProperties;
 import android.net.Network;
 import android.net.Proxy;
 import android.net.ProxyInfo;
@@ -87,8 +86,6 @@
 import android.util.SuperNotCalledException;
 import android.view.Display;
 import android.view.HardwareRenderer;
-import android.view.IWindowManager;
-import android.view.IWindowSessionCallback;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewManager;
@@ -165,8 +162,8 @@
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
-    private static final int LOG_ON_PAUSE_CALLED = 30021;
-    private static final int LOG_ON_RESUME_CALLED = 30022;
+    private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
+    private static final int LOG_AM_ON_RESUME_CALLED = 30022;
 
     private ContextImpl mSystemContext;
 
@@ -2993,7 +2990,7 @@
                 }
                 r.activity.performResume();
 
-                EventLog.writeEvent(LOG_ON_RESUME_CALLED,
+                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED,
                         UserHandle.myUserId(), r.activity.getComponentName().getClassName());
 
                 r.paused = false;
@@ -3263,7 +3260,7 @@
             // Now we are idle.
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
-            EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
+            EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                     r.activity.getComponentName().getClassName());
             if (!r.activity.mCalled) {
                 throw new SuperNotCalledException(
@@ -3660,7 +3657,7 @@
                 try {
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
-                    EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
+                    EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                             r.activity.getComponentName().getClassName());
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 8519f3d..3b27cd2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -252,6 +252,20 @@
         return false;
     }
 
+    void removeAppFromTaskLocked() {
+        mIsExiting = false;
+        removeAllWindows();
+
+        final Task task = service.mTaskIdToTask.get(groupId);
+        if (task != null) {
+            if (!task.removeAppToken(this)) {
+                Slog.e(WindowManagerService.TAG, "removeAppFromTaskLocked: token=" + this
+                        + " not found.");
+            }
+            task.mStack.mExitingAppTokens.remove(this);
+        }
+    }
+
     @Override
     void removeAllWindows() {
         for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
@@ -266,8 +280,10 @@
                 Slog.w(WindowManagerService.TAG, "removeAllWindows: removing win=" + win);
             }
 
-            win.mService.removeWindowLocked(win.mSession, win);
+            service.removeWindowLocked(win.mSession, win);
         }
+        allAppWindows.clear();
+        windows.clear();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 45d0921..e3b53b0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -329,15 +329,9 @@
                     for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                         AppWindowToken wtoken = tokens.get(tokenNdx);
                         if (wtoken.mIsExiting) {
-                            stack.mExitingAppTokens.remove(wtoken);
-                            wtoken.mIsExiting = false;
-                            mService.removeAppFromTaskLocked(wtoken);
+                            wtoken.removeAppFromTaskLocked();
                         }
                     }
-                    if (task.mDeferRemoval) {
-                        task.mDeferRemoval = false;
-                        mService.removeTaskLocked(task);
-                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b49b87c..80d727d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,9 +17,11 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.WindowManagerService.TAG;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 
 import android.util.EventLog;
 import android.util.Slog;
+import com.android.server.EventLogTags;
 
 class Task {
     TaskStack mStack;
@@ -27,12 +29,14 @@
     final int taskId;
     final int mUserId;
     boolean mDeferRemoval = false;
+    final WindowManagerService mService;
 
-    Task(AppWindowToken wtoken, TaskStack stack, int userId) {
+    Task(AppWindowToken wtoken, TaskStack stack, int userId, WindowManagerService service) {
         taskId = wtoken.groupId;
         mAppTokens.add(wtoken);
         mStack = stack;
         mUserId = userId;
+        mService = service;
     }
 
     DisplayContent getDisplayContent() {
@@ -51,11 +55,27 @@
         mDeferRemoval = false;
     }
 
+    void removeLocked() {
+        if (!mAppTokens.isEmpty() && mStack.isAnimating()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
+            mDeferRemoval = true;
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
+        mDeferRemoval = false;
+        mStack.removeTask(this);
+        mService.mTaskIdToTask.delete(taskId);
+    }
+
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
             EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
                     "removeAppToken: last token");
+            if (mDeferRemoval) {
+                removeLocked();
+            }
         }
         return removed;
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 802cf4b..d6741b3 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -224,6 +224,14 @@
             }
             mDisplayContent.layoutNeeded = true;
         }
+        final int taskId = task.taskId;
+        for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
+            final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
+            if (wtoken.groupId == taskId) {
+                wtoken.mIsExiting = false;
+                mExitingAppTokens.remove(appNdx);
+            }
+        }
     }
 
     void attachDisplayContent(DisplayContent displayContent) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 36ef88e..2c05e93 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3620,7 +3620,7 @@
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(atoken, stack, userId);
+        Task task = new Task(atoken, stack, userId, this);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */);
         return task;
@@ -4778,17 +4778,6 @@
         }
     }
 
-    void removeAppFromTaskLocked(AppWindowToken wtoken) {
-        wtoken.removeAllWindows();
-
-        final Task task = mTaskIdToTask.get(wtoken.groupId);
-        if (task != null) {
-            if (!task.removeAppToken(wtoken)) {
-                Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found.");
-            }
-        }
-    }
-
     @Override
     public void removeAppToken(IBinder token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4836,7 +4825,7 @@
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
-                    removeAppFromTaskLocked(wtoken);
+                    wtoken.removeAppFromTaskLocked();
                 }
 
                 wtoken.removed = true;
@@ -5112,30 +5101,6 @@
         mStackIdToStack.remove(stackId);
     }
 
-    void removeTaskLocked(Task task) {
-        final int taskId = task.taskId;
-        final TaskStack stack = task.mStack;
-        if (!task.mAppTokens.isEmpty() && 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;
-        stack.removeTask(task);
-        mTaskIdToTask.delete(task.taskId);
-
-        final ArrayList<AppWindowToken> exitingApps = stack.mExitingAppTokens;
-        for (int appNdx = exitingApps.size() - 1; appNdx >= 0; --appNdx) {
-            final AppWindowToken wtoken = exitingApps.get(appNdx);
-            if (wtoken.groupId == taskId) {
-                wtoken.mIsExiting = false;
-                exitingApps.remove(appNdx);
-            }
-        }
-    }
-
     public void removeTask(int taskId) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -5143,7 +5108,7 @@
                 if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
                 return;
             }
-            removeTaskLocked(task);
+            task.removeLocked();
         }
     }
 
@@ -9979,12 +9944,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    removeAppFromTaskLocked(token);
-                    exitingAppTokens.remove(i);
-                    final Task task = mTaskIdToTask.get(token.groupId);
-                    if (task != null && task.mDeferRemoval && task.mAppTokens.isEmpty()) {
-                        removeTaskLocked(task);
-                    }
+                    token.removeAppFromTaskLocked();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 1a672e68..bbeee8c 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -85,6 +85,7 @@
                     "removeAllWindows: removing win=" + win);
             win.mService.removeWindowLocked(win.mSession, win);
         }
+        windows.clear();
     }
 
     void dump(PrintWriter pw, String prefix) {