Migrate AppWindowToken lists into DisplayContent.

In preparation for converting ActivityManager control to a task-based
interface the AppWindowTokens are being stored per-display.

Change-Id: Ie5e355219554523f5e56eaef138d382975cf1682
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e0046ad..55c2e2a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -194,7 +194,7 @@
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
     static final boolean DEBUG_MU = localLOGV || false;
     static final boolean DEBUG_IMMERSIVE = localLOGV || false;
-    static final boolean VALIDATE_TOKENS = false;
+    static final boolean VALIDATE_TOKENS = true;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
     // Control over CPU and battery monitoring.
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index de9dda4..2c8a698 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -22,6 +22,7 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
+import com.android.server.am.ActivityRecord.Token;
 import com.android.server.wm.AppTransition;
 
 import android.app.Activity;
@@ -157,7 +158,7 @@
     /**
      * Used for validating app tokens with window manager.
      */
-    final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
+    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
 
     /**
      * List of running activities, sorted by recent usage.
@@ -1959,8 +1960,17 @@
     final void validateAppTokensLocked() {
         mValidateAppTokens.clear();
         mValidateAppTokens.ensureCapacity(mHistory.size());
+        int taskId = Integer.MIN_VALUE;
+        TaskGroup task = null;
         for (int i=0; i<mHistory.size(); i++) {
-            mValidateAppTokens.add(mHistory.get(i).appToken);
+            final ActivityRecord r = mHistory.get(i);
+            if (taskId != r.task.taskId) {
+                taskId = r.task.taskId;
+                task = new TaskGroup();
+                task.taskId = taskId;
+                mValidateAppTokens.add(task);
+            }
+            task.tokens.add(r.appToken);
         }
         mService.mWindowManager.validateAppTokens(mValidateAppTokens);
     }
diff --git a/services/java/com/android/server/am/TaskGroup.java b/services/java/com/android/server/am/TaskGroup.java
new file mode 100644
index 0000000..7574103
--- /dev/null
+++ b/services/java/com/android/server/am/TaskGroup.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.view.IApplicationToken;
+
+import java.util.ArrayList;
+
+public class TaskGroup {
+    public int taskId = -1;
+    public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
+}
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 0ada604..8fd5209 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -30,6 +30,10 @@
 import android.view.WindowManager;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+
+class AppTokenList extends ArrayList<AppWindowToken> {
+}
 
 /**
  * Version of WindowToken that is specifically for a particular application (or
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 59e4b0e..906ea57 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
@@ -33,6 +34,7 @@
  * WindowManagerService.mWindowMap.
  */
 class DisplayContent {
+//    private final static String TAG = "DisplayContent";
 
     /** Unique identifier of this stack. */
     private final int mDisplayId;
@@ -67,6 +69,38 @@
     final boolean isDefaultDisplay;
 
     /**
+     * List controlling the ordering of windows in different applications which must
+     * be kept in sync with ActivityManager.
+     */
+    final AppTokenList mAppTokens = new AppTokenList();
+
+    /**
+     * AppWindowTokens in the Z order they were in at the start of an animation. Between
+     * animations this list is maintained in the exact order of mAppTokens. If tokens
+     * are added to mAppTokens during an animation an attempt is made to insert them at the same
+     * logical location in this list. Note that this list is always in sync with mWindows.
+     */
+    AppTokenList mAnimatingAppTokens = new AppTokenList();
+
+    /**
+     * Window tokens that are in the process of exiting, but still
+     * on screen for animations.
+     */
+    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+
+    /**
+     * Application tokens that are in the process of exiting, but still
+     * on screen for animations.
+     */
+    final AppTokenList mExitingAppTokens = new AppTokenList();
+
+    /**
+     * Sorted most recent at top, oldest at [0].
+     */
+//    ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
+    SparseArray<TaskList> mTaskIdToTaskList = new SparseArray<TaskList>();
+
+    /**
      * @param display May not be null.
      */
     DisplayContent(Display display) {
@@ -96,6 +130,71 @@
         mDisplay.getDisplayInfo(mDisplayInfo);
     }
 
+    /**
+     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
+     * @param addPos The location the token was inserted into in mAppTokens.
+     * @param atoken The token to insert.
+     */
+    void addAppToken(final int addPos, final AppWindowToken atoken) {
+        mAppTokens.add(addPos, atoken);
+
+        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
+            // It was inserted into the beginning or end of mAppTokens. Honor that.
+            mAnimatingAppTokens.add(addPos, atoken);
+        } else {
+            // Find the item immediately above the mAppTokens insertion point and put the token
+            // immediately below that one in mAnimatingAppTokens.
+            final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
+            mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
+        }
+
+        TaskList task = mTaskIdToTaskList.get(atoken.groupId);
+        if (task == null) {
+            mTaskIdToTaskList.put(atoken.groupId, new TaskList(atoken));
+        }
+    }
+
+    void removeAppToken(final AppWindowToken wtoken) {
+        mAppTokens.remove(wtoken);
+        mAnimatingAppTokens.remove(wtoken);
+        final int taskId = wtoken.groupId;
+        final TaskList task = mTaskIdToTaskList.get(taskId);
+        if (task != null) {
+            AppTokenList appTokens = task.mAppTokens;
+            appTokens.remove(wtoken);
+            if (appTokens.size() == 0) {
+                mTaskIdToTaskList.delete(taskId);
+            }
+        }
+    }
+
+    void refillAnimatingAppTokens() {
+        mAnimatingAppTokens.clear();
+        mAnimatingAppTokens.addAll(mAppTokens);
+    }
+
+    void setAppTaskId(AppWindowToken wtoken, int newTaskId) {
+        final int taskId = wtoken.groupId;
+        TaskList task = mTaskIdToTaskList.get(taskId);
+        if (task != null) {
+            AppTokenList appTokens = task.mAppTokens;
+            appTokens.remove(wtoken);
+            if (appTokens.size() == 0) {
+                mTaskIdToTaskList.delete(taskId);
+            }
+        }
+
+        task = mTaskIdToTaskList.get(newTaskId);
+        if (task == null) {
+            task = new TaskList(wtoken);
+            mTaskIdToTaskList.put(newTaskId, task);
+        } else {
+            task.mAppTokens.add(wtoken);
+        }
+
+        wtoken.groupId = newTaskId;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
         final String subPrefix = "  " + prefix;
@@ -119,7 +218,48 @@
             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-        pw.print(subPrefix); pw.print("layoutNeeded="); pw.print(layoutNeeded);
+            if (mAppTokens.size() > 0) {
+                pw.println();
+                pw.println("  Application tokens in Z order:");
+                for (int i=mAppTokens.size()-1; i>=0; i--) {
+                    pw.print("  App #"); pw.print(i);
+                            pw.print(' '); pw.print(mAppTokens.get(i)); pw.println(":");
+                    mAppTokens.get(i).dump(pw, "    ");
+                }
+            }
+            if (mExitingTokens.size() > 0) {
+                pw.println();
+                pw.println("  Exiting tokens:");
+                for (int i=mExitingTokens.size()-1; i>=0; i--) {
+                    WindowToken token = mExitingTokens.get(i);
+                    pw.print("  Exiting #"); pw.print(i);
+                    pw.print(' '); pw.print(token);
+                    pw.println(':');
+                    token.dump(pw, "    ");
+                }
+            }
+            if (mExitingAppTokens.size() > 0) {
+                pw.println();
+                pw.println("  Exiting application tokens:");
+                for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+                    WindowToken token = mExitingAppTokens.get(i);
+                    pw.print("  Exiting App #"); pw.print(i);
+                      pw.print(' '); pw.print(token);
+                      pw.println(':');
+                      token.dump(pw, "    ");
+                }
+            }
+            if (mTaskIdToTaskList.size() > 0) {
+                pw.println();
+                for (int i = 0; i < mTaskIdToTaskList.size(); ++i) {
+                    pw.print("  TaskList #"); pw.print(i);
+                      pw.print(" taskId="); pw.println(mTaskIdToTaskList.keyAt(i));
+                    pw.print("    mAppTokens=");
+                      pw.println(mTaskIdToTaskList.valueAt(i).mAppTokens);
+                    pw.println();
+                }
+            }
+        pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
         pw.println();
     }
 }
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
new file mode 100644
index 0000000..fe12b98
--- /dev/null
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import com.android.server.am.TaskGroup;
+
+class TaskList extends TaskGroup {
+//    private final String TAG = "TaskGroup";
+    AppTokenList mAppTokens = new AppTokenList();
+
+    TaskList(AppWindowToken wtoken) {
+        taskId = wtoken.groupId;
+        tokens.add(wtoken.appToken);
+        mAppTokens.add(wtoken);
+    }
+}
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index d42221e..546bf2f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -171,9 +171,10 @@
         }
     }
 
-    private void updateAppWindowsLocked() {
+    private void updateAppWindowsLocked(int displayId) {
         int i;
-        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        final AppTokenList appTokens = displayContent.mAnimatingAppTokens;
         final int NAT = appTokens.size();
         for (i=0; i<NAT; i++) {
             final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
@@ -190,9 +191,10 @@
             }
         }
 
-        final int NEAT = mService.mExitingAppTokens.size();
+        final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        final int NEAT = exitingAppTokens.size();
         for (i=0; i<NEAT; i++) {
-            final AppWindowAnimator appAnimator = mService.mExitingAppTokens.get(i).mAppAnimator;
+            final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -453,10 +455,11 @@
 
     /** See if any windows have been drawn, so they (and others associated with them) can now be
      *  shown. */
-    private void testTokenMayBeDrawnLocked() {
+    private void testTokenMayBeDrawnLocked(int displayId) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final AppTokenList appTokens =
+                mService.getDisplayContentLocked(displayId).mAnimatingAppTokens;
         final int NT = appTokens.size();
         for (int i=0; i<NT; i++) {
             AppWindowToken wtoken = appTokens.get(i);
@@ -529,11 +532,10 @@
         Surface.openTransaction();
         Surface.setAnimationTransaction();
         try {
-            updateAppWindowsLocked();
-
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
+                updateAppWindowsLocked(displayId);
                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                 final ScreenRotationAnimation screenRotationAnimation =
@@ -559,10 +561,11 @@
                 }
             }
 
-            testTokenMayBeDrawnLocked();
-
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
+
+                testTokenMayBeDrawnLocked(displayId);
+
                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                 final ScreenRotationAnimation screenRotationAnimation =
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index ff2dc0f..6e8130e 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -53,6 +53,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.am.TaskGroup;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.power.PowerManagerService;
@@ -179,7 +180,7 @@
     static final boolean DEBUG_INPUT_METHOD = false;
     static final boolean DEBUG_VISIBILITY = false;
     static final boolean DEBUG_WINDOW_MOVEMENT = false;
-    static final boolean DEBUG_TOKEN_MOVEMENT = false;
+    static final boolean DEBUG_TOKEN_MOVEMENT = true;
     static final boolean DEBUG_ORIENTATION = false;
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
@@ -330,32 +331,6 @@
             new HashMap<IBinder, WindowToken>();
 
     /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
-
-    /**
-     * List controlling the ordering of windows in different applications which must
-     * be kept in sync with ActivityManager.
-     */
-    final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
-
-    /**
-     * AppWindowTokens in the Z order they were in at the start of an animation. Between
-     * animations this list is maintained in the exact order of mAppTokens. If tokens
-     * are added to mAppTokens during an animation an attempt is made to insert them at the same
-     * logical location in this list. Note that this list is always in sync with mWindows.
-     */
-    ArrayList<AppWindowToken> mAnimatingAppTokens = new ArrayList<AppWindowToken>();
-
-    /**
-     * Application tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
-
-    /**
      * List of window tokens that have finished starting their application,
      * and now need to have the policy remove their windows.
      */
@@ -438,8 +413,10 @@
 
     String mLastANRState;
 
-    /** All DisplayDontents in the world, kept here */
+    /** All DisplayContents in the world, kept here */
     private SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>();
+    private SparseArray<DisplayContent> mTaskIdToDisplayContents =
+            new SparseArray<DisplayContent>();
 
     int mRotation = 0;
     int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -949,10 +926,11 @@
                         + client.asBinder() + " (token=" + token + ")");
                     // Figure out where the window should go, based on the
                     // order of applications.
-                    final int NA = mAnimatingAppTokens.size();
+                    AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
+                    final int NA = animatingAppTokens.size();
                     WindowState pos = null;
                     for (i=NA-1; i>=0; i--) {
-                        AppWindowToken t = mAnimatingAppTokens.get(i);
+                        AppWindowToken t = animatingAppTokens.get(i);
                         if (t == token) {
                             i--;
                             break;
@@ -988,8 +966,8 @@
                         // Continue looking down until we find the first
                         // token that has windows on this display.
                         while (i >= 0) {
-                            AppWindowToken t = mAnimatingAppTokens.get(i);
-                            tokenWindowList = getTokenWindowsOnDisplay(t, win.mDisplayContent);
+                            AppWindowToken t = animatingAppTokens.get(i);
+                            tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
                             final int NW = tokenWindowList.size();
                             if (NW > 0) {
                                 pos = tokenWindowList.get(NW-1);
@@ -3082,28 +3060,56 @@
     // Application Window Tokens
     // -------------------------------------------------------------
 
-    public void validateAppTokens(List<IBinder> tokens) {
-        int v = tokens.size()-1;
-        int m = mAppTokens.size()-1;
-        while (v >= 0 && m >= 0) {
-            AppWindowToken atoken = mAppTokens.get(m);
-            if (atoken.removed) {
+    public void validateAppTokens(List<TaskGroup> tasks) {
+        int t = tasks.size() - 1;
+        if (t < 0) {
+            Slog.w(TAG, "validateAppTokens: empty task list");
+            return;
+        }
+
+        TaskGroup task = tasks.get(0);
+        int taskId = task.taskId;
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.w(TAG, "validateAppTokens: no Display for taskId=" + taskId);
+            return;
+        }
+        AppTokenList appTokens = displayContent.mAppTokens;
+        int m = appTokens.size() - 1;
+
+        for ( ; t >= 0; --t) {
+            task = tasks.get(t);
+            List<IApplicationToken> tokens = task.tokens;
+            int v = task.tokens.size() - 1;
+
+            DisplayContent lastDisplayContent = displayContent;
+            displayContent = mTaskIdToDisplayContents.get(taskId);
+            if (displayContent != lastDisplayContent) {
+                Slog.w(TAG, "validateAppTokens: displayContent changed in TaskGroup list!");
+                return;
+            }
+
+            while (v >= 0 && m >= 0) {
+                AppWindowToken atoken = appTokens.get(m);
+                if (atoken.removed) {
+                    m--;
+                    continue;
+                }
+                if (tokens.get(v) != atoken.token) {
+                    Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
+                          + " @ " + v + ", internal is " + atoken.token + " @ " + m);
+                }
+                v--;
                 m--;
-                continue;
             }
-            if (tokens.get(v) != atoken.token) {
-                Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
-                      + " @ " + v + ", internal is " + atoken.token + " @ " + m);
+            while (v >= 0) {
+                Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
+                v--;
             }
-            v--;
-            m--;
         }
-        while (v >= 0) {
-            Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
-            v--;
-        }
+
         while (m >= 0) {
-            AppWindowToken atoken = mAppTokens.get(m);
+            AppWindowToken atoken = appTokens.get(m);
             if (!atoken.removed) {
                 Slog.w(TAG, "Invalid internal atoken: " + atoken.token + " @ " + m);
             }
@@ -3171,6 +3177,7 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
+            DisplayContent displayContent = null;
             WindowToken wtoken = mTokenMap.remove(token);
             if (wtoken != null) {
                 boolean delayed = false;
@@ -3180,6 +3187,7 @@
 
                     for (int i=0; i<N; i++) {
                         WindowState win = wtoken.windows.get(i);
+                        displayContent = win.mDisplayContent;
 
                         if (win.mWinAnimator.isAnimating()) {
                             delayed = true;
@@ -3189,13 +3197,12 @@
                             win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
                                     false);
                             //TODO (multidisplay): Magnification is supported only for the default
-                            if (mDisplayMagnifier != null
-                                    && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
+                            if (mDisplayMagnifier != null && win.isDefaultDisplay()) {
                                 mDisplayMagnifier.onWindowTransitionLocked(win,
                                         WindowManagerPolicy.TRANSIT_EXIT);
                             }
                             changed = true;
-                            win.mDisplayContent.layoutNeeded = true;
+                            displayContent.layoutNeeded = true;
                         }
                     }
 
@@ -3208,7 +3215,7 @@
                     }
 
                     if (delayed) {
-                        mExitingTokens.add(wtoken);
+                        displayContent.mExitingTokens.add(wtoken);
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
@@ -3222,27 +3229,9 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    /**
-     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
-     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
-     * @param addPos The location the token was inserted into in mAppTokens.
-     * @param atoken The token to insert.
-     */
-    private void addAppTokenToAnimating(final int addPos, final AppWindowToken atoken) {
-        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
-            // It was inserted into the beginning or end of mAppTokens. Honor that.
-            mAnimatingAppTokens.add(addPos, atoken);
-            return;
-        }
-        // Find the item immediately above the mAppTokens insertion point and put the token
-        // immediately below that one in mAnimatingAppTokens.
-        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
-        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
-    }
-
     @Override
     public void addAppToken(int addPos, IApplicationToken token,
-            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
+            int taskId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3270,15 +3259,21 @@
             }
             atoken = new AppWindowToken(this, token);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-            atoken.groupId = groupId;
+            atoken.groupId = taskId;
             atoken.appFullscreen = fullscreen;
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                     + " at " + addPos);
-            mAppTokens.add(addPos, atoken);
-            addAppTokenToAnimating(addPos, atoken);
+
+            DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+            if (displayContent == null) {
+                displayContent = getDefaultDisplayContentLocked();
+                mTaskIdToDisplayContents.put(taskId, displayContent);
+            }
+            displayContent.addAppToken(addPos, atoken);
             mTokenMap.put(token.asBinder(), atoken);
+            mTaskIdToDisplayContents.put(taskId, displayContent);
 
             // Application tokens start out hidden.
             atoken.hidden = true;
@@ -3301,7 +3296,7 @@
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
-            atoken.groupId = groupId;
+            mTaskIdToDisplayContents.get(atoken.groupId).setAppTaskId(atoken, groupId);
         }
     }
 
@@ -3347,8 +3342,11 @@
         boolean findingBehind = false;
         boolean haveGroup = false;
         boolean lastFullscreen = false;
-        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
-            AppWindowToken atoken = mAppTokens.get(pos);
+        // TODO: Multi window.
+        DisplayContent displayContent = getDefaultDisplayContentLocked();
+        AppTokenList appTokens = displayContent.mAppTokens;
+        for (int pos = appTokens.size() - 1; pos >= 0; pos--) {
+            AppWindowToken atoken = appTokens.get(pos);
 
             if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken);
 
@@ -4261,7 +4259,7 @@
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
-                    mExitingAppTokens.add(wtoken);
+                    mTaskIdToDisplayContents.get(wtoken.groupId).mExitingAppTokens.add(wtoken);
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
@@ -4271,8 +4269,7 @@
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
-                mAppTokens.remove(wtoken);
-                mAnimatingAppTokens.remove(wtoken);
+                mTaskIdToDisplayContents.get(wtoken.groupId).removeAppToken(wtoken);
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4324,14 +4321,26 @@
     }
 
     void dumpAppTokensLocked() {
-        for (int i=mAppTokens.size()-1; i>=0; i--) {
-            Slog.v(TAG, "  #" + i + ": " + mAppTokens.get(i).token);
+        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            DisplayContent displayContent = iterator.next();
+            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
+            AppTokenList appTokens = displayContent.mAppTokens;
+            for (int i=appTokens.size()-1; i>=0; i--) {
+                Slog.v(TAG, "  #" + i + ": " + appTokens.get(i).token);
+            }
         }
     }
 
     void dumpAnimatingAppTokensLocked() {
-        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
-            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
+        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            DisplayContent displayContent = iterator.next();
+            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
+            AppTokenList appTokens = displayContent.mAnimatingAppTokens;
+            for (int i=appTokens.size()-1; i>=0; i--) {
+                Slog.v(TAG, "  #" + i + ": " + appTokens.get(i).token);
+            }
         }
     }
 
@@ -4344,10 +4353,11 @@
         }
     }
 
-    private int findWindowOffsetLocked(WindowList windows, int tokenPos) {
+    private int findWindowOffsetLocked(DisplayContent displayContent, int tokenPos) {
+        final WindowList windows = displayContent.getWindowList();
         final int NW = windows.size();
 
-        if (tokenPos >= mAnimatingAppTokens.size()) {
+        if (tokenPos >= displayContent.mAnimatingAppTokens.size()) {
             int i = NW;
             while (i > 0) {
                 i--;
@@ -4358,10 +4368,11 @@
             }
         }
 
+        final AppTokenList appTokens = displayContent.mAppTokens;
         while (tokenPos > 0) {
             // Find the first app token below the new position that has
             // a window displayed.
-            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
+            final AppWindowToken wtoken = appTokens.get(tokenPos-1);
             if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
                     + tokenPos + " -- " + wtoken.token);
             if (wtoken.sendingToBottom) {
@@ -4455,28 +4466,29 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
             if (DEBUG_REORDER) dumpAppTokensLocked();
             final AppWindowToken wtoken = findAppWindowToken(token);
-            final int oldIndex = mAppTokens.indexOf(wtoken);
+            DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
+            final AppTokenList appTokens = displayContent.mAppTokens;
+            final AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
+            final int oldIndex = appTokens.indexOf(wtoken);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
                     "Start moving token " + wtoken + " initially at "
                     + oldIndex);
             if (oldIndex > index && mAppTransition.isTransitionSet()) {
                 // animation towards back has not started, copy old list for duration of animation.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
+                displayContent.refillAnimatingAppTokens();
             }
-            if (wtoken == null || !mAppTokens.remove(wtoken)) {
+            if (wtoken == null || !appTokens.remove(wtoken)) {
                 Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
                       + token + " (" + wtoken + ")");
                 return;
             }
-            mAppTokens.add(index, wtoken);
+            appTokens.add(index, wtoken);
             if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
             else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
             if (DEBUG_REORDER) dumpAppTokensLocked();
             if (!mAppTransition.isTransitionSet()) {
                 // Not animating, bring animating app list in line with mAppTokens.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
+                displayContent.refillAnimatingAppTokens();
 
                 // Bring window ordering, window focus and input window in line with new app token
                 final long origId = Binder.clearCallingIdentity();
@@ -4487,9 +4499,8 @@
                     if (DEBUG_REORDER) dumpWindowsLocked();
                     DisplayContentsIterator iterator = new DisplayContentsIterator();
                     while(iterator.hasNext()) {
-                        final DisplayContent displayContent = iterator.next();
-                        final WindowList windows = displayContent.getWindowList();
-                        final int pos = findWindowOffsetLocked(windows, index);
+                        displayContent = iterator.next();
+                        final int pos = findWindowOffsetLocked(displayContent, index);
                         final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
                         if (pos != newPos) {
                             displayContent.layoutNeeded = true;
@@ -4516,18 +4527,22 @@
         for (int i=0; i<N; i++) {
             IBinder token = tokens.get(i);
             final AppWindowToken wtoken = findAppWindowToken(token);
-            if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                    "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken));
-            if (!mAppTokens.remove(wtoken)) {
-                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
-                      + token + " (" + wtoken + ")");
-                i--;
-                N--;
+            if (wtoken != null) {
+                final DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
+                if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Temporarily removing "
+                        + wtoken + " from " + displayContent.mAppTokens.indexOf(wtoken));
+                if (!displayContent.mAppTokens.remove(wtoken)) {
+                    Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
+                            + token + " (" + wtoken + ")");
+                    i--;
+                    N--;
+                }
             }
         }
     }
 
-    private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
+    private void moveAppWindowsLocked(List<IBinder> tokens, DisplayContent displayContent,
+            int tokenPos) {
         // First remove all of the windows from the list.
         final int N = tokens.size();
         int i;
@@ -4539,26 +4554,21 @@
         }
 
         // And now add them back at the correct place.
-        DisplayContentsIterator iterator = new DisplayContentsIterator();
-        while (iterator.hasNext()) {
-            final DisplayContent displayContent = iterator.next();
-            final WindowList windows = displayContent.getWindowList();
-            // Where to start adding?
-            int pos = findWindowOffsetLocked(windows, tokenPos);
-            for (i=0; i<N; i++) {
-                WindowToken token = mTokenMap.get(tokens.get(i));
-                if (token != null) {
-                    final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
-                    if (newPos != pos) {
-                        displayContent.layoutNeeded = true;
-                    }
-                    pos = newPos;
+        // Where to start adding?
+        int pos = findWindowOffsetLocked(displayContent, tokenPos);
+        for (i=0; i<N; i++) {
+            WindowToken token = mTokenMap.get(tokens.get(i));
+            if (token != null) {
+                final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
+                if (newPos != pos) {
+                    displayContent.layoutNeeded = true;
                 }
+                pos = newPos;
             }
-            if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                    false /*updateInputWindows*/)) {
-                assignLayersLocked(windows);
-            }
+        }
+        if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+            false /*updateInputWindows*/)) {
+            assignLayersLocked(displayContent.getWindowList());
         }
 
         mInputMonitor.setUpdateInputWindowsNeededLw();
@@ -4580,23 +4590,28 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
+            DisplayContent displayContent = null;
             removeAppTokensLocked(tokens);
             final int N = tokens.size();
             for (int i=0; i<N; i++) {
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
                 if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
-                            "Adding next to top: " + wt);
-                    mAppTokens.add(wt);
+                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) {
+                        Slog.v(TAG, "Adding next to top: " + wt);
+                        if (displayContent != null &&
+                                displayContent != mTaskIdToDisplayContents.get(wt.groupId)) Slog.e(
+                                    TAG, "moveAppTokensToTop: Not all tokens on same display");
+                    }
+                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
+                    displayContent.mAppTokens.add(wt);
                     if (mAppTransition.isTransitionSet()) {
                         wt.sendingToBottom = false;
                     }
                 }
             }
 
-            mAnimatingAppTokens.clear();
-            mAnimatingAppTokens.addAll(mAppTokens);
-            moveAppWindowsLocked(tokens, mAppTokens.size());
+            displayContent.refillAnimatingAppTokens();
+            moveAppWindowsLocked(tokens, displayContent, displayContent.mAppTokens.size());
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -4610,20 +4625,29 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
+            DisplayContent displayContent = null;
             final int N = tokens.size();
             if (N > 0) {
                 // animating towards back, hang onto old list for duration of animation.
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
+                AppWindowToken wt = findAppWindowToken(tokens.get(0));
+                if (wt != null) {
+                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
+                    displayContent.refillAnimatingAppTokens();
+                }
             }
             removeAppTokensLocked(tokens);
             int pos = 0;
             for (int i=0; i<N; i++) {
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
                 if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                            "Adding next to bottom: " + wt + " at " + pos);
-                    mAppTokens.add(pos, wt);
+                    if (DEBUG_TOKEN_MOVEMENT) {
+                        Slog.v(TAG, "Adding next to bottom: " + wt + " at " + pos);
+                        if (displayContent != null &&
+                                displayContent != mTaskIdToDisplayContents.get(wt.groupId)) Slog.e(
+                                    TAG, "moveAppTokensToBottom: Not all tokens on same display");
+                    }
+                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
+                    displayContent.mAppTokens.add(pos, wt);
                     if (mAppTransition.isTransitionSet()) {
                         wt.sendingToBottom = true;
                     }
@@ -4631,9 +4655,8 @@
                 }
             }
 
-            mAnimatingAppTokens.clear();
-            mAnimatingAppTokens.addAll(mAppTokens);
-            moveAppWindowsLocked(tokens, 0);
+            displayContent.refillAnimatingAppTokens();
+            moveAppWindowsLocked(tokens, displayContent, 0);
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -6875,8 +6898,7 @@
                         if (mAppTransition.isTransitionSet()) {
                             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
                             mAppTransition.setTimeout();
-                            mAnimatingAppTokens.clear();
-                            mAnimatingAppTokens.addAll(mAppTokens);
+                            getDefaultDisplayContentLocked().refillAnimatingAppTokens();
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -6921,10 +6943,12 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
-                        int i = mAppTokens.size();
+                        DisplayContent displayContent = getDefaultDisplayContentLocked();
+                        AppTokenList appTokens = displayContent.mAppTokens;
+                        int i = appTokens.size();
                         while (i > 0) {
                             i--;
-                            AppWindowToken tok = mAppTokens.get(i);
+                            AppWindowToken tok = appTokens.get(i);
                             if (tok.mAppAnimator.freezingScreen) {
                                 Slog.w(TAG, "Force clearing freeze: " + tok);
                                 unsetAppFreezingScreenLocked(tok, true, true);
@@ -7378,15 +7402,17 @@
         // in the main app list, but still have windows shown.  We put them
         // in the back because now that the animation is over we no longer
         // will care about them.
-        int NT = mExitingAppTokens.size();
+        AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        int NT = exitingAppTokens.size();
         for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
+            i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
         }
 
         // And add in the still active app tokens in Z order.
-        NT = mAnimatingAppTokens.size();
+        AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
+        NT = animatingAppTokens.size();
         for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
+            i = reAddAppWindowsLocked(displayContent, i, animatingAppTokens.get(j));
         }
 
         i -= lastBelow;
@@ -8052,11 +8078,12 @@
 
         mAppTransition.setIdle();
         // Restore window app tokens to the ActivityManager views
-        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
-            mAnimatingAppTokens.get(i).sendingToBottom = false;
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        final AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
+        for (int i = animatingAppTokens.size() - 1; i >= 0; i--) {
+            animatingAppTokens.get(i).sendingToBottom = false;
         }
-        mAnimatingAppTokens.clear();
-        mAnimatingAppTokens.addAll(mAppTokens);
+        displayContent.refillAnimatingAppTokens();
         rebuildAppWindowListLocked();
 
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
@@ -8210,10 +8237,10 @@
         }
     }
 
-    private void updateAllDrawnLocked() {
+    private void updateAllDrawnLocked(DisplayContent displayContent) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
+        final AppTokenList appTokens = displayContent.mAnimatingAppTokens;
         final int NT = appTokens.size();
         for (int i=0; i<NT; i++) {
             AppWindowToken wtoken = appTokens.get(i);
@@ -8248,13 +8275,17 @@
         }
 
         // Initialize state of exiting tokens.
-        for (i=mExitingTokens.size()-1; i>=0; i--) {
-            mExitingTokens.get(i).hasVisible = false;
-        }
+        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            final DisplayContent displayContent = iterator.next();
+            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingTokens.get(i).hasVisible = false;
+            }
 
-        // Initialize state of exiting applications.
-        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
-            mExitingAppTokens.get(i).hasVisible = false;
+            // Initialize state of exiting applications.
+            for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingAppTokens.get(i).hasVisible = false;
+            }
         }
 
         mInnerFields.mHoldScreen = null;
@@ -8283,10 +8314,10 @@
             }
 
             boolean focusDisplayed = false;
-            boolean updateAllDrawn = false;
 
-            DisplayContentsIterator iterator = new DisplayContentsIterator();
+            iterator = new DisplayContentsIterator();
             while (iterator.hasNext()) {
+                boolean updateAllDrawn = false;
                 final DisplayContent displayContent = iterator.next();
                 WindowList windows = displayContent.getWindowList();
                 DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -8530,10 +8561,10 @@
                 if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
                     stopDimmingLocked(displayId);
                 }
-            }
 
-            if (updateAllDrawn) {
-                updateAllDrawnLocked();
+                if (updateAllDrawn) {
+                    updateAllDrawnLocked(displayContent);
+                }
             }
 
             if (focusDisplayed) {
@@ -8678,30 +8709,36 @@
         }
 
         // Time to remove any exiting tokens?
-        for (i=mExitingTokens.size()-1; i>=0; i--) {
-            WindowToken token = mExitingTokens.get(i);
-            if (!token.hasVisible) {
-                mExitingTokens.remove(i);
-                if (token.windowType == TYPE_WALLPAPER) {
-                    mWallpaperTokens.remove(token);
+        iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            final DisplayContent displayContent = iterator.next();
+            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
+            for (i = exitingTokens.size() - 1; i >= 0; i--) {
+                WindowToken token = exitingTokens.get(i);
+                if (!token.hasVisible) {
+                    exitingTokens.remove(i);
+                    if (token.windowType == TYPE_WALLPAPER) {
+                        mWallpaperTokens.remove(token);
+                    }
                 }
             }
-        }
 
-        // Time to remove any exiting applications?
-        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
-            AppWindowToken token = mExitingAppTokens.get(i);
-            if (!token.hasVisible && !mClosingApps.contains(token)) {
-                // 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
-                token.mAppAnimator.clearAnimation();
-                token.mAppAnimator.animating = false;
-                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                        "performLayout: App token exiting now removed" + token);
-                mAppTokens.remove(token);
-                mAnimatingAppTokens.remove(token);
-                mExitingAppTokens.remove(i);
+            // Time to remove any exiting applications?
+            AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
+                AppWindowToken token = exitingAppTokens.get(i);
+                if (!token.hasVisible && !mClosingApps.contains(token)) {
+                    // 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
+                    token.mAppAnimator.clearAnimation();
+                    token.mAppAnimator.animating = false;
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
+                            "performLayout: App token exiting now removed" + token);
+                    displayContent.mAppTokens.remove(token);
+                    displayContent.mAnimatingAppTokens.remove(token);
+                    exitingAppTokens.remove(i);
+                }
             }
         }
 
@@ -8721,7 +8758,7 @@
             defaultDisplay.layoutNeeded = true;
         }
 
-        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        iterator = new DisplayContentsIterator();
         while (iterator.hasNext()) {
             DisplayContent displayContent = iterator.next();
             if (displayContent.pendingLayoutChanges != 0) {
@@ -9136,8 +9173,9 @@
     }
 
     private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
-        int nextAppIndex = mAppTokens.size()-1;
-        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
+        final AppTokenList appTokens = displayContent.mAppTokens;
+        int nextAppIndex = appTokens.size()-1;
+        WindowToken nextApp = nextAppIndex >= 0 ? appTokens.get(nextAppIndex) : null;
 
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
@@ -9173,7 +9211,7 @@
                         return null;
                     }
                     nextAppIndex--;
-                    nextApp = mAppTokens.get(nextAppIndex);
+                    nextApp = appTokens.get(nextAppIndex);
                     if (nextApp == thisApp) {
                         break;
                     }
@@ -9183,7 +9221,7 @@
                     // happen, but if it does we can get totally hosed...
                     // so restart at the original app.
                     nextAppIndex = origAppIndex;
-                    nextApp = mAppTokens.get(nextAppIndex);
+                    nextApp = appTokens.get(nextAppIndex);
                 }
             }
 
@@ -9548,15 +9586,6 @@
                 }
             }
         }
-        if (mAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Application tokens in Z order:");
-            for (int i=mAppTokens.size()-1; i>=0; i--) {
-                pw.print("  App #"); pw.print(i);
-                        pw.print(' '); pw.print(mAppTokens.get(i)); pw.println(":");
-                mAppTokens.get(i).dump(pw, "    ");
-            }
-        }
         if (mFinishedStarting.size() > 0) {
             pw.println();
             pw.println("  Finishing start of application tokens:");
@@ -9572,41 +9601,13 @@
                 }
             }
         }
-        if (mExitingTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting tokens:");
-            for (int i=mExitingTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingTokens.get(i);
-                pw.print("  Exiting #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
-        if (mExitingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingAppTokens.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
-        if (mAppTransition.isRunning() && mAnimatingAppTokens.size() > 0) {
+        final AppTokenList animatingAppTokens =
+                getDefaultDisplayContentLocked().mAnimatingAppTokens;
+        if (mAppTransition.isRunning() && animatingAppTokens.size() > 0) {
             pw.println();
             pw.println("  Application tokens during animation:");
-            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mAnimatingAppTokens.get(i);
+            for (int i=animatingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = animatingAppTokens.get(i);
                 pw.print("  App moving to bottom #"); pw.print(i);
                         pw.print(' '); pw.print(token);
                 if (dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java
index bd0ace8..2267123 100644
--- a/services/java/com/android/server/wm/WindowToken.java
+++ b/services/java/com/android/server/wm/WindowToken.java
@@ -19,7 +19,6 @@
 import android.os.IBinder;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * Container of a set of related windows in the window manager.  Often this