summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java19
-rw-r--r--core/java/android/app/ActivityManager.java36
-rw-r--r--core/java/android/app/ActivityManagerNative.java24
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java27
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java55
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java129
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java81
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java29
11 files changed, 336 insertions, 89 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b1e47015be9d..3ed72e5528b8 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -139,6 +139,7 @@ public class Am extends BaseCommand {
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am stack split <STACK_ID> <v|h> [INTENT]\n" +
+ " am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
" am stack list\n" +
" am stack info <STACK_ID>\n" +
" am task lock <TASK_ID>\n" +
@@ -280,6 +281,8 @@ public class Am extends BaseCommand {
" of the current task will be moved to the new stack. Command will also force\n" +
" all current tasks in both stacks to be resizeable.\n" +
"\n" +
+ "am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>" +
+ "\n" +
"am stack list: list all of the activity stacks and their sizes.\n" +
"\n" +
"am stack info: display the information about activity stack <STACK_ID>.\n" +
@@ -1921,6 +1924,8 @@ public class Am extends BaseCommand {
runStackMoveTask();
} else if (op.equals("resize")) {
runStackResize();
+ } else if (op.equals("positiontask")) {
+ runStackPositionTask();
} else if (op.equals("list")) {
runStackList();
} else if (op.equals("info")) {
@@ -1984,6 +1989,20 @@ public class Am extends BaseCommand {
}
}
+ private void runStackPositionTask() throws Exception {
+ String taskIdStr = nextArgRequired();
+ int taskId = Integer.valueOf(taskIdStr);
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ String positionStr = nextArgRequired();
+ int position = Integer.valueOf(positionStr);
+
+ try {
+ mAm.positionTaskInStack(taskId, stackId, position);
+ } catch (RemoteException e) {
+ }
+ }
+
private void runStackList() throws Exception {
try {
List<StackInfo> stacks = mAm.getAllStackInfos();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5974fcfe949a..b7a7d075afc7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -404,6 +404,42 @@ public class ActivityManager {
*/
public static final int COMPAT_MODE_TOGGLE = 2;
+ /**
+ * First static stack stack ID.
+ * @hide
+ */
+ public static final int FIRST_STATIC_STACK_ID = 0;
+
+ /**
+ * Home activity stack ID.
+ * @hide
+ */
+ public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
+
+ /**
+ * ID of stack where fullscreen activities are normally launched into.
+ * @hide
+ */
+ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
+
+ /**
+ * ID of stack where freeform/resized activities are normally launched into.
+ * @hide
+ */
+ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
+
+ /**
+ * Last static stack stack ID.
+ * @hide
+ */
+ public static final int LAST_STATIC_STACK_ID = FREEFORM_WORKSPACE_STACK_ID;
+
+ /**
+ * Start of ID range used by stacks that are created dynamically.
+ * @hide
+ */
+ public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
+
/** @hide */
public int getFrontActivityScreenCompatMode() {
try {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index facaee4b4ca5..abfe2156d837 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -752,6 +752,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case POSITION_TASK_IN_STACK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int taskId = data.readInt();
+ int stackId = data.readInt();
+ int position = data.readInt();
+ positionTaskInStack(taskId, stackId, position);
+ reply.writeNoException();
+ return true;
+ }
+
case GET_ALL_STACK_INFOS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
List<StackInfo> list = getAllStackInfos();
@@ -3469,6 +3479,20 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
@Override
+ public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(taskId);
+ data.writeInt(stackId);
+ data.writeInt(position);
+ mRemote.transact(POSITION_TASK_IN_STACK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ @Override
public List<StackInfo> getAllStackInfos() throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c3e55f1b566e..4944bfcfbc14 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -139,6 +139,7 @@ public interface IActivityManager extends IInterface {
public void moveTaskBackwards(int task) throws RemoteException;
public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
public void resizeStack(int stackId, Rect bounds) throws RemoteException;
+ public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
public List<StackInfo> getAllStackInfos() throws RemoteException;
public StackInfo getStackInfo(int stackId) throws RemoteException;
public boolean isInHomeStack(int taskId) throws RemoteException;
@@ -874,4 +875,5 @@ public interface IActivityManager extends IInterface {
// Start of N transactions
int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 340;
int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 341;
+ int POSITION_TASK_IN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 342;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 266e3c71c2f6..7b50999a90eb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.HOME_STACK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -28,7 +29,6 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -8898,7 +8898,8 @@ public final class ActivityManagerService extends ActivityManagerNative
"createStackOnDisplay()");
synchronized (this) {
final int stackId = mStackSupervisor.getNextStackId();
- final ActivityStack stack = mStackSupervisor.createStackOnDisplay(stackId, displayId);
+ final ActivityStack stack =
+ mStackSupervisor.createStackOnDisplay(stackId, displayId, true /*onTop*/);
if (stack == null) {
return null;
}
@@ -8952,6 +8953,28 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void positionTaskInStack(int taskId, int stackId, int position) {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "positionTaskInStack()");
+ if (stackId == HOME_STACK_ID) {
+ Slog.e(TAG, "positionTaskInStack: Attempt to change the position of task "
+ + taskId + " in/to home stack",
+ new RuntimeException("here").fillInStackTrace());
+ }
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
+ "positionTaskInStack: positioning task=" + taskId
+ + " in stackId=" + stackId + " at position=" + position);
+ mStackSupervisor.positionTaskInStackLocked(taskId, stackId, position);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public List<StackInfo> getAllStackInfos() {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"getAllStackInfos()");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 431b4338552b..e6c8d4382ab5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.HOME_STACK_ID;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -23,8 +25,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
import android.util.ArraySet;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -1211,6 +1211,15 @@ final class ActivityStack {
return true;
}
+ // Any stack that isn't the front stack is not visible, except for the case of the home
+ // stack behind the main application stack since we can have dialog activities on the
+ // main application stack that need the home stack to display behind them.
+ // TODO(multi-window): Also need to add exception for side-by-side stacks.
+ final boolean homeStack = mStackId == HOME_STACK_ID;
+ if (!homeStack) {
+ return false;
+ }
+
/**
* Start at the task above this one and go up, looking for a visible
* fullscreen activity, or a translucent activity that requested the
@@ -1218,10 +1227,10 @@ final class ActivityStack {
*/
for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
final ActivityStack stack = mStacks.get(i);
- // stack above isn't fullscreen, so, we assume we're still visible.
- if (!stack.mFullscreen) {
- continue;
+ if (stack.mStackId != FULLSCREEN_WORKSPACE_STACK_ID) {
+ return false;
}
+
final ArrayList<TaskRecord> tasks = stack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
@@ -2034,6 +2043,31 @@ final class ActivityStack {
return null;
}
+ private void insertTaskAtPosition(TaskRecord task, int position) {
+ if (position >= mTaskHistory.size()) {
+ insertTaskAtTop(task, null);
+ return;
+ }
+ // Calculate maximum possible position for this task.
+ int maxPosition = mTaskHistory.size();
+ if (!mStackSupervisor.isCurrentProfileLocked(task.userId)
+ && task.topRunningActivityLocked(null) == null) {
+ // Put non-current user tasks below current user tasks.
+ while (maxPosition > 0) {
+ final TaskRecord tmpTask = mTaskHistory.get(maxPosition - 1);
+ if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
+ || tmpTask.topRunningActivityLocked(null) == null) {
+ break;
+ }
+ maxPosition--;
+ }
+ }
+ position = Math.min(position, maxPosition);
+ mTaskHistory.remove(task);
+ mTaskHistory.add(position, task);
+ updateTaskMovement(task, true);
+ }
+
private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
// If the moving task is over home stack, transfer its return type to next task
if (task.isOverHomeStack()) {
@@ -4363,6 +4397,17 @@ final class ActivityStack {
}
}
+ void positionTask(final TaskRecord task, int position, boolean moving) {
+ task.stack = this;
+ insertTaskAtPosition(task, position);
+ if (!moving && task.voiceSession != null) {
+ try {
+ task.voiceSession.taskStarted(task.intent, task.taskId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
public int getStackId() {
return mStackId;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e7f28c5cd3df..4169754d61e7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,6 +17,12 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.app.ActivityManager.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.FIRST_STATIC_STACK_ID;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
@@ -146,8 +152,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
- public static final int HOME_STACK_ID = 0;
-
/** How long we wait until giving up on the last activity telling us it is idle. */
static final int IDLE_TIMEOUT = 10 * 1000;
@@ -214,8 +218,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
WindowManagerService mWindowManager;
DisplayManager mDisplayManager;
- /** Identifier counter for all ActivityStacks */
- private int mLastStackId = HOME_STACK_ID;
+ /** Counter for next free stack ID to use for dynamic activity stacks. */
+ private int mNextFreeStackId = FIRST_DYNAMIC_STACK_ID;
/** Task identifier that activities are currently being started in. Incremented each time a
* new task is created. */
@@ -402,7 +406,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mActivityDisplays.put(displayId, activityDisplay);
}
- createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);
+ createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
@@ -1794,8 +1798,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- // Need to create an app stack for this user.
- stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+ // TODO (multi-window): Change to select task id based on if the task should on in
+ // fullscreen, freefrom, or sid-by-side stack.
+ stack = getStack(
+ FULLSCREEN_WORKSPACE_STACK_ID,
+ true /*createStaticStackIfNeeded*/,
+ true /*createOnTop*/);
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ r + " stackId=" + stack.mStackId);
return stack;
@@ -2782,11 +2790,19 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
ActivityStack getStack(int stackId) {
+ return getStack(stackId, false /*createStaticStackIfNeeded*/, false /*createOnTop*/);
+ }
+
+ ActivityStack getStack(int stackId, boolean createStaticStackIfNeeded, boolean createOnTop) {
ActivityContainer activityContainer = mActivityContainers.get(stackId);
if (activityContainer != null) {
return activityContainer.mStack;
}
- return null;
+ if (!createStaticStackIfNeeded
+ || (stackId < FIRST_STATIC_STACK_ID || stackId > LAST_STATIC_STACK_ID)) {
+ return null;
+ }
+ return createStackOnDisplay(stackId, Display.DEFAULT_DISPLAY, createOnTop);
}
ArrayList<ActivityStack> getStacks() {
@@ -2931,7 +2947,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- ActivityStack createStackOnDisplay(int stackId, int displayId) {
+ ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
return null;
@@ -2939,50 +2955,29 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityContainer activityContainer = new ActivityContainer(stackId);
mActivityContainers.put(stackId, activityContainer);
- activityContainer.attachToDisplayLocked(activityDisplay);
+ activityContainer.attachToDisplayLocked(activityDisplay, onTop);
return activityContainer.mStack;
}
int getNextStackId() {
while (true) {
- if (++mLastStackId <= HOME_STACK_ID) {
- mLastStackId = HOME_STACK_ID + 1;
- }
- if (getStack(mLastStackId) == null) {
+ if (mNextFreeStackId >= FIRST_DYNAMIC_STACK_ID
+ && getStack(mNextFreeStackId) == null) {
break;
}
+ mNextFreeStackId++;
}
- return mLastStackId;
+ return mNextFreeStackId;
}
private boolean restoreRecentTaskLocked(TaskRecord task) {
- ActivityStack stack = null;
- // Determine stack to restore task to.
- if (mLeanbackOnlyDevice) {
- // There is only one stack for lean back devices.
- stack = mHomeStack;
- } else {
- // Look for the top stack on the home display that isn't the home stack.
- final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
- for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
- if (!tmpStack.isHomeStack()) {
- stack = tmpStack;
- break;
- }
- }
- }
-
- if (stack == null) {
- // We couldn't find a stack to restore the task to. Possible if are restoring recents
- // before an application stack is created...Go ahead and create one on the default
- // display.
- stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
- // Restore home stack to top.
- moveHomeStack(true, "restoreRecentTask");
- if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
- "Created stack=" + stack + " for recents restoration.");
- }
+ // TODO (multi-window): Change to select task id based on if the task should on in
+ // fullscreen, freefrom, or sid-by-side stack.
+ // Always put task for lean back device in home stack since they only have one stack,
+ // else use the preferred stack ID to get the stack we should use if it already exists.
+ ActivityStack stack = mLeanbackOnlyDevice ? mHomeStack :
+ getStack(FULLSCREEN_WORKSPACE_STACK_ID,
+ true /*createStaticStackIfNeeded*/, false /*createOnTop*/);
if (stack == null) {
// What does this mean??? Not sure how we would get here...
@@ -3012,11 +3007,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
return;
}
- final ActivityStack stack = getStack(stackId);
- if (stack == null) {
- Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
- return;
- }
+ ActivityStack stack =
+ getStack(stackId, true /*createStaticStackIfNeeded*/, toTop /*createOnTop*/);
mWindowManager.moveTaskToStack(taskId, stackId, toTop);
if (task.stack != null) {
task.stack.removeTask(task, "moveTaskToStack", false /* notMoving */);
@@ -3028,6 +3020,26 @@ public final class ActivityStackSupervisor implements DisplayListener {
resumeTopActivitiesLocked();
}
+ void positionTaskInStackLocked(int taskId, int stackId, int position) {
+ final TaskRecord task = anyTaskForIdLocked(taskId);
+ if (task == null) {
+ Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
+ return;
+ }
+ ActivityStack stack =
+ getStack(stackId, true /*createStaticStackIfNeeded*/, false /*createOnTop*/);
+ mWindowManager.positionTaskInStack(taskId, stackId, position);
+ final boolean stackChanged = task.stack != null && task.stack != stack;
+ if (stackChanged) {
+ task.stack.removeTask(task, "moveTaskToStack", false /* notMoving */);
+ }
+ stack.positionTask(task, position, stackChanged);
+ // The task might have already been running and its visibility needs to be synchronized with
+ // the visibility of the stack / windows.
+ stack.ensureActivitiesVisibleLocked(null, 0);
+ resumeTopActivitiesLocked();
+ }
+
ActivityRecord findTaskLocked(ActivityRecord r) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -4204,15 +4216,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- void attachToDisplayLocked(ActivityDisplay activityDisplay) {
+ void attachToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
- + " to display=" + activityDisplay);
+ + " to display=" + activityDisplay + " onTop=" + onTop);
mActivityDisplay = activityDisplay;
mStack.mDisplayId = activityDisplay.mDisplayId;
mStack.mStacks = activityDisplay.mStacks;
- activityDisplay.attachActivities(mStack);
- mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
+ activityDisplay.attachActivities(mStack, onTop);
+ mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
}
@Override
@@ -4222,7 +4234,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
if (activityDisplay == null) {
return;
}
- attachToDisplayLocked(activityDisplay);
+ attachToDisplayLocked(activityDisplay, true);
}
}
@@ -4435,7 +4447,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
new VirtualActivityDisplay(width, height, density);
mActivityDisplay = virtualActivityDisplay;
mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
- attachToDisplayLocked(virtualActivityDisplay);
+ attachToDisplayLocked(virtualActivityDisplay, true);
}
if (mSurface != null) {
@@ -4521,10 +4533,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
mDisplay.getDisplayInfo(mDisplayInfo);
}
- void attachActivities(ActivityStack stack) {
+ void attachActivities(ActivityStack stack, boolean onTop) {
if (DEBUG_STACK) Slog.v(TAG_STACK,
- "attachActivities: attaching " + stack + " to displayId=" + mDisplayId);
- mStacks.add(stack);
+ "attachActivities: attaching " + stack + " to displayId=" + mDisplayId
+ + " onTop=" + onTop);
+ if (onTop) {
+ mStacks.add(stack);
+ } else {
+ mStacks.add(0, stack);
+ }
}
void detachActivitiesLocked(ActivityStack stack) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d9786c813c31..fcf743e634cf 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,7 +16,8 @@
package com.android.server.wm;
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static android.app.ActivityManager.HOME_STACK_ID;
+
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
@@ -190,15 +191,19 @@ class DisplayContent {
out.set(left, top, left + width, top + height);
}
- /** Refer to {@link WindowManagerService#attachStack(int, int)} */
- void attachStack(TaskStack stack) {
+ /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
+ void attachStack(TaskStack stack, boolean onTop) {
if (stack.mStackId == HOME_STACK_ID) {
if (mHomeStack != null) {
throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
}
mHomeStack = stack;
}
- mStacks.add(stack);
+ if (onTop) {
+ mStacks.add(stack);
+ } else {
+ mStacks.add(0, stack);
+ }
layoutNeeded = true;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 09d70d88cdef..79527b785466 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -131,6 +131,16 @@ class Task implements DimLayer.DimLayerUser {
stack.addTask(this, toTop);
}
+ void positionTaskInStack(TaskStack stack, int position) {
+ if (mStack != null && stack != mStack) {
+ if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
+ + " from stack=" + mStack);
+ EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
+ mStack.removeTask(this);
+ }
+ stack.positionTask(this, position, showForAllUsers());
+ }
+
boolean removeAppToken(AppWindowToken wtoken) {
boolean removed = mAppTokens.remove(wtoken);
if (mAppTokens.size() == 0) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 90a173ab8ccc..aef99bc2d6b1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -183,34 +183,75 @@ public class TaskStack implements DimLayer.DimLayerUser {
* @param showForAllUsers Whether to show the task regardless of the current user.
*/
void addTask(Task task, boolean toTop, boolean showForAllUsers) {
- int stackNdx;
- if (!toTop) {
- stackNdx = 0;
+ positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
+ }
+
+ void positionTask(Task task, int position, boolean showForAllUsers) {
+ final boolean canShowTask =
+ showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
+ mTasks.remove(task);
+ int stackSize = mTasks.size();
+ int minPosition = 0;
+ int maxPosition = stackSize;
+
+ if (canShowTask) {
+ minPosition = computeMinPosition(minPosition, stackSize);
} else {
- stackNdx = mTasks.size();
- if (!showForAllUsers && !mService.isCurrentProfileLocked(task.mUserId)) {
- // Place the task below all current user tasks.
- while (--stackNdx >= 0) {
- final Task tmpTask = mTasks.get(stackNdx);
- if (!tmpTask.showForAllUsers()
- || !mService.isCurrentProfileLocked(tmpTask.mUserId)) {
- break;
- }
- }
- // Put it above first non-current user task.
- ++stackNdx;
- }
+ maxPosition = computeMaxPosition(maxPosition);
}
- if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop
- + " pos=" + stackNdx);
- mTasks.add(stackNdx, task);
+ // Reset position based on minimum/maximum possible positions.
+ position = Math.min(Math.max(position, minPosition), maxPosition);
+
+ if (DEBUG_TASK_MOVEMENT) Slog.d(TAG,
+ "positionTask: task=" + task + " position=" + position);
+ mTasks.add(position, task);
task.mStack = this;
task.updateDisplayInfo(mDisplayContent);
+ boolean toTop = position == mTasks.size() - 1;
if (toTop) {
mDisplayContent.moveStack(this, true);
}
- EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, stackNdx);
+ EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
+ }
+
+ /** Calculate the minimum possible position for a task that can be shown to the user.
+ * The minimum position will be above all other tasks that can't be shown.
+ * @param minPosition The minimum position the caller is suggesting.
+ * We will start adjusting up from here.
+ * @param size The size of the current task list.
+ */
+ private int computeMinPosition(int minPosition, int size) {
+ while (minPosition < size) {
+ final Task tmpTask = mTasks.get(minPosition);
+ final boolean canShowTmpTask =
+ tmpTask.showForAllUsers()
+ || mService.isCurrentProfileLocked(tmpTask.mUserId);
+ if (canShowTmpTask) {
+ break;
+ }
+ minPosition++;
+ }
+ return minPosition;
+ }
+
+ /** Calculate the maximum possible position for a task that can't be shown to the user.
+ * The maximum position will be below all other tasks that can be shown.
+ * @param maxPosition The maximum position the caller is suggesting.
+ * We will start adjusting down from here.
+ */
+ private int computeMaxPosition(int maxPosition) {
+ while (maxPosition > 0) {
+ final Task tmpTask = mTasks.get(maxPosition - 1);
+ final boolean canShowTmpTask =
+ tmpTask.showForAllUsers()
+ || mService.isCurrentProfileLocked(tmpTask.mUserId);
+ if (!canShowTmpTask) {
+ break;
+ }
+ maxPosition--;
+ }
+ return maxPosition;
}
void moveTaskToTop(Task task) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 320edbe6bf8c..68bc77328ffc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5127,8 +5127,10 @@ public class WindowManagerService extends IWindowManager.Stub
* Create a new TaskStack and place it on a DisplayContent.
* @param stackId The unique identifier of the new stack.
* @param displayId The unique identifier of the DisplayContent.
+ * @param onTop If true the stack will be place at the top of the display,
+ * else at the bottom
*/
- public void attachStack(int stackId, int displayId) {
+ public void attachStack(int stackId, int displayId, boolean onTop) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
@@ -5141,7 +5143,7 @@ public class WindowManagerService extends IWindowManager.Stub
mStackIdToStack.put(stackId, stack);
}
stack.attachDisplayContent(displayContent);
- displayContent.attachStack(stack);
+ displayContent.attachStack(stack, onTop);
moveStackWindowsLocked(displayContent);
final WindowList windows = displayContent.getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
@@ -5264,6 +5266,29 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void positionTaskInStack(int taskId, int stackId, int position) {
+ synchronized (mWindowMap) {
+ if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: positioning taskId=" + taskId
+ + " in stackId=" + stackId + " at " + position);
+ Task task = mTaskIdToTask.get(taskId);
+ if (task == null) {
+ if (DEBUG_STACK) Slog.i(TAG,
+ "positionTaskInStack: could not find taskId=" + taskId);
+ return;
+ }
+ TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ if (DEBUG_STACK) Slog.i(TAG,
+ "positionTaskInStack: could not find stackId=" + stackId);
+ return;
+ }
+ task.positionTaskInStack(stack, position);
+ final DisplayContent displayContent = stack.getDisplayContent();
+ displayContent.layoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+
/**
* Re-sizes the specified task and its containing windows.
* Returns a {@link Configuration} object that contains configurations settings