Implement separate stacks.

One for home activity(s), one for other activities. Coordination
between the stacks is handled by the ActivityStackSupervisor.

Change-Id: I11395edea501d2f84a18a6a8bced1ce3d0797dad
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 4c08f85..d3e5b48 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -61,6 +61,7 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.wm.StackBox;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -69,10 +70,11 @@
 import java.util.List;
 
 public class ActivityStackSupervisor {
-    static final boolean DEBUG_ADD_REMOVE = false;
-    static final boolean DEBUG_APP = false;
-    static final boolean DEBUG_SAVED_STATE = false;
-    static final boolean DEBUG_STATES = false;
+    static final boolean DEBUG = ActivityManagerService.DEBUG || false;
+    static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
+    static final boolean DEBUG_APP = DEBUG || false;
+    static final boolean DEBUG_SAVED_STATE = DEBUG || false;
+    static final boolean DEBUG_STATES = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
 
@@ -96,12 +98,31 @@
     /** The stack containing the launcher app */
     private ActivityStack mHomeStack;
 
-    /** The stack currently receiving input or launching the next activity */
+    /** The non-home stack currently receiving input or launching the next activity. If home is
+     * in front then mHomeStack overrides mMainStack. */
     private ActivityStack mMainStack;
 
     /** All the non-launcher stacks */
     private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
 
+    private static final int STACK_STATE_HOME_IN_FRONT = 0;
+    private static final int STACK_STATE_HOME_TO_BACK = 1;
+    private static final int STACK_STATE_HOME_IN_BACK = 2;
+    private static final int STACK_STATE_HOME_TO_FRONT = 3;
+    private int mStackState = STACK_STATE_HOME_IN_FRONT;
+
+    /** List of activities that are waiting for a new activity to become visible before completing
+     * whatever operation they are supposed to do. */
+    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<ActivityRecord>();
+
+    /** List of activities that are ready to be stopped, but waiting for the next activity to
+     * settle down before doing so. */
+    final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<ActivityRecord>();
+
+    /** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
+     * is being brought in front of us. */
+    boolean mUserLeaving = false;
+
     public ActivityStackSupervisor(ActivityManagerService service, Context context,
             Looper looper) {
         mService = service;
@@ -111,7 +132,6 @@
 
     void init(int userId) {
         mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID, this, userId);
-        setMainStack(mHomeStack);
         mStacks.add(mHomeStack);
     }
 
@@ -122,20 +142,59 @@
         }
     }
 
-    boolean isHomeStackMain() {
-        return mHomeStack == mMainStack;
+    ActivityStack getTopStack() {
+        switch (mStackState) {
+            case STACK_STATE_HOME_IN_FRONT:
+            case STACK_STATE_HOME_TO_FRONT:
+                return mHomeStack;
+            case STACK_STATE_HOME_IN_BACK:
+            case STACK_STATE_HOME_TO_BACK:
+            default:
+                return mMainStack;
+        }
     }
 
-    boolean isMainStack(ActivityStack stack) {
-        return stack == mMainStack;
+    ActivityStack getLastStack() {
+        switch (mStackState) {
+            case STACK_STATE_HOME_IN_FRONT:
+            case STACK_STATE_HOME_TO_BACK:
+                return mHomeStack;
+            case STACK_STATE_HOME_TO_FRONT:
+            case STACK_STATE_HOME_IN_BACK:
+            default:
+                return mMainStack;
+        }
     }
 
-    ActivityStack getMainStack() {
-        return mMainStack;
+    boolean isFrontStack(ActivityStack stack) {
+        return stack == getTopStack();
     }
 
-    void setMainStack(ActivityStack stack) {
-        mMainStack = stack;
+    boolean homeIsInFront() {
+        return isFrontStack(mHomeStack);
+    }
+
+    void moveHomeStack(boolean toFront) {
+        final boolean homeInFront = isFrontStack(mHomeStack);
+        if (homeInFront ^ toFront) {
+            mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT;
+        }
+    }
+
+    final void setLaunchHomeTaskNextFlag(ActivityRecord sourceRecord, ActivityRecord r,
+            ActivityStack stack) {
+        if (stack == mHomeStack) {
+            return;
+        }
+        if ((sourceRecord == null && getLastStack() == mHomeStack) ||
+                (sourceRecord != null && sourceRecord.isHomeActivity)) {
+            if (r == null) {
+                r = stack.topRunningActivityLocked(null);
+            }
+            if (r != null && !r.isHomeActivity && r.isRootActivity()) {
+                r.mLaunchHomeTaskNext = true;
+            }
+        }
     }
 
     void setDismissKeyguard(boolean dismiss) {
@@ -173,6 +232,33 @@
         return mCurTaskId;
     }
 
+    void removeTask(TaskRecord task) {
+        final ActivityStack stack = task.stack;
+        if (stack.removeTask(task) && !stack.isHomeStack()) {
+            mStacks.remove(stack);
+            final int oldStackId = stack.mStackId;
+            final int newMainStackId = mService.mWindowManager.removeStack(oldStackId);
+            if (newMainStackId == HOME_STACK_ID) {
+                return;
+            }
+            if (mMainStack.mStackId == oldStackId) {
+                mMainStack = getStack(newMainStackId);
+            }
+        }
+    }
+
+    ActivityRecord resumedAppLocked() {
+        ActivityStack stack = getTopStack();
+        ActivityRecord resumedActivity = stack.mResumedActivity;
+        if (resumedActivity == null || resumedActivity.app == null) {
+            resumedActivity = stack.mPausingActivity;
+            if (resumedActivity == null || resumedActivity.app == null) {
+                resumedActivity = stack.topRunningActivityLocked(null);
+            }
+        }
+        return resumedActivity;
+    }
+
     boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
         boolean didSomething = false;
         final String processName = app.processName;
@@ -212,6 +298,65 @@
         return true;
     }
 
+    boolean allResumedActivitiesComplete() {
+        final boolean homeInBack = !homeIsInFront();
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.isHomeStack() ^ homeInBack) {
+                final ActivityRecord r = stack.mResumedActivity;
+                if (r != null && r.state != ActivityState.RESUMED) {
+                    return false;
+                }
+            }
+        }
+        // TODO: Not sure if this should check if all Paused are complete too.
+        switch (mStackState) {
+            case STACK_STATE_HOME_TO_BACK:
+                mStackState = STACK_STATE_HOME_IN_BACK;
+                break;
+            case STACK_STATE_HOME_TO_FRONT:
+                mStackState = STACK_STATE_HOME_IN_FRONT;
+                break;
+        }
+        return true;
+    }
+
+    boolean allResumedActivitiesVisible() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            final ActivityRecord r = stack.mResumedActivity;
+            if (r != null && (!r.nowVisible || r.waitingVisible)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    boolean allPausedActivitiesComplete() {
+        final boolean homeInBack = !homeIsInFront();
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.isHomeStack() ^ homeInBack) {
+                final ActivityRecord r = stack.mLastPausedActivity;
+                if (r != null && r.state != ActivityState.PAUSED
+                        && r.state != ActivityState.STOPPED
+                        && r.state != ActivityState.STOPPING) {
+                    return false;
+                }
+            }
+        }
+        // TODO: Not sure if this should check if all Resumed are complete too.
+        switch (mStackState) {
+            case STACK_STATE_HOME_TO_BACK:
+                mStackState = STACK_STATE_HOME_IN_BACK;
+                break;
+            case STACK_STATE_HOME_TO_FRONT:
+                mStackState = STACK_STATE_HOME_IN_FRONT;
+                break;
+        }
+        return true;
+    }
+
     ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
             PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
         ActivityRecord r = null;
@@ -220,7 +365,7 @@
             final ActivityStack stack = mStacks.get(stackNdx);
             final ActivityRecord ar =
                     stack.getTasksLocked(maxNum - list.size(), receiver, pending, list);
-            if (isMainStack(stack)) {
+            if (isFrontStack(stack)) {
                 r = ar;
             }
         }
@@ -275,6 +420,7 @@
     }
 
     void startHomeActivity(Intent intent, ActivityInfo aInfo) {
+        moveHomeStack(true);
         startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
                 null, false, null);
     }
@@ -308,10 +454,11 @@
                 callingPid = callingUid = -1;
             }
 
-            mMainStack.mConfigWillChange = config != null
+            final ActivityStack stack = getTopStack();
+            stack.mConfigWillChange = config != null
                     && mService.mConfiguration.diff(config) != 0;
             if (DEBUG_CONFIGURATION) Slog.v(TAG,
-                    "Starting activity when config will change = " + mMainStack.mConfigWillChange);
+                    "Starting activity when config will change = " + stack.mConfigWillChange);
 
             final long origId = Binder.clearCallingIdentity();
 
@@ -389,14 +536,14 @@
                     aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
                     callingPackage, startFlags, options, componentSpecified, null);
 
-            if (mMainStack.mConfigWillChange) {
+            if (stack.mConfigWillChange) {
                 // If the caller also wants to switch to a new configuration,
                 // do so now.  This allows a clean switch, as we are waiting
                 // for the current activity to pause (so we will not destroy
                 // it), and have not yet started the next activity.
                 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                         "updateConfiguration()");
-                mMainStack.mConfigWillChange = false;
+                stack.mConfigWillChange = false;
                 if (DEBUG_CONFIGURATION) Slog.v(TAG,
                         "Updating to new configuration after starting activity.");
                 mService.updateConfigurationLocked(config, null, false, false);
@@ -407,7 +554,7 @@
             if (outResult != null) {
                 outResult.result = res;
                 if (res == ActivityManager.START_SUCCESS) {
-                    mMainStack.mWaitingActivityLaunched.add(outResult);
+                    stack.mWaitingActivityLaunched.add(outResult);
                     do {
                         try {
                             mService.wait();
@@ -415,7 +562,7 @@
                         }
                     } while (!outResult.timeout && outResult.who == null);
                 } else if (res == ActivityManager.START_TASK_TO_FRONT) {
-                    ActivityRecord r = mMainStack.topRunningActivityLocked(null);
+                    ActivityRecord r = stack.topRunningActivityLocked(null);
                     if (r.nowVisible) {
                         outResult.timeout = false;
                         outResult.who = new ComponentName(r.info.packageName, r.info.name);
@@ -423,7 +570,7 @@
                         outResult.thisTime = 0;
                     } else {
                         outResult.thisTime = SystemClock.uptimeMillis();
-                        mMainStack.mWaitingActivityVisible.add(outResult);
+                        stack.mWaitingActivityVisible.add(outResult);
                         do {
                             try {
                                 mService.wait();
@@ -679,7 +826,7 @@
         // launching the initial activity (that is, home), so that it can have
         // a chance to initialize itself while in the background, making the
         // switch back to it faster and look better.
-        if (isMainStack(stack)) {
+        if (isFrontStack(stack)) {
             mService.startSetupActivityLocked();
         }
 
@@ -852,16 +999,17 @@
 
         ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                 intent, resolvedType, aInfo, mService.mConfiguration,
-                resultRecord, resultWho, requestCode, componentSpecified);
+                resultRecord, resultWho, requestCode, componentSpecified, this);
         if (outActivity != null) {
             outActivity[0] = r;
         }
 
-        if (mMainStack.mResumedActivity == null
-                || mMainStack.mResumedActivity.info.applicationInfo.uid != callingUid) {
+        final ActivityStack stack = getTopStack();
+        if (stack.mResumedActivity == null
+                || stack.mResumedActivity.info.applicationInfo.uid != callingUid) {
             if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
                 PendingActivityLaunch pal =
-                        new PendingActivityLaunch(r, sourceRecord, startFlags, mMainStack);
+                        new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
                 mService.mPendingActivityLaunches.add(pal);
                 setDismissKeyguard(false);
                 ActivityOptions.abort(options);
@@ -883,7 +1031,7 @@
         mService.doPendingActivityLaunchesLocked(false);
 
         err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
-        if (mMainStack.mPausingActivity == null) {
+        if (stack.mPausingActivity == null) {
             // Someone asked to have the keyguard dismissed on the next
             // activity start, but we are not actually doing an activity
             // switch...  just dismiss the keyguard now, because we
@@ -893,6 +1041,19 @@
         return err;
     }
 
+    ActivityStack getCorrectStack(ActivityRecord r) {
+        if (!r.isHomeActivity) {
+            if (mStacks.size() == 1) {
+                // Time to create the first app stack.
+                int stackId =
+                        mService.createStack(HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f);
+                mMainStack = getStack(stackId);
+            }
+            return mMainStack;
+        }
+        return mHomeStack;
+    }
+
     final int startActivityUncheckedLocked(ActivityRecord r,
             ActivityRecord sourceRecord, int startFlags, boolean doResume,
             Bundle options) {
@@ -901,14 +1062,10 @@
 
         int launchFlags = intent.getFlags();
 
-        final ActivityStack stack = mMainStack;
-        ActivityStack targetStack = mMainStack;
-
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
-        targetStack.mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG,
-                "startActivity() => mUserLeaving=" + targetStack.mUserLeaving);
+        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+        if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
 
         // If the caller has asked not to resume at this point, we make note
         // of this in the record so that we can skip it when trying to find
@@ -926,7 +1083,7 @@
         if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
             ActivityRecord checkedCaller = sourceRecord;
             if (checkedCaller == null) {
-                checkedCaller = targetStack.topRunningNonDelayedActivityLocked(notTop);
+                checkedCaller = getTopStack().topRunningNonDelayedActivityLocked(notTop);
             }
             if (!checkedCaller.realActivity.equals(r.realActivity)) {
                 // Caller is not the same as launcher, so always needed.
@@ -954,6 +1111,16 @@
             launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
         }
 
+        final ActivityStack sourceStack;
+        final TaskRecord sourceTask;
+        if (sourceRecord != null) {
+            sourceTask = sourceRecord.task;
+            sourceStack = sourceTask.stack;
+        } else {
+            sourceTask = null;
+            sourceStack = null;
+        }
+
         if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             // For whatever reason this activity is being launched into a new
             // task...  yet the caller has requested a result back.  Well, that
@@ -970,6 +1137,7 @@
         boolean addingToTask = false;
         boolean movedHome = false;
         TaskRecord reuseTask = null;
+        ActivityStack targetStack;
         if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
@@ -987,6 +1155,7 @@
                         : findActivityLocked(intent, r.info);
                 if (intentActivity != null) {
                     targetStack = intentActivity.task.stack;
+                    moveHomeStack(targetStack.isHomeStack());
                     if (intentActivity.task.intent == null) {
                         // This task was started because of movement of
                         // the activity based on affinity...  now that we
@@ -1000,16 +1169,21 @@
                     // to have the same behavior as if a new instance was
                     // being started, which means not bringing it to the front
                     // if the caller is not itself in the front.
-                    ActivityRecord curTop = targetStack.topRunningNonDelayedActivityLocked(notTop);
+                    ActivityRecord curTop =
+                            targetStack.topRunningNonDelayedActivityLocked(notTop);
                     if (curTop != null && curTop.task != intentActivity.task) {
                         r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-                        boolean callerAtFront = sourceRecord == null
-                                || curTop.task == sourceRecord.task;
-                        if (callerAtFront) {
+                        if (sourceRecord == null || sourceStack.topActivity() == sourceRecord) {
                             // We really do want to push this one into the
                             // user's face, right now.
                             movedHome = true;
-                            targetStack.moveHomeToFrontFromLaunchLocked(launchFlags);
+                            if ((launchFlags &
+                                    (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
+                                    == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
+                                // Caller wants to appear on home activity, so before starting
+                                // their own activity we will bring home to the front.
+                                r.mLaunchHomeTaskNext = true;
+                            }
                             targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                             options = null;
                         }
@@ -1025,6 +1199,7 @@
                         // is the case, so this is it!  And for paranoia, make
                         // sure we have correctly resumed the top activity.
                         if (doResume) {
+                            setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
                             targetStack.resumeTopActivityLocked(null, options);
                         } else {
                             ActivityOptions.abort(options);
@@ -1117,7 +1292,8 @@
                         // don't use that intent!)  And for paranoia, make
                         // sure we have correctly resumed the top activity.
                         if (doResume) {
-                            stack.resumeTopActivityLocked(null, options);
+                            setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
+                            targetStack.resumeTopActivityLocked(null, options);
                         } else {
                             ActivityOptions.abort(options);
                         }
@@ -1137,7 +1313,8 @@
             // If the activity being launched is the same as the one currently
             // at the top, then we need to check if it should only be launched
             // once.
-            ActivityRecord top = targetStack.topRunningNonDelayedActivityLocked(notTop);
+            ActivityStack topStack = getTopStack();
+            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
             if (top != null && r.resultTo == null) {
                 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                     if (top.app != null && top.app.thread != null) {
@@ -1149,7 +1326,8 @@
                             // For paranoia, make sure we have correctly
                             // resumed the top activity.
                             if (doResume) {
-                                targetStack.resumeTopActivityLocked(null);
+                                setLaunchHomeTaskNextFlag(sourceRecord, null, topStack);
+                                topStack.resumeTopActivityLocked(null);
                             }
                             ActivityOptions.abort(options);
                             if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -1167,9 +1345,8 @@
 
         } else {
             if (r.resultTo != null) {
-                r.resultTo.task.stack.sendActivityResultLocked(-1,
-                        r.resultTo, r.resultWho, r.requestCode,
-                    Activity.RESULT_CANCELED, null);
+                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
+                        r.requestCode, Activity.RESULT_CANCELED, null);
             }
             ActivityOptions.abort(options);
             return ActivityManager.START_CLASS_NOT_FOUND;
@@ -1181,20 +1358,29 @@
         // Should this be considered a new task?
         if (r.resultTo == null && !addingToTask
                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+            targetStack = getCorrectStack(r);
+            moveHomeStack(targetStack.isHomeStack());
             if (reuseTask == null) {
-                stack.setTask(r, targetStack.createTaskRecord(getNextTaskId(), r.info, intent,
-                        true), null, true);
-                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
-                        + " in new task " + r.task);
+                r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+                        null, true);
+                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
+                        r.task);
             } else {
-                stack.setTask(r, reuseTask, reuseTask, true);
+                r.setTask(reuseTask, reuseTask, true);
             }
             newTask = true;
             if (!movedHome) {
-                stack.moveHomeToFrontFromLaunchLocked(launchFlags);
+                if ((launchFlags &
+                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
+                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
+                    // Caller wants to appear on home activity, so before starting
+                    // their own activity we will bring home to the front.
+                    r.mLaunchHomeTaskNext = true;
+                }
             }
-
         } else if (sourceRecord != null) {
+            targetStack = sourceRecord.task.stack;
+            moveHomeStack(targetStack.isHomeStack());
             if (!addingToTask &&
                     (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                 // In this case, we are adding the activity to an existing
@@ -1208,6 +1394,7 @@
                     // For paranoia, make sure we have correctly
                     // resumed the top activity.
                     if (doResume) {
+                        setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
                         targetStack.resumeTopActivityLocked(null);
                     }
                     ActivityOptions.abort(options);
@@ -1221,11 +1408,13 @@
                 final ActivityRecord top =
                         targetStack.findActivityInHistoryLocked(r, sourceRecord.task);
                 if (top != null) {
-                    targetStack.moveActivityToFrontLocked(top);
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
+                    final TaskRecord task = top.task;
+                    task.moveActivityToFrontLocked(top);
+                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
                     top.updateOptionsLocked(options);
                     top.deliverNewIntentLocked(callingUid, r.intent);
                     if (doResume) {
+                        setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
                         targetStack.resumeTopActivityLocked(null);
                     }
                     return ActivityManager.START_DELIVERED_TO_TOP;
@@ -1234,7 +1423,7 @@
             // An existing activity is starting this new activity, so we want
             // to keep the new one in the same task as the one that is starting
             // it.
-            stack.setTask(r, sourceRecord.task, sourceRecord.thumbHolder, false);
+            r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in existing task " + r.task);
 
@@ -1242,10 +1431,12 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            ActivityRecord prev = stack.topActivity();
-            stack.setTask(r, prev != null
-                    ? prev.task
-                    : stack.createTaskRecord(getNextTaskId(), r.info, intent, true), null, true);
+            targetStack = getLastStack();
+            moveHomeStack(targetStack.isHomeStack());
+            ActivityRecord prev = targetStack.topActivity();
+            r.setTask(prev != null ? prev.task
+                    : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+                    null, true);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
@@ -1257,6 +1448,7 @@
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
         }
         ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
+        setLaunchHomeTaskNextFlag(sourceRecord, r, targetStack);
         targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
         return ActivityManager.START_SUCCESS;
     }
@@ -1407,11 +1599,14 @@
     }
 
     void comeOutOfSleepIfNeededLocked() {
+        final boolean homeIsBack = !homeIsInFront();
         final int numStacks = mStacks.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
             final ActivityStack stack = mStacks.get(stackNdx);
-            stack.awakeFromSleepingLocked();
-            stack.resumeTopActivityLocked(null);
+            if (stack.isHomeStack() ^ homeIsBack) {
+                stack.awakeFromSleepingLocked();
+                stack.resumeTopActivityLocked(null);
+            }
         }
     }
 
@@ -1423,28 +1618,10 @@
         }
     }
 
-    boolean updateConfigurationLocked(int changes, ActivityRecord starting) {
-        boolean kept = true;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (changes != 0 && starting == null) {
-                // If the configuration changed, and the caller is not already
-                // in the process of starting an activity, then find the top
-                // activity to check if its configuration needs to change.
-                starting = stack.topRunningActivityLocked(null);
-            }
-
-            if (starting != null) {
-                if (!stack.ensureActivityConfigurationLocked(starting, changes)) {
-                    kept = false;
-                }
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
-                stack.ensureActivitiesVisibleLocked(starting, changes);
-            }
+    void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).ensureActivitiesVisibleLocked(starting, configChanges);
         }
-        return kept;
     }
 
     void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
@@ -1457,22 +1634,65 @@
 
     boolean switchUserLocked(int userId, UserStartedState uss) {
         mCurrentUser = userId;
+        boolean homeInBack = !homeIsInFront();
         boolean haveActivities = false;
         final int numStacks = mStacks.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
             final ActivityStack stack = mStacks.get(stackNdx);
-            haveActivities |= stack.switchUserLocked(userId, uss);
+            if (stack.isHomeStack() ^ homeInBack) {
+                haveActivities |= stack.switchUserLocked(userId, uss);
+            }
         }
         return haveActivities;
     }
 
+    final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
+        int N = mStoppingActivities.size();
+        if (N <= 0) return null;
+
+        ArrayList<ActivityRecord> stops = null;
+
+        final boolean nowVisible = allResumedActivitiesVisible();
+        for (int i=0; i<N; i++) {
+            ActivityRecord s = mStoppingActivities.get(i);
+            if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
+                    + nowVisible + " waitingVisible=" + s.waitingVisible
+                    + " finishing=" + s.finishing);
+            if (s.waitingVisible && nowVisible) {
+                mWaitingVisibleActivities.remove(s);
+                s.waitingVisible = false;
+                if (s.finishing) {
+                    // If this activity is finishing, it is sitting on top of
+                    // everyone else but we now know it is no longer needed...
+                    // so get rid of it.  Otherwise, we need to go through the
+                    // normal flow and hide it once we determine that it is
+                    // hidden by the activities in front of it.
+                    if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
+                    mService.mWindowManager.setAppVisibility(s.appToken, false);
+                }
+            }
+            if ((!s.waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
+                if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
+                if (stops == null) {
+                    stops = new ArrayList<ActivityRecord>();
+                }
+                stops.add(s);
+                mStoppingActivities.remove(i);
+                N--;
+                i--;
+            }
+        }
+
+        return stops;
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity:");
                 pw.println(mDismissKeyguardOnNextActivity);
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
-        return mMainStack.getDumpActivitiesLocked(name);
+        return getTopStack().getDumpActivitiesLocked(name);
     }
 
     boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
@@ -1486,18 +1706,6 @@
             pw.println("  Running activities (most recent first):");
             dumpHistoryList(fd, pw, stack.mLRUActivities, "  ", "Run", false, !dumpAll, false,
                     dumpPackage);
-            if (stack.mWaitingVisibleActivities.size() > 0) {
-                pw.println(" ");
-                pw.println("  Activities waiting for another to become visible:");
-                dumpHistoryList(fd, pw, stack.mWaitingVisibleActivities, "  ", "Wait", false,
-                        !dumpAll, false, dumpPackage);
-            }
-            if (stack.mStoppingActivities.size() > 0) {
-                pw.println(" ");
-                pw.println("  Activities waiting to stop:");
-                dumpHistoryList(fd, pw, stack.mStoppingActivities, "  ", "Stop", false,
-                        !dumpAll, false, dumpPackage);
-            }
             if (stack.mGoingToSleepActivities.size() > 0) {
                 pw.println(" ");
                 pw.println("  Activities waiting to sleep:");
@@ -1510,10 +1718,7 @@
                 dumpHistoryList(fd, pw, stack.mFinishingActivities, "  ", "Fin", false,
                         !dumpAll, false, dumpPackage);
             }
-        }
 
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
             pw.print("  Stack #"); pw.println(mStacks.indexOf(stack));
             if (stack.mPausingActivity != null) {
                 pw.println("  mPausingActivity: " + stack.mPausingActivity);
@@ -1525,6 +1730,20 @@
             }
         }
 
+        if (mStoppingActivities.size() > 0) {
+            pw.println(" ");
+            pw.println("  Activities waiting to stop:");
+            dumpHistoryList(fd, pw, mStoppingActivities, "  ", "Stop", false, !dumpAll, false,
+                    dumpPackage);
+        }
+
+        if (mWaitingVisibleActivities.size() > 0) {
+            pw.println(" ");
+            pw.println("  Activities waiting for another to become visible:");
+            dumpHistoryList(fd, pw, mWaitingVisibleActivities, "  ", "Wait", false, !dumpAll,
+                    false, dumpPackage);
+        }
+
         if (dumpAll) {
             pw.println(" ");
             pw.println("  mCurTaskId: " + mCurTaskId);