diff options
author | Craig Mautner <cmautner@google.com> | 2013-12-04 16:14:06 -0800 |
---|---|---|
committer | Craig Mautner <cmautner@google.com> | 2013-12-18 15:08:15 -0800 |
commit | 4a1cb22056112f7ffd5f4fad8b7a092b96e7cc7b (patch) | |
tree | 2a30eb0760369a59905895e88f8325fbf9934414 /services | |
parent | 3bcdbd6b2d96427d7cee835e9ed79aeed51de267 (diff) | |
download | frameworks_base-4a1cb22056112f7ffd5f4fad8b7a092b96e7cc7b.zip frameworks_base-4a1cb22056112f7ffd5f4fad8b7a092b96e7cc7b.tar.gz frameworks_base-4a1cb22056112f7ffd5f4fad8b7a092b96e7cc7b.tar.bz2 |
Pair ActivityStacks with Displays
- Introduce concept of ActivityStacks residing on Displays and able
to be decoupled and moved around.
- Add a new interface, IActivityContainer for clients to handle
ActivityStacks.
- Abandon ordering of stacks based on mStackState and instead use
ActivityDisplayInfo.stacks<ActivityStack> ordering.
Progress towards closing bug 12078972.
Change-Id: I7785b61c26dc17f432a4803eebee07c7415fcc1f
Diffstat (limited to 'services')
7 files changed, 716 insertions, 412 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 05666b4..4540c1c 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -28,13 +28,15 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import android.app.AppOpsManager; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.appwidget.AppWidgetManager; import android.graphics.Rect; import android.util.ArrayMap; -import android.view.Display; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; +import com.android.internal.app.ProcessMap; import com.android.internal.app.ProcessStats; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; @@ -47,7 +49,6 @@ import com.android.internal.util.Preconditions; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.IntentResolver; -import com.android.internal.app.ProcessMap; import com.android.server.SystemServer; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; @@ -1770,7 +1771,6 @@ public final class ActivityManagerService extends ActivityManagerNative public void setWindowManager(WindowManagerService wm) { mWindowManager = wm; mStackSupervisor.setWindowManager(wm); - wm.createStack(HOME_STACK_ID, Display.DEFAULT_DISPLAY); } public void startObservingNativeCrashes() { @@ -1801,7 +1801,7 @@ public final class ActivityManagerService extends ActivityManagerNative m.mFactoryTest = factoryTest; m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface()); - m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper); + m.mStackSupervisor = new ActivityStackSupervisor(m); m.mBatteryStatsService.publish(context); m.mUsageStatsService.publish(context); @@ -7096,22 +7096,28 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public int createStack(int taskId) { + public IBinder getHomeActivityToken() throws RemoteException { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "createStack()"); - if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId); + "getHomeActivityToken()"); synchronized (this) { - long ident = Binder.clearCallingIdentity(); - try { - int stackId = mStackSupervisor.createStack(); - mWindowManager.createStack(stackId, Display.DEFAULT_DISPLAY); - if (taskId > 0) { - moveTaskToStack(taskId, stackId, true); - } - return stackId; - } finally { - Binder.restoreCallingIdentity(ident); + return mStackSupervisor.getHomeActivityToken(); + } + } + + @Override + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "createActivityContainer()"); + synchronized (this) { + if (parentActivityToken == null) { + throw new IllegalArgumentException("parent token must not be null"); } + ActivityRecord r = ActivityRecord.forToken(parentActivityToken); + if (r == null) { + return null; + } + return mStackSupervisor.createActivityContainer(r, callback); } } @@ -7150,11 +7156,11 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public List<StackInfo> getAllStackInfos() { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "getStackBoxes()"); + "getAllStackInfos()"); long ident = Binder.clearCallingIdentity(); try { synchronized (this) { - return mStackSupervisor.getAllStackInfos(); + return mStackSupervisor.getAllStackInfosLocked(); } } finally { Binder.restoreCallingIdentity(ident); @@ -7168,7 +7174,7 @@ public final class ActivityManagerService extends ActivityManagerNative long ident = Binder.clearCallingIdentity(); try { synchronized (this) { - return mStackSupervisor.getStackInfo(stackId); + return mStackSupervisor.getStackInfoLocked(stackId); } } finally { Binder.restoreCallingIdentity(ident); @@ -14049,18 +14055,21 @@ public final class ActivityManagerService extends ActivityManagerNative boolean kept = true; final ActivityStack mainStack = mStackSupervisor.getFocusedStack(); - 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 = mainStack.topRunningActivityLocked(null); - } - - if (starting != null) { - kept = mainStack.ensureActivityConfigurationLocked(starting, changes); - // And we need to make sure at this point that all other activities - // are made visible with the correct configuration. - mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + // mainStack is null during startup. + if (mainStack != null) { + 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 = mainStack.topRunningActivityLocked(null); + } + + if (starting != null) { + kept = mainStack.ensureActivityConfigurationLocked(starting, changes); + // And we need to make sure at this point that all other activities + // are made visible with the correct configuration. + mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + } } if (values != null && mWindowManager != null) { diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 49f29fe..38b01df 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -21,6 +21,7 @@ import com.android.internal.R.styleable; import com.android.internal.app.ResolverActivity; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import android.app.ActivityOptions; import android.app.ResultInfo; @@ -138,6 +139,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity + ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); String stringName; // for caching of toString(). diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 82d29a9..690574c 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -39,6 +39,7 @@ import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import com.android.server.wm.AppTransition; import com.android.server.wm.TaskGroup; import com.android.server.wm.WindowManagerService; @@ -52,7 +53,6 @@ import android.app.IThumbnailReceiver; import android.app.ResultInfo; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -139,8 +139,6 @@ final class ActivityStack { final ActivityManagerService mService; final WindowManagerService mWindowManager; - final Context mContext; - /** * The back history of all previous (and possibly still * running) activities. It contains #TaskRecord objects. @@ -230,6 +228,8 @@ final class ActivityStack { final int mStackId; + final ActivityContainer mActivityContainer; + /** Run all ActivityStacks through this */ final ActivityStackSupervisor mStackSupervisor; @@ -327,14 +327,14 @@ final class ActivityStack { return count; } - ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) { - mHandler = new ActivityStackHandler(looper); - mService = service; - mWindowManager = service.mWindowManager; - mStackSupervisor = service.mStackSupervisor; - mContext = context; - mStackId = stackId; - mCurrentUser = service.mCurrentUserId; + ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) { + mActivityContainer = activityContainer; + mStackSupervisor = activityContainer.getOuter(); + mService = mStackSupervisor.mService; + mHandler = new ActivityStackHandler(mService.mHandler.getLooper()); + mWindowManager = mService.mWindowManager; + mStackId = activityContainer.mStackId; + mCurrentUser = mService.mCurrentUserId; } boolean okToShow(ActivityRecord r) { @@ -436,25 +436,6 @@ final class ActivityStack { return null; } - boolean containsApp(ProcessRecord app) { - if (app == null) { - return false; - } - for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.finishing) { - continue; - } - if (r.app == app) { - return true; - } - } - } - return false; - } - final boolean updateLRUListLocked(ActivityRecord r) { final boolean hadit = mLRUActivities.remove(r); mLRUActivities.add(r); @@ -465,6 +446,13 @@ final class ActivityStack { return mStackId == HOME_STACK_ID; } + ArrayList<ActivityStack> getStacksLocked() { + if (mActivityContainer.isAttached()) { + return mActivityContainer.mActivityDisplayInfo.stacks; + } + return null; + } + /** * Returns the top activity in any existing task matching the given * Intent. Returns null if no such task is found. diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 4a46288..f1ac7fe 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -37,6 +37,8 @@ import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.app.IActivityManager; import android.app.IApplicationThread; import android.app.IThumbnailReceiver; @@ -54,6 +56,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.graphics.Point; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -69,9 +74,11 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; -import android.util.SparseIntArray; +import android.util.SparseArray; +import android.util.SparseIntArray; import android.view.Display; +import android.view.DisplayInfo; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.os.TransferPipe; import com.android.server.am.ActivityManagerService.PendingActivityLaunch; @@ -84,7 +91,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -public final class ActivityStackSupervisor { +public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG = ActivityManagerService.DEBUG || false; static final boolean DEBUG_ADD_REMOVE = DEBUG || false; static final boolean DEBUG_APP = DEBUG || false; @@ -108,19 +115,22 @@ public final class ActivityStackSupervisor { static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2; static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3; static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4; + static final int HANDLE_DISPLAY_ADDED = FIRST_SUPERVISOR_STACK_MSG + 5; + static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6; + static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7; + // For debugging to make sure the caller when acquiring/releasing our // wake lock is the system process. static final boolean VALIDATE_WAKE_LOCK_CALLER = false; final ActivityManagerService mService; - final Context mContext; - final Looper mLooper; final ActivityStackSupervisorHandler mHandler; /** Short cut */ WindowManagerService mWindowManager; + DisplayManager mDisplayManager; /** Dismiss the keyguard after the next activity is displayed? */ boolean mDismissKeyguardOnNextActivity = false; @@ -143,14 +153,10 @@ public final class ActivityStackSupervisor { * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */ private ActivityStack mFocusedStack; - /** 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; + /** If this is the same as mFocusedStack then the activity on the top of the focused stack has + * been resumed. If stacks are changing position this will hold the old stack until the new + * stack becomes resumed after which it will be set to the new stack. */ + private ActivityStack mLastFocusedStack; /** List of activities that are waiting for a new activity to become visible before completing * whatever operation they are supposed to do. */ @@ -207,14 +213,17 @@ public final class ActivityStackSupervisor { /** Stack id of the front stack when user switched, indexed by userId. */ SparseIntArray mUserStackInFront = new SparseIntArray(2); - public ActivityStackSupervisor(ActivityManagerService service, Context context, - Looper looper) { + /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); + + /** Mapping from displayId to display current state */ + SparseArray<ActivityDisplayInfo> mDisplayInfos = new SparseArray<ActivityDisplayInfo>(); + + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; - mContext = context; - mLooper = looper; - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mHandler = new ActivityStackSupervisorHandler(looper); + mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper()); if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { throw new IllegalStateException("Calling must be system uid"); } @@ -224,9 +233,23 @@ public final class ActivityStackSupervisor { } void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; - mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID); - mStacks.add(mHomeStack); + synchronized (mService) { + mWindowManager = wm; + + mDisplayManager = + (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE); + mDisplayManager.registerDisplayListener(this, null); + + Display[] displays = mDisplayManager.getDisplays(); + for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) { + final int displayId = displays[displayNdx].getDisplayId(); + ActivityDisplayInfo info = new ActivityDisplayInfo(displayId); + mDisplayInfos.put(displayId, info); + } + + createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); + mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); + } } void dismissKeyguard() { @@ -238,43 +261,38 @@ public final class ActivityStackSupervisor { } ActivityStack getFocusedStack() { - if (mFocusedStack == null) { - return mHomeStack; - } - 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 mFocusedStack; - } + return mFocusedStack; } 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 mFocusedStack; - } + return mLastFocusedStack; } + // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the + // top of all visible stacks. boolean isFrontStack(ActivityStack stack) { - return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack()); + ArrayList<ActivityStack> stacks = stack.getStacksLocked(); + if (stacks != null && !stacks.isEmpty()) { + return stack == stacks.get(stacks.size() - 1); + } + return false; } void moveHomeStack(boolean toFront) { - final boolean homeInFront = isFrontStack(mHomeStack); - if (homeInFront ^ toFront) { - if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" + - stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ? - STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT)); - mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT; + ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked(); + int topNdx = stacks.size() - 1; + if (topNdx <= 0) { + return; + } + ActivityStack topStack = stacks.get(topNdx); + final boolean homeInFront = topStack == mHomeStack; + if (homeInFront != toFront) { + mLastFocusedStack = topStack; + stacks.remove(mHomeStack); + stacks.add(toFront ? topNdx : 0, mHomeStack); + mFocusedStack = stacks.get(topNdx); + if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new=" + + mFocusedStack); } } @@ -302,21 +320,29 @@ public final class ActivityStackSupervisor { } TaskRecord anyTaskForIdLocked(int id) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); - TaskRecord task = stack.taskForIdLocked(id); - if (task != null) { - return task; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); + TaskRecord task = stack.taskForIdLocked(id); + if (task != null) { + return task; + } } } return null; } ActivityRecord isInAnyStackLocked(IBinder token) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token); - if (r != null) { - return r; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token); + if (r != null) { + return r; + } } } return null; @@ -341,14 +367,11 @@ public final class ActivityStackSupervisor { } if (stack.removeTask(task) && !stack.isHomeStack()) { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack); - mStacks.remove(stack); + stack.mActivityContainer.detachLocked(); final int stackId = stack.mStackId; final int nextStackId = mWindowManager.removeStack(stackId); // TODO: Perhaps we need to let the ActivityManager determine the next focus... - if (mFocusedStack == null || mFocusedStack.mStackId == stackId) { - // If this is the last app stack, set mFocusedStack to null. - mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId); - } + mFocusedStack = getStack(nextStackId); } } @@ -368,25 +391,28 @@ public final class ActivityStackSupervisor { } boolean attachApplicationLocked(ProcessRecord app) throws Exception { - boolean didSomething = false; final String processName = app.processName; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - ActivityRecord hr = stack.topRunningActivityLocked(null); - if (hr != null) { - if (hr.app == null && app.uid == hr.info.applicationInfo.uid - && processName.equals(hr.processName)) { - try { - if (realStartActivityLocked(hr, app, true, true)) { - didSomething = true; + boolean didSomething = false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack)) { + continue; + } + ActivityRecord hr = stack.topRunningActivityLocked(null); + if (hr != null) { + if (hr.app == null && app.uid == hr.info.applicationInfo.uid + && processName.equals(hr.processName)) { + try { + if (realStartActivityLocked(hr, app, true, true)) { + didSomething = true; + } + } catch (Exception e) { + Slog.w(TAG, "Exception in new application when starting activity " + + hr.intent.getComponent().flattenToShortString(), e); + throw e; } - } catch (Exception e) { - Slog.w(TAG, "Exception in new application when starting activity " - + hr.intent.getComponent().flattenToShortString(), e); - throw e; } } } @@ -398,53 +424,52 @@ public final class ActivityStackSupervisor { } boolean allResumedActivitiesIdle() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - final ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity == null || !resumedActivity.idle) { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack)) { + continue; + } + final ActivityRecord resumedActivity = stack.mResumedActivity; + if (resumedActivity == null || !resumedActivity.idle) { + return false; + } } } return true; } boolean allResumedActivitiesComplete() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - final ActivityRecord r = stack.mResumedActivity; - if (r != null && r.state != ActivityState.RESUMED) { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + 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: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_BACK)); - mStackState = STACK_STATE_HOME_IN_BACK; - break; - case STACK_STATE_HOME_TO_FRONT: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_FRONT)); - mStackState = STACK_STATE_HOME_IN_FRONT; - break; - } + if (DEBUG_STACK) Slog.d(TAG, + "allResumedActivitiesComplete: mLastFocusedStack changing from=" + + mLastFocusedStack + " to=" + mFocusedStack); + mLastFocusedStack = mFocusedStack; 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; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mResumedActivity; + if (r != null && (!r.nowVisible || r.waitingVisible)) { + return false; + } } } return true; @@ -457,13 +482,16 @@ public final class ActivityStackSupervisor { */ boolean pauseBackStacks(boolean userLeaving) { boolean someActivityPaused = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack) && stack.mResumedActivity != null) { - if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + - " mResumedActivity=" + stack.mResumedActivity); - stack.startPausingLocked(userLeaving, false); - someActivityPaused = true; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack) && stack.mResumedActivity != null) { + if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + + " mResumedActivity=" + stack.mResumedActivity); + stack.startPausingLocked(userLeaving, false); + someActivityPaused = true; + } } } return someActivityPaused; @@ -471,17 +499,20 @@ public final class ActivityStackSupervisor { boolean allPausedActivitiesComplete() { boolean pausing = true; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - final ActivityRecord r = stack.mPausingActivity; - if (r != null && r.state != ActivityState.PAUSED - && r.state != ActivityState.STOPPED - && r.state != ActivityState.STOPPING) { - if (DEBUG_STATES) { - Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); - pausing = false; - } else { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mPausingActivity; + if (r != null && r.state != ActivityState.PAUSED + && r.state != ActivityState.STOPPED + && r.state != ActivityState.STOPPING) { + if (DEBUG_STATES) { + Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); + pausing = false; + } else { + return false; + } } } } @@ -523,8 +554,10 @@ public final class ActivityStackSupervisor { return r; } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // Return to the home stack. + final ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (stack != focusedStack && isFrontStack(stack)) { r = stack.topRunningActivityLocked(null); if (r != null) { @@ -540,15 +573,19 @@ public final class ActivityStackSupervisor { ActivityRecord r = null; // Gather all of the running tasks for each stack into runningTaskLists. - final int numStacks = mStacks.size(); - ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks]; - for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); - runningTaskLists[stackNdx] = stackTaskList; - final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); - if (isFrontStack(stack)) { - r = ar; + ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = + new ArrayList<ArrayList<RunningTaskInfo>>(); + final int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); + runningTaskLists.add(stackTaskList); + final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); + if (r == null && isFrontStack(stack)) { + r = ar; + } } } @@ -557,8 +594,9 @@ public final class ActivityStackSupervisor { while (maxNum > 0) { long mostRecentActiveTime = Long.MIN_VALUE; ArrayList<RunningTaskInfo> selectedStackList = null; - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx]; + final int numTaskLists = runningTaskLists.size(); + for (int stackNdx = 0; stackNdx < numTaskLists; ++stackNdx) { + ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists.get(stackNdx); if (!stackTaskList.isEmpty()) { final long lastActiveTime = stackTaskList.get(0).lastActiveTime; if (lastActiveTime > mostRecentActiveTime) { @@ -1264,7 +1302,7 @@ public final class ActivityStackSupervisor { if (mFocusedStack != taskStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task); - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; + mFocusedStack = taskStack; } else { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Focused stack already=" + mFocusedStack); @@ -1272,24 +1310,28 @@ public final class ActivityStackSupervisor { return taskStack; } - if (mFocusedStack != null) { + if (mFocusedStack != mHomeStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; } - for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); - if (!stack.isHomeStack()) { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "adjustStackFocus: Setting focused stack=" + stack); - mFocusedStack = stack; - return mFocusedStack; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); + if (!stack.isHomeStack()) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Setting focused stack=" + stack); + mFocusedStack = stack; + return mFocusedStack; + } } } - // Time to create the first app stack for this user. - int stackId = mService.createStack(-1); + // Need to create an app stack for this user. + int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -1299,30 +1341,10 @@ public final class ActivityStackSupervisor { } void setFocusedStack(ActivityRecord r) { - if (r == null) { - return; - } - if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) { - if (mStackState != STACK_STATE_HOME_IN_FRONT) { - if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_FRONT; - } - } else { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task + - " Callers=" + Debug.getCallers(3)); - final ActivityStack taskStack = r.task.stack; - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; - if (mStackState != STACK_STATE_HOME_IN_BACK) { - if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_BACK; - } + if (r != null) { + final boolean isHomeActivity = + !r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask()); + moveHomeStack(isHomeActivity); } } @@ -1938,17 +1960,21 @@ public final class ActivityStackSupervisor { boolean handleAppDiedLocked(ProcessRecord app) { boolean hasVisibleActivities = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app); + } } return hasVisibleActivities; } void closeSystemDialogsLocked() { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.closeSystemDialogsLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).closeSystemDialogsLocked(); + } } } @@ -1961,11 +1987,14 @@ public final class ActivityStackSupervisor { */ boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { - didSomething = true; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { + didSomething = true; + } } } return didSomething; @@ -1980,15 +2009,18 @@ public final class ActivityStackSupervisor { // we don't blow away the previous app if this activity is being // hosted by the process that is actually still the foreground. ProcessRecord fgApp = null; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - if (stack.mResumedActivity != null) { - fgApp = stack.mResumedActivity.app; - } else if (stack.mPausingActivity != null) { - fgApp = stack.mPausingActivity.app; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + if (stack.mResumedActivity != null) { + fgApp = stack.mResumedActivity.app; + } else if (stack.mPausingActivity != null) { + fgApp = stack.mPausingActivity.app; + } + break; } - break; } } @@ -2012,13 +2044,16 @@ public final class ActivityStackSupervisor { targetStack = getFocusedStack(); } boolean result = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - if (stack == targetStack) { - result = stack.resumeTopActivityLocked(target, targetOptions); - } else { - stack.resumeTopActivityLocked(null); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + if (stack == targetStack) { + result = stack.resumeTopActivityLocked(target, targetOptions); + } else { + stack.resumeTopActivityLocked(null); + } } } } @@ -2026,38 +2061,91 @@ public final class ActivityStackSupervisor { } void finishTopRunningActivityLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.finishTopRunningActivityLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.finishTopRunningActivityLocked(app); + } } } void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { - if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + - mStacks.get(stackNdx)); - return; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { + if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + + stacks.get(stackNdx)); + return; + } } } } ActivityStack getStack(int stackId) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.getStackId() == stackId) { - return stack; - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } ArrayList<ActivityStack> getStacks() { - return new ArrayList<ActivityStack>(mStacks); + ArrayList<ActivityStack> allStacks = new ArrayList<ActivityStack>(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + allStacks.addAll(mDisplayInfos.valueAt(displayNdx).stacks); + } + return allStacks; + } + + IBinder getHomeActivityToken() { + final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = tasks.get(taskNdx); + if (task.isHomeTask()) { + final ArrayList<ActivityRecord> activities = task.mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.isHomeActivity()) { + return r.appToken; + } + } + } + } + return null; + } + + ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId, + IActivityContainerCallback callback) { + ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId, + callback); + mActivityContainers.put(stackId, activityContainer); + if (parentActivity != null) { + parentActivity.mChildContainers.add(activityContainer.mStack); + } + return activityContainer; + } + + ActivityContainer createActivityContainer(ActivityRecord parentActivity, + IActivityContainerCallback callback) { + return createActivityContainer(parentActivity, getNextStackId(), callback); + } + + private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) { + ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId); + if (displayInfo == null) { + return -1; + } + + ActivityContainer activityContainer = + createActivityContainer(parentActivity, stackId, null); + activityContainer.attachToDisplayLocked(displayInfo); + return stackId; } - int createStack() { + int getNextStackId() { while (true) { if (++mLastStackId <= HOME_STACK_ID) { mLastStackId = HOME_STACK_ID + 1; @@ -2066,7 +2154,6 @@ public final class ActivityStackSupervisor { break; } } - mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId)); return mLastStackId; } @@ -2088,15 +2175,18 @@ public final class ActivityStackSupervisor { ActivityRecord findTaskLocked(ActivityRecord r) { if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!r.isApplicationActivity() && !stack.isHomeStack()) { - if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); - continue; - } - final ActivityRecord ar = stack.findTaskLocked(r); - if (ar != null) { - return ar; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!r.isApplicationActivity() && !stack.isHomeStack()) { + if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); + continue; + } + final ActivityRecord ar = stack.findTaskLocked(r); + if (ar != null) { + return ar; + } } } if (DEBUG_TASKS) Slog.d(TAG, "No task found"); @@ -2104,10 +2194,13 @@ public final class ActivityStackSupervisor { } ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info); - if (ar != null) { - return ar; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info); + if (ar != null) { + return ar; + } } } return null; @@ -2135,8 +2228,11 @@ public final class ActivityStackSupervisor { final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (cantShutdown) { long timeRemaining = endTime - System.currentTimeMillis(); @@ -2167,11 +2263,14 @@ public final class ActivityStackSupervisor { if (mGoingToSleep.isHeld()) { mGoingToSleep.release(); } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.awakeFromSleepingLocked(); - if (isFrontStack(stack)) { - resumeTopActivitiesLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.awakeFromSleepingLocked(); + if (isFrontStack(stack)) { + resumeTopActivitiesLocked(); + } } } mGoingToSleepActivities.clear(); @@ -2190,8 +2289,11 @@ public final class ActivityStackSupervisor { if (!mSleepTimeout) { boolean dontSleep = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (mStoppingActivities.size() > 0) { @@ -2214,8 +2316,11 @@ public final class ActivityStackSupervisor { } } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).goToSleep(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).goToSleep(); + } } removeSleepTimeouts(); @@ -2242,37 +2347,45 @@ public final class ActivityStackSupervisor { } void handleAppCrashLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.handleAppCrashLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.handleAppCrashLocked(app); + } } } void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) { // First the front stacks. In case any are not fullscreen and are in front of home. boolean showHomeBehindStack = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - showHomeBehindStack = - stack.ensureActivitiesVisibleLocked(starting, configChanges); - } - } - // Now do back stacks. - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stackNdx == topStackNdx) { + // Top stack. + showHomeBehindStack = + stack.ensureActivitiesVisibleLocked(starting, configChanges); + } else { + // Back stack. + stack.ensureActivitiesVisibleLocked(starting, configChanges, + showHomeBehindStack); + } } } } void scheduleDestroyAllActivities(ProcessRecord app, String reason) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.scheduleDestroyActivities(app, false, reason); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.scheduleDestroyActivities(app, false, reason); + } } } @@ -2282,8 +2395,11 @@ public final class ActivityStackSupervisor { mCurrentUser = userId; mStartingUsers.add(uss); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).switchUserLocked(userId); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).switchUserLocked(userId); + } } ActivityStack stack = getStack(restoreStackId); @@ -2337,8 +2453,9 @@ public final class ActivityStackSupervisor { } void validateTopActivitiesLocked() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // FIXME +/* for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.topRunningActivityLocked(null); final ActivityState state = r == null ? ActivityState.DESTROYED : r.state; if (isFrontStack(stack)) { @@ -2368,23 +2485,14 @@ public final class ActivityStackSupervisor { } } } - } - - private static String stackStateToString(int stackState) { - switch (stackState) { - case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT"; - case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK"; - case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK"; - case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT"; - default: return "Unknown stackState=" + stackState; - } +*/ } public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity="); pw.println(mDismissKeyguardOnNextActivity); pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack); - pw.print(" mStackState="); pw.println(stackStateToString(mStackState)); + pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack); pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout); pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); @@ -2413,42 +2521,48 @@ public final class ActivityStackSupervisor { boolean dumpClient, String dumpPackage) { boolean printed = false; boolean needSep = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - StringBuilder stackHeader = new StringBuilder(128); - stackHeader.append(" Stack #"); - stackHeader.append(mStacks.indexOf(stack)); - stackHeader.append(":"); - printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep, - stackHeader.toString()); - printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, !dumpAll, - false, dumpPackage, true, " Running activities (most recent first):", null); - - needSep = printed; - boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, - " mPausingActivity: "); - if (pr) { - printed = true; - needSep = false; - } - pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, - " mResumedActivity: "); - if (pr) { - printed = true; - needSep = false; - } - if (dumpAll) { - pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, - " mLastPausedActivity: "); + for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) { + ActivityDisplayInfo info = mDisplayInfos.valueAt(displayNdx); + pw.print("Display #"); pw.println(info.mDisplayId); + ArrayList<ActivityStack> stacks = info.stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + StringBuilder stackHeader = new StringBuilder(128); + stackHeader.append(" Stack #"); + stackHeader.append(stack.mStackId); + stackHeader.append(":"); + printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, + needSep, stackHeader.toString()); + printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, + !dumpAll, false, dumpPackage, true, + " Running activities (most recent first):", null); + + needSep = printed; + boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, + " mPausingActivity: "); + if (pr) { + printed = true; + needSep = false; + } + pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, + " mResumedActivity: "); if (pr) { printed = true; - needSep = true; + needSep = false; + } + if (dumpAll) { + pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, + " mLastPausedActivity: "); + if (pr) { + printed = true; + needSep = true; + } + printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, + needSep, " mLastNoHistoryActivity: "); } - printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, - needSep, " mLastNoHistoryActivity: "); + needSep = printed; } - needSep = printed; } printed |= dumpHistoryList(fd, pw, mFinishingActivities, " ", "Fin", false, !dumpAll, @@ -2578,6 +2692,95 @@ public final class ActivityStackSupervisor { mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT); } + @Override + public void onDisplayAdded(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0)); + } + + @Override + public void onDisplayRemoved(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0)); + } + + @Override + public void onDisplayChanged(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0)); + } + + public void handleDisplayAddedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = new ActivityDisplayInfo(displayId); + mDisplayInfos.put(displayId, info); + } + mWindowManager.onDisplayAdded(displayId); + } + + public void handleDisplayRemovedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = mDisplayInfos.get(displayId); + if (info != null) { + ArrayList<ActivityStack> stacks = info.stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + info.detachActivities(stacks.get(stackNdx)); + } + mDisplayInfos.remove(displayId); + } + } + mWindowManager.onDisplayRemoved(displayId); + } + + public void handleDisplayChangedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = mDisplayInfos.get(displayId); + if (info != null) { + // TODO: Update the bounds. + } + } + mWindowManager.onDisplayChanged(displayId); + } + + StackInfo getStackInfo(ActivityStack stack) { + StackInfo info = new StackInfo(); + mWindowManager.getStackBounds(stack.mStackId, info.bounds); + info.displayId = Display.DEFAULT_DISPLAY; + info.stackId = stack.mStackId; + + ArrayList<TaskRecord> tasks = stack.getAllTasks(); + final int numTasks = tasks.size(); + int[] taskIds = new int[numTasks]; + String[] taskNames = new String[numTasks]; + for (int i = 0; i < numTasks; ++i) { + final TaskRecord task = tasks.get(i); + taskIds[i] = task.taskId; + taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() + : task.realActivity != null ? task.realActivity.flattenToString() + : task.getTopActivity() != null ? task.getTopActivity().packageName + : "unknown"; + } + info.taskIds = taskIds; + info.taskNames = taskNames; + return info; + } + + StackInfo getStackInfoLocked(int stackId) { + ActivityStack stack = getStack(stackId); + if (stack != null) { + return getStackInfo(stack); + } + return null; + } + + ArrayList<StackInfo> getAllStackInfosLocked() { + ArrayList<StackInfo> list = new ArrayList<StackInfo>(); + for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) { + list.add(getStackInfo(stacks.get(ndx))); + } + } + return list; + } + private final class ActivityStackSupervisorHandler extends Handler { public ActivityStackSupervisorHandler(Looper looper) { @@ -2641,46 +2844,131 @@ public final class ActivityStackSupervisor { } } } break; + case HANDLE_DISPLAY_ADDED: { + handleDisplayAddedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_CHANGED: { + handleDisplayChangedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_REMOVED: { + handleDisplayRemovedLocked(msg.arg1); + } break; } } } - StackInfo getStackInfo(ActivityStack stack) { - StackInfo info = new StackInfo(); - mWindowManager.getStackBounds(stack.mStackId, info.bounds); - info.displayId = Display.DEFAULT_DISPLAY; - info.stackId = stack.mStackId; + class ActivityContainer extends IActivityContainer.Stub { + final int mStackId; + final IActivityContainerCallback mCallback; + final ActivityStack mStack; + final ActivityRecord mParentActivity; - ArrayList<TaskRecord> tasks = stack.getAllTasks(); - final int numTasks = tasks.size(); - int[] taskIds = new int[numTasks]; - String[] taskNames = new String[numTasks]; - for (int i = 0; i < numTasks; ++i) { - final TaskRecord task = tasks.get(i); - taskIds[i] = task.taskId; - taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() - : task.realActivity != null ? task.realActivity.flattenToString() - : task.getTopActivity() != null ? task.getTopActivity().packageName - : "unknown"; + /** Display this ActivityStack is currently on. Null if not attached to a Display. */ + ActivityDisplayInfo mActivityDisplayInfo; + + ActivityContainer(ActivityRecord parentActivity, int stackId, + IActivityContainerCallback callback) { + synchronized (mService) { + mStackId = stackId; + mStack = new ActivityStack(this); + mParentActivity = parentActivity; + mCallback = callback; + } } - info.taskIds = taskIds; - info.taskNames = taskNames; - return info; - } - StackInfo getStackInfo(int stackId) { - ActivityStack stack = getStack(stackId); - if (stack != null) { - return getStackInfo(stack); + void attachToDisplayLocked(ActivityDisplayInfo displayInfo) { + mActivityDisplayInfo = displayInfo; + displayInfo.attachActivities(mStack); + mWindowManager.createStack(mStackId, displayInfo.mDisplayId); + } + + @Override + public void attachToDisplay(int displayId) throws RemoteException { + synchronized (mService) { + ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId); + if (displayInfo == null) { + return; + } + attachToDisplayLocked(displayInfo); + } + } + + @Override + public int getStackId() throws RemoteException { + return mStack.mStackId; + } + + void detachLocked() { + if (mActivityDisplayInfo != null) { + mActivityDisplayInfo.detachActivities(mStack); + mActivityDisplayInfo = null; + } + } + + @Override + public void detachFromDisplay() throws RemoteException { + synchronized (mService) { + detachLocked(); + } + } + + @Override + public void startActivity(Intent intent) throws RemoteException { + + } + + @Override + public IBinder asBinder() { + return this; + } + + ActivityStackSupervisor getOuter() { + return ActivityStackSupervisor.this; + } + + boolean isAttached() { + return mActivityDisplayInfo != null; + } + + void getBounds(Point outBounds) { + if (mActivityDisplayInfo != null) { + mActivityDisplayInfo.getBounds(outBounds); + } else { + outBounds.set(0, 0); + } } - return null; } - ArrayList<StackInfo> getAllStackInfos() { - ArrayList<StackInfo> list = new ArrayList<StackInfo>(); - for (int ndx = mStacks.size() - 1; ndx >= 0; --ndx) { - list.add(getStackInfo(mStacks.get(ndx))); + /** Exactly one of these classes per Display in the system. Capable of holding zero or more + * attached {@link ActivityStack}s */ + final class ActivityDisplayInfo { + /** Actual Display this object tracks. */ + final int mDisplayId; + final Display mDisplay; + final DisplayInfo mDisplayInfo = new DisplayInfo(); + + /** All of the stacks on this display. Order matters, topmost stack is in front of all other + * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ + final ArrayList<ActivityStack> stacks = new ArrayList<ActivityStack>(); + + ActivityDisplayInfo(int displayId) { + mDisplayId = displayId; + mDisplay = mDisplayManager.getDisplay(displayId); + mDisplay.getDisplayInfo(mDisplayInfo); + } + + void attachActivities(ActivityStack stack) { + stacks.add(stack); + } + + void detachActivities(ActivityStack stack) { + stacks.remove(stack); + } + + void getBounds(Point bounds) { + mDisplay.getDisplayInfo(mDisplayInfo); + bounds.x = mDisplayInfo.appWidth; + bounds.y = mDisplayInfo.appHeight; } - return list; } } diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java index 4352ece..4064377 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -27,6 +27,7 @@ import android.util.EventLog; import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; +import android.view.Surface; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -211,10 +212,15 @@ class DisplayContent { void getLogicalDisplayRect(Rect out) { updateDisplayInfo(); // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. + final int orientation = mDisplayInfo.rotation; + boolean rotated = (orientation == Surface.ROTATION_90 + || orientation == Surface.ROTATION_270); + final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; + final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; int width = mDisplayInfo.logicalWidth; - int left = (mBaseDisplayWidth - width) / 2; + int left = (physWidth - width) / 2; int height = mDisplayInfo.logicalHeight; - int top = (mBaseDisplayHeight - height) / 2; + int top = (physHeight - height) / 2; out.set(left, top, left + width, top + height); } @@ -247,8 +253,12 @@ class DisplayContent { mStacks.add(toTop ? mStacks.size() : 0, stack); } - TaskStack topStack() { - return mStacks.get(mStacks.size() - 1); + TaskStack removeStack(TaskStack stack) { + mStacks.remove(stack); + if (!mStacks.isEmpty()) { + return mStacks.get(mStacks.size() - 1); + } + return null; } /** diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java index df1d108..ef245f9 100644 --- a/services/java/com/android/server/wm/TaskStack.java +++ b/services/java/com/android/server/wm/TaskStack.java @@ -205,7 +205,11 @@ public class TaskStack { mAnimationBackgroundSurface.destroySurface(); mDimLayer.destroySurface(); EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); - return mDisplayContent.topStack().mStackId; + TaskStack next = mDisplayContent.removeStack(this); + if (next != null) { + return next.mStackId; + } + return -1; } void resetAnimationBackgroundAnimator() { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index e50d61f..04129e2 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -4842,7 +4842,9 @@ public class WindowManagerService extends IWindowManager.Stub int nextStackId = stack.remove(); stack.getDisplayContent().layoutNeeded = true; requestTraversalLocked(); - return nextStackId; + if (nextStackId > HOME_STACK_ID) { + return nextStackId; + } } if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId); } @@ -8778,7 +8780,8 @@ public class WindowManagerService extends IWindowManager.Stub if (canBeSeen) { // This function assumes that the contents of the default display are // processed first before secondary displays. - if (w.mDisplayContent.isDefaultDisplay) { + final DisplayContent displayContent = w.mDisplayContent; + if (displayContent.isDefaultDisplay) { // While a dream or keyguard is showing, obscure ordinary application // content on secondary displays (by forcibly enabling mirroring unless // there is other content we want to show) but still allow opaque |