OSDN Git Service

Add AppWindowTokens to TaskList.
authorCraig Mautner <cmautner@google.com>
Mon, 11 Feb 2013 17:39:27 +0000 (09:39 -0800)
committerCraig Mautner <cmautner@google.com>
Tue, 12 Feb 2013 18:52:55 +0000 (10:52 -0800)
- Add/remove/move TaskLists from ActivityStack.
- Further isolate mHistory.
- Cleanup warnings by parameterizing ArrayList.
- Fix previous bugs.

Change-Id: Ife8c7b7347479c70f10467cc384283456149ac50

services/java/com/android/server/am/ActivityManagerService.java
services/java/com/android/server/am/ActivityRecord.java
services/java/com/android/server/am/ActivityStack.java
services/java/com/android/server/wm/DisplayContent.java
services/java/com/android/server/wm/TaskGroup.java [moved from services/java/com/android/server/am/TaskGroup.java with 96% similarity]
services/java/com/android/server/wm/TaskList.java
services/java/com/android/server/wm/WindowManagerService.java

index 9a64a7e..f62c3d3 100644 (file)
@@ -2838,11 +2838,8 @@ public final class ActivityManagerService  extends ActivityManagerNative
             for (int i=0; i<activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing) {
-                    int index = mMainStack.indexOfTokenLocked(r.appToken);
-                    if (index >= 0) {
-                        mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
-                                null, "finish-heavy", true);
-                    }
+                    mMainStack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "finish-heavy", true);
                 }
             }
             
@@ -8001,33 +7998,7 @@ public final class ActivityManagerService  extends ActivityManagerNative
             }
             mMainStack.resumeTopActivityLocked(null);
         } else {
-            ActivityRecord r = mMainStack.topRunningActivityLocked(null);
-            if (r != null && r.app == app) {
-                // If the top running activity is from this crashing
-                // process, then terminate it to avoid getting in a loop.
-                Slog.w(TAG, "  Force finishing activity "
-                        + r.intent.getComponent().flattenToShortString());
-                int index = mMainStack.indexOfActivityLocked(r);
-                r.stack.finishActivityLocked(r, index,
-                        Activity.RESULT_CANCELED, null, "crashed", false);
-                // Also terminate any activities below it that aren't yet
-                // stopped, to avoid a situation where one will get
-                // re-start our crashing activity once it gets resumed again.
-                index--;
-                if (index >= 0) {
-                    r = mMainStack.getActivityAtIndex(index);
-                    if (r.state == ActivityState.RESUMED
-                            || r.state == ActivityState.PAUSING
-                            || r.state == ActivityState.PAUSED) {
-                        if (!r.isHomeActivity || mHomeProcess != r.app) {
-                            Slog.w(TAG, "  Force finishing activity "
-                                    + r.intent.getComponent().flattenToShortString());
-                            r.stack.finishActivityLocked(r, index,
-                                    Activity.RESULT_CANCELED, null, "crashed", false);
-                        }
-                    }
-                }
-            }
+            mMainStack.finishTopRunningActivityLocked(app);
         }
 
         // Bump up the crash count of any services currently running in the proc.
@@ -12364,7 +12335,6 @@ public final class ActivityManagerService  extends ActivityManagerNative
 
     public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
             Intent resultData) {
-        ComponentName dest = destIntent.getComponent();
 
         synchronized (this) {
             ActivityRecord srec = ActivityRecord.forToken(token);
@@ -12372,87 +12342,7 @@ public final class ActivityManagerService  extends ActivityManagerNative
                 return false;
             }
             ActivityStack stack = srec.stack;
-            final int start = stack.indexOfActivityLocked(srec);
-            if (start < 0) {
-                // Current activity is not in history stack; do nothing.
-                return false;
-            }
-            int finishTo = start - 1;
-            ActivityRecord parent = null;
-            boolean foundParentInTask = false;
-            if (dest != null) {
-                TaskRecord tr = srec.task;
-                for (int i = start - 1; i >= 0; i--) {
-                    ActivityRecord r = stack.getActivityAtIndex(i);
-                    if (tr != r.task) {
-                        // Couldn't find parent in the same task; stop at the one above this.
-                        // (Root of current task; in-app "home" behavior)
-                        // Always at least finish the current activity.
-                        finishTo = Math.min(start - 1, i + 1);
-                        parent = stack.getActivityAtIndex(finishTo);
-                        break;
-                    } else if (r.info.packageName.equals(dest.getPackageName()) &&
-                            r.info.name.equals(dest.getClassName())) {
-                        finishTo = i;
-                        parent = r;
-                        foundParentInTask = true;
-                        break;
-                    }
-                }
-            }
-
-            if (mController != null) {
-                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
-                if (next != null) {
-                    // ask watcher if this is allowed
-                    boolean resumeOK = true;
-                    try {
-                        resumeOK = mController.activityResuming(next.packageName);
-                    } catch (RemoteException e) {
-                        mController = null;
-                    }
-
-                    if (!resumeOK) {
-                        return false;
-                    }
-                }
-            }
-            final long origId = Binder.clearCallingIdentity();
-            for (int i = start; i > finishTo; i--) {
-                ActivityRecord r = stack.getActivityAtIndex(i);
-                mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                        "navigate-up", true);
-                // Only return the supplied result for the first activity finished
-                resultCode = Activity.RESULT_CANCELED;
-                resultData = null;
-            }
-
-            if (parent != null && foundParentInTask) {
-                final int parentLaunchMode = parent.info.launchMode;
-                final int destIntentFlags = destIntent.getFlags();
-                if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
-                        (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                    parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
-                } else {
-                    try {
-                        ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                                destIntent.getComponent(), 0, srec.userId);
-                        int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
-                                null, aInfo, parent.appToken, null,
-                                0, -1, parent.launchedFromUid, parent.launchedFromPackage,
-                                0, null, true, null);
-                        foundParentInTask = res == ActivityManager.START_SUCCESS;
-                    } catch (RemoteException e) {
-                        foundParentInTask = false;
-                    }
-                    mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
-                            resultData, "navigate-up", true);
-                }
-            }
-            Binder.restoreCallingIdentity(origId);
-            return foundParentInTask;
+            return stack.navigateUpToLocked(srec, destIntent, resultCode, resultData);
         }
     }
 
index ba2e47a..2ea79b8 100644 (file)
@@ -22,6 +22,7 @@ import com.android.server.am.ActivityStack.ActivityState;
 
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -95,9 +96,9 @@ final class ActivityRecord {
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
     final int requestCode;  // code given by requester (resultTo)
-    ArrayList results;      // pending ActivityResult objs we have received
+    ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
-    ArrayList newIntents;   // any pending new intents for single-top mode
+    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
     ActivityOptions pendingOptions; // most recently given options
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
index d969709..76836f9 100644 (file)
@@ -24,11 +24,13 @@ import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.wm.AppTransition;
+import com.android.server.wm.TaskGroup;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IThumbnailReceiver;
 import android.app.IThumbnailRetriever;
@@ -501,14 +503,10 @@ final class ActivityStack {
         return null;
     }
 
-    final int indexOfTokenLocked(IBinder token) {
+    private final int indexOfTokenLocked(IBinder token) {
         return mHistory.indexOf(ActivityRecord.forToken(token));
     }
 
-    final int indexOfActivityLocked(ActivityRecord r) {
-        return mHistory.indexOf(r);
-    }
-
     final ActivityRecord isInStackLocked(IBinder token) {
         ActivityRecord r = ActivityRecord.forToken(token);
         if (mHistory.contains(r)) {
@@ -517,14 +515,6 @@ final class ActivityStack {
         return null;
     }
 
-    // TODO: This exposes mHistory too much, replace usage with ActivityStack methods. 
-    final ActivityRecord getActivityAtIndex(int index) {
-        if (index >= 0 && index < mHistory.size()) {
-            return mHistory.get(index);
-        }
-        return null;
-    }
-
     int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
         TaskRecord lastTask = null;
         final int N = mHistory.size();
@@ -745,7 +735,13 @@ final class ActivityStack {
                 try {
                     profileFd = profileFd.dup();
                 } catch (IOException e) {
-                    profileFd = null;
+                    if (profileFd != null) {
+                        try {
+                            profileFd.close();
+                        } catch (IOException o) {
+                        }
+                        profileFd = null;
+                    }
                 }
             }
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
@@ -1758,7 +1754,7 @@ final class ActivityStack {
             
             try {
                 // Deliver all pending results.
-                ArrayList a = next.results;
+                ArrayList<ResultInfo> a = next.results;
                 if (a != null) {
                     final int N = a.size();
                     if (!next.finishing && N > 0) {
@@ -2156,6 +2152,7 @@ final class ActivityStack {
                             }
                             i++;
                         }
+                        mService.mWindowManager.moveTaskToBottom(target.task.taskId);
                         if (taskTop == p) {
                             taskTop = below;
                         }
@@ -2304,6 +2301,8 @@ final class ActivityStack {
                             validateAppTokensLocked();
                         }
                     }
+                    // TODO: This is wrong because it doesn't take lastReparentPos into account.
+                    mService.mWindowManager.moveTaskToTop(task.taskId);
                     replyChainEnd = -1;
                     
                     // Now we've moved it in to place...  but what if this is
@@ -2413,7 +2412,7 @@ final class ActivityStack {
                 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                         && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                     if (!ret.finishing) {
-                        int index = indexOfTokenLocked(ret.appToken);
+                        int index = mHistory.indexOf(ret);
                         if (index >= 0) {
                             finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
                                     null, "clear", false);
@@ -3568,7 +3567,7 @@ final class ActivityStack {
             }
 
             // Get the activity record.
-            int index = indexOfActivityLocked(r);
+            int index = mHistory.indexOf(r);
             if (index >= 0) {
                 res = r;
 
@@ -3654,7 +3653,7 @@ final class ActivityStack {
         // Stop any activities that are scheduled to do so but have been
         // waiting for the next one to start.
         for (i=0; i<NS; i++) {
-            ActivityRecord r = (ActivityRecord)stops.get(i);
+            ActivityRecord r = stops.get(i);
             synchronized (mService) {
                 if (r.finishing) {
                     finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
@@ -3667,7 +3666,7 @@ final class ActivityStack {
         // Finish any activities that are scheduled to do so but have been
         // waiting for the next one to start.
         for (i=0; i<NF; i++) {
-            ActivityRecord r = (ActivityRecord)finishes.get(i);
+            ActivityRecord r = finishes.get(i);
             synchronized (mService) {
                 activityRemoved = destroyActivityLocked(r, true, false, "finish-idle");
             }
@@ -3675,7 +3674,7 @@ final class ActivityStack {
 
         // Report back to any thumbnail receivers.
         for (i=0; i<NT; i++) {
-            ActivityRecord r = (ActivityRecord)thumbnails.get(i);
+            ActivityRecord r = thumbnails.get(i);
             mService.sendPendingThumbnail(r, null, null, null, true);
         }
 
@@ -3730,7 +3729,7 @@ final class ActivityStack {
 
         int i;
         for (i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.resultTo == self && r.requestCode == requestCode) {
                 if ((r.resultWho == null && resultWho == null) ||
                     (r.resultWho != null && r.resultWho.equals(resultWho))) {
@@ -3742,6 +3741,36 @@ final class ActivityStack {
         mService.updateOomAdjLocked();
     }
 
+    final void finishTopRunningActivityLocked(ProcessRecord app) {
+        ActivityRecord r = topRunningActivityLocked(null);
+        if (r != null && r.app == app) {
+            // If the top running activity is from this crashing
+            // process, then terminate it to avoid getting in a loop.
+            Slog.w(TAG, "  Force finishing activity "
+                    + r.intent.getComponent().flattenToShortString());
+            int index = mHistory.indexOf(r);
+            r.stack.finishActivityLocked(r, index,
+                    Activity.RESULT_CANCELED, null, "crashed", false);
+            // Also terminate any activities below it that aren't yet
+            // stopped, to avoid a situation where one will get
+            // re-start our crashing activity once it gets resumed again.
+            index--;
+            if (index >= 0) {
+                r = mHistory.get(index);
+                if (r.state == ActivityState.RESUMED
+                        || r.state == ActivityState.PAUSING
+                        || r.state == ActivityState.PAUSED) {
+                    if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
+                        Slog.w(TAG, "  Force finishing activity "
+                                + r.intent.getComponent().flattenToShortString());
+                        r.stack.finishActivityLocked(r, index,
+                                Activity.RESULT_CANCELED, null, "crashed", false);
+                    }
+                }
+            }
+        }
+    }
+
     final boolean finishActivityAffinityLocked(IBinder token) {
         int index = indexOfTokenLocked(token);
         if (DEBUG_RESULTS) Slog.v(
@@ -3800,6 +3829,19 @@ final class ActivityStack {
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
+    final boolean finishActivityLocked(ActivityRecord r,
+            int resultCode, Intent resultData, String reason, boolean oomAdj) {
+        int index = mHistory.indexOf(r);
+        if (index >= 0) {
+            return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
+        }
+        return false;
+    }
+
+    /**
+     * @return Returns true if this activity has been removed from the history
+     * list, or false if it is still in the list and will be removed later.
+     */
     final boolean finishActivityLocked(ActivityRecord r, int index,
             int resultCode, Intent resultData, String reason, boolean oomAdj) {
         return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
@@ -3892,7 +3934,7 @@ final class ActivityStack {
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
             int mode, boolean oomAdj) {
-        final int index = indexOfActivityLocked(r);
+        final int index = mHistory.indexOf(r);
         if (index < 0) {
             return null;
         }
@@ -3948,16 +3990,102 @@ final class ActivityStack {
                 resumeTopActivityLocked(null);
             }
             return activityRemoved ? null : r;
-        } else {
-            // Need to go through the full pause cycle to get this
-            // activity into the stopped state and then finish it.
-            if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
-            mFinishingActivities.add(r);
-            resumeTopActivityLocked(null);
         }
+
+        // Need to go through the full pause cycle to get this
+        // activity into the stopped state and then finish it.
+        if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+        mFinishingActivities.add(r);
+        resumeTopActivityLocked(null);
         return r;
     }
 
+    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+            Intent resultData) {
+        final int start = mHistory.indexOf(srec);
+        if (start < 0) {
+            // Current activity is not in history stack; do nothing.
+            return false;
+        }
+        int finishTo = start - 1;
+        ActivityRecord parent = null;
+        boolean foundParentInTask = false;
+        ComponentName dest = destIntent.getComponent();
+        if (dest != null) {
+            TaskRecord tr = srec.task;
+            for (int i = start - 1; i >= 0; i--) {
+                ActivityRecord r = mHistory.get(i);
+                if (tr != r.task) {
+                    // Couldn't find parent in the same task; stop at the one above this.
+                    // (Root of current task; in-app "home" behavior)
+                    // Always at least finish the current activity.
+                    finishTo = Math.min(start - 1, i + 1);
+                    parent = mHistory.get(finishTo);
+                    break;
+                } else if (r.info.packageName.equals(dest.getPackageName()) &&
+                        r.info.name.equals(dest.getClassName())) {
+                    finishTo = i;
+                    parent = r;
+                    foundParentInTask = true;
+                    break;
+                }
+            }
+        }
+
+        IActivityController controller = mService.mController;
+        if (controller != null) {
+            ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+            if (next != null) {
+                // ask watcher if this is allowed
+                boolean resumeOK = true;
+                try {
+                    resumeOK = controller.activityResuming(next.packageName);
+                } catch (RemoteException e) {
+                    mService.mController = null;
+                }
+
+                if (!resumeOK) {
+                    return false;
+                }
+            }
+        }
+        final long origId = Binder.clearCallingIdentity();
+        for (int i = start; i > finishTo; i--) {
+            ActivityRecord r = mHistory.get(i);
+            requestFinishActivityLocked(r.appToken, resultCode, resultData,
+                    "navigate-up", true);
+            // Only return the supplied result for the first activity finished
+            resultCode = Activity.RESULT_CANCELED;
+            resultData = null;
+        }
+
+        if (parent != null && foundParentInTask) {
+            final int parentLaunchMode = parent.info.launchMode;
+            final int destIntentFlags = destIntent.getFlags();
+            if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+                    (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+                parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+            } else {
+                try {
+                    ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+                            destIntent.getComponent(), 0, srec.userId);
+                    int res = startActivityLocked(srec.app.thread, destIntent,
+                            null, aInfo, parent.appToken, null,
+                            0, -1, parent.launchedFromUid, parent.launchedFromPackage,
+                            0, null, true, null);
+                    foundParentInTask = res == ActivityManager.START_SUCCESS;
+                } catch (RemoteException e) {
+                    foundParentInTask = false;
+                }
+                requestFinishActivityLocked(parent.appToken, resultCode,
+                        resultData, "navigate-up", true);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+        return foundParentInTask;
+    }
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
@@ -4216,7 +4344,7 @@ final class ActivityStack {
                     mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
                 }
 
-                int index = indexOfActivityLocked(r);
+                int index = mHistory.indexOf(r);
                 if (index >= 0) {
                     if (r.state == ActivityState.DESTROYING) {
                         cleanUpActivityLocked(r, true, false);
@@ -4230,15 +4358,15 @@ final class ActivityStack {
         }
     }
     
-    private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app,
-            String listName) {
+    private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+            ProcessRecord app, String listName) {
         int i = list.size();
         if (DEBUG_CLEANUP) Slog.v(
             TAG, "Removing app " + app + " from list " + listName
             + " with " + i + " entries");
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)list.get(i);
+            ActivityRecord r = list.get(i);
             if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
             if (r.app == app) {
                 if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
@@ -4264,7 +4392,7 @@ final class ActivityStack {
             TAG, "Removing app " + app + " from history with " + i + " entries");
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (DEBUG_CLEANUP) Slog.v(
                 TAG, "Record #" + i + " " + r + ": app=" + r.app);
             if (r.app == app) {
@@ -4440,6 +4568,7 @@ final class ActivityStack {
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
+        mService.mWindowManager.moveTaskToTop(task);
 
         finishTaskMoveLocked(task);
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
@@ -4532,6 +4661,7 @@ final class ActivityStack {
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
+        mService.mWindowManager.moveTaskToBottom(task);
 
         finishTaskMoveLocked(task);
         return true;
@@ -4561,9 +4691,8 @@ final class ActivityStack {
         TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
         if (info.numSubThumbbails <= 0) {
             return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
-        } else {
-            return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
         }
+        return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
     }
 
     public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
@@ -4643,6 +4772,7 @@ final class ActivityStack {
         }
         if (thumbs.numSubThumbbails > 0) {
             thumbs.retriever = new IThumbnailRetriever.Stub() {
+                @Override
                 public Bitmap getThumbnail(int index) {
                     if (index < 0 || index >= thumbs.subtasks.size()) {
                         return null;
index 906ea57..43a5f0c 100644 (file)
 
 package com.android.server.wm;
 
+import android.os.Debug;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 
 class DisplayContentList extends ArrayList<DisplayContent> {
 }
@@ -34,7 +38,7 @@ class DisplayContentList extends ArrayList<DisplayContent> {
  * WindowManagerService.mWindowMap.
  */
 class DisplayContent {
-//    private final static String TAG = "DisplayContent";
+    private final static String TAG = "DisplayContent";
 
     /** Unique identifier of this stack. */
     private final int mDisplayId;
@@ -97,7 +101,7 @@ class DisplayContent {
     /**
      * Sorted most recent at top, oldest at [0].
      */
-//    ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
+    ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
     SparseArray<TaskList> mTaskIdToTaskList = new SparseArray<TaskList>();
 
     /**
@@ -133,24 +137,28 @@ class DisplayContent {
     /**
      *  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.
+     * @param wtoken The token to insert.
      */
-    void addAppToken(final int addPos, final AppWindowToken atoken) {
-        mAppTokens.add(addPos, atoken);
+    void addAppToken(final int addPos, final AppWindowToken wtoken) {
+        mAppTokens.add(addPos, wtoken);
 
         if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
             // It was inserted into the beginning or end of mAppTokens. Honor that.
-            mAnimatingAppTokens.add(addPos, atoken);
+            mAnimatingAppTokens.add(addPos, wtoken);
         } 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);
+            mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
         }
 
-        TaskList task = mTaskIdToTaskList.get(atoken.groupId);
+        TaskList task = mTaskIdToTaskList.get(wtoken.groupId);
         if (task == null) {
-            mTaskIdToTaskList.put(atoken.groupId, new TaskList(atoken));
+            task = new TaskList(wtoken, this);
+            mTaskIdToTaskList.put(wtoken.groupId, task);
+            mTaskLists.add(task);
+        } else {
+            task.mAppTokens.add(wtoken);
         }
     }
 
@@ -163,6 +171,7 @@ class DisplayContent {
             AppTokenList appTokens = task.mAppTokens;
             appTokens.remove(wtoken);
             if (appTokens.size() == 0) {
+                mTaskLists.remove(task);
                 mTaskIdToTaskList.delete(taskId);
             }
         }
@@ -186,7 +195,7 @@ class DisplayContent {
 
         task = mTaskIdToTaskList.get(newTaskId);
         if (task == null) {
-            task = new TaskList(wtoken);
+            task = new TaskList(wtoken, this);
             mTaskIdToTaskList.put(newTaskId, task);
         } else {
             task.mAppTokens.add(wtoken);
@@ -195,6 +204,122 @@ class DisplayContent {
         wtoken.groupId = newTaskId;
     }
 
+    class TaskListsIterator implements Iterator<TaskList> {
+        private int mCur;
+        private boolean mReverse;
+
+        TaskListsIterator() {
+            this(false);
+        }
+
+        TaskListsIterator(boolean reverse) {
+            mReverse = reverse;
+            int numTaskLists = mTaskLists.size();
+            mCur = reverse ? numTaskLists - 1 : 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskLists.size();
+        }
+
+        @Override
+        public TaskList next() {
+            if (hasNext()) {
+                TaskList taskList = mTaskLists.get(mCur);
+                mCur += (mReverse ? -1 : 1);
+                return taskList;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    class AppTokenIterator implements Iterator<AppWindowToken> {
+        final TaskListsIterator mIterator;
+        final boolean mReverse;
+        int mCur;
+        TaskList mTaskList;
+
+        public AppTokenIterator() {
+            this(false);
+        }
+
+        public AppTokenIterator(boolean reverse) {
+            mReverse = reverse;
+            mIterator = new TaskListsIterator(reverse);
+            getNextTaskList();
+        }
+
+        private void getNextTaskList() {
+            if (mIterator.hasNext()) {
+                mTaskList = mIterator.next();
+                mCur = mReverse ? mTaskList.mAppTokens.size() - 1 : 0;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mTaskList == null) {
+                return false;
+            }
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskList.mAppTokens.size();
+        }
+
+        @Override
+        public AppWindowToken next() {
+            if (hasNext()) {
+                AppWindowToken wtoken = mTaskList.mAppTokens.get(mCur);
+                mCur += mReverse ? -1 : 1;
+                if (!hasNext()) {
+                    getNextTaskList();
+                }
+                return wtoken;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    void verifyAppTokens() {
+        AppTokenIterator iterator = new AppTokenIterator();
+        for (int i = 0; i < mAppTokens.size(); ++i) {
+            if (!iterator.hasNext()) {
+                Slog.e(TAG, "compareAppTokens: More mAppTokens than TaskList tokens. Callers="
+                        + Debug.getCallers(4));
+                while (i < mAppTokens.size()) {
+                    Slog.e(TAG, "compareAppTokens: mAppTokens[" + i + "]=" + mAppTokens.get(i));
+                    i++;
+                }
+                return;
+            }
+            AppWindowToken appToken = mAppTokens.get(i);
+            AppWindowToken taskListToken = iterator.next();
+            if (appToken != taskListToken) {
+                Slog.e(TAG, "compareAppTokens: Mismatch at " + i + " appToken=" + appToken
+                        + " taskListToken=" + taskListToken + ". Callers=" + Debug.getCallers(4));
+            }
+        }
+        if (iterator.hasNext()) {
+            Slog.e(TAG, "compareAppTokens: More TaskList tokens than mAppTokens Callers="
+                    + Debug.getCallers(4));
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
         final String subPrefix = "  " + prefix;
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.am;
+package com.android.server.wm;
 
 import android.view.IApplicationToken;
 
index fe12b98..88791f2 100644 (file)
 
 package com.android.server.wm;
 
-import com.android.server.am.TaskGroup;
-
-class TaskList extends TaskGroup {
+class TaskList {
 //    private final String TAG = "TaskGroup";
-    AppTokenList mAppTokens = new AppTokenList();
+    DisplayContent mDisplayContent;
+    final AppTokenList mAppTokens = new AppTokenList();
+    final int taskId;
 
-    TaskList(AppWindowToken wtoken) {
+    TaskList(AppWindowToken wtoken, DisplayContent displayContent) {
         taskId = wtoken.groupId;
-        tokens.add(wtoken.appToken);
         mAppTokens.add(wtoken);
+        mDisplayContent = displayContent;
     }
 }
index 62eccdf..3dec9a4 100644 (file)
@@ -54,7 +54,6 @@ import com.android.server.AttributeCache;
 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;
@@ -330,8 +329,7 @@ public class WindowManagerService extends IWindowManager.Stub
     /**
      * Mapping from a token IBinder to a WindowToken object.
      */
-    final HashMap<IBinder, WindowToken> mTokenMap =
-            new HashMap<IBinder, WindowToken>();
+    final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();
 
     /**
      * List of window tokens that have finished starting their application,
@@ -3286,6 +3284,7 @@ public class WindowManagerService extends IWindowManager.Stub
                 mTaskIdToDisplayContents.put(taskId, displayContent);
             }
             displayContent.addAppToken(addPos, atoken);
+            displayContent.verifyAppTokens();
             mTokenMap.put(token.asBinder(), atoken);
             mTaskIdToDisplayContents.put(taskId, displayContent);
 
@@ -4269,11 +4268,12 @@ public class WindowManagerService extends IWindowManager.Stub
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
                         + " animation=" + wtoken.mAppAnimator.animation
                         + " animating=" + wtoken.mAppAnimator.animating);
+                DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
                 if (delayed) {
                     // 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);
-                    mTaskIdToDisplayContents.get(wtoken.groupId).mExitingAppTokens.add(wtoken);
+                    displayContent.mExitingAppTokens.add(wtoken);
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
@@ -4283,7 +4283,8 @@ public class WindowManagerService extends IWindowManager.Stub
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
-                mTaskIdToDisplayContents.get(wtoken.groupId).removeAppToken(wtoken);
+                displayContent.removeAppToken(wtoken);
+                displayContent.verifyAppTokens();
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4675,6 +4676,44 @@ public class WindowManagerService extends IWindowManager.Stub
         Binder.restoreCallingIdentity(origId);
     }
 
+    public void moveTaskToTop(int taskId) {
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
+                    + " not found in mTaskIdToDisplayContents");
+            return;
+        }
+        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+        if (taskList == null) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskIdToTaskLists");
+            return;
+        }
+        if (!displayContent.mTaskLists.remove(taskList)) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskLists");
+        }
+        displayContent.mTaskLists.add(taskList);
+        displayContent.verifyAppTokens();
+    }
+
+    public void moveTaskToBottom(int taskId) {
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
+                    + " not found in mTaskIdToDisplayContents");
+            return;
+        }
+        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+        if (taskList == null) {
+            Slog.e(TAG, "moveTaskToTopBottomtaskId=" + taskId + " not found in mTaskIdToTaskLists");
+            return;
+        }
+        if (!displayContent.mTaskLists.remove(taskList)) {
+            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId + " not found in mTaskLists");
+        }
+        displayContent.mTaskLists.add(0, taskList);
+        displayContent.verifyAppTokens();
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------