Add shell command to move activity stacks between displays
Also rename "stack movetask" command to be consistent with other
shell commands.
Test: New CTS tests coming soon.
Change-Id: I3d7e04e0ae8ea76c27c3e4c1e286d5cd4539870c
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 15f6361..141c899 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -752,6 +752,15 @@
return true;
}
+ case MOVE_STACK_TO_DISPLAY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int stackId = data.readInt();
+ int displayId = data.readInt();
+ moveStackToDisplay(stackId, displayId);
+ reply.writeNoException();
+ return true;
+ }
+
case MOVE_TASK_TO_FRONT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int task = data.readInt();
@@ -3885,6 +3894,19 @@
reply.recycle();
return list;
}
+ public void moveStackToDisplay(int stackId, int displayId) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(stackId);
+ data.writeInt(displayId);
+ mRemote.transact(MOVE_STACK_TO_DISPLAY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ @Override
public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index c075ed6..cada1b8 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -448,13 +448,6 @@
mGuard.open("release");
}
- void attachToDisplay(int displayId) {
- try {
- mIActivityContainer.attachToDisplay(displayId);
- } catch (RemoteException e) {
- }
- }
-
void setSurface(Surface surface, int width, int height, int density)
throws RemoteException {
mIActivityContainer.setSurface(surface, width, height, density);
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 170aff3..1ff3c87 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -25,7 +25,7 @@
/** @hide */
interface IActivityContainer {
- void attachToDisplay(int displayId);
+ void addToDisplay(int displayId);
void setSurface(in Surface surface, int width, int height, int density);
int startActivity(in Intent intent);
int startActivityIntentSender(in IIntentSender intentSender);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0323651..7166789 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -143,6 +143,7 @@
public List<RunningServiceInfo> getServices(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
throws RemoteException;
+ public void moveStackToDisplay(int stackId, int displayId) throws RemoteException;
public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
@@ -1100,4 +1101,5 @@
int REQUEST_ACTIVITY_RELAUNCH = IBinder.FIRST_CALL_TRANSACTION+400;
int UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 401;
int UNREGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+402;
+ int MOVE_STACK_TO_DISPLAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 403;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5d41d36..5aee770 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9513,6 +9513,22 @@
}
@Override
+ public void moveStackToDisplay(int stackId, int displayId) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveStackToDisplay()");
+
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
+ + " to displayId=" + displayId);
+ mStackSupervisor.moveStackToDisplayLocked(stackId, displayId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public boolean removeTask(int taskId) {
enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");
synchronized (this) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8234f35..3efd300 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -215,6 +215,8 @@
return runGetInactive(pw);
case "send-trim-memory":
return runSendTrimMemory(pw);
+ case "display":
+ return runDisplay(pw);
case "stack":
return runStack(pw);
case "task":
@@ -1631,12 +1633,23 @@
return 0;
}
+ int runDisplay(PrintWriter pw) throws RemoteException {
+ String op = getNextArgRequired();
+ switch (op) {
+ case "move-stack":
+ return runDisplayMoveStack(pw);
+ default:
+ getErrPrintWriter().println("Error: unknown command '" + op + "'");
+ return -1;
+ }
+ }
+
int runStack(PrintWriter pw) throws RemoteException {
String op = getNextArgRequired();
switch (op) {
case "start":
return runStackStart(pw);
- case "movetask":
+ case "move-task":
return runStackMoveTask(pw);
case "resize":
return runStackResize(pw);
@@ -1691,6 +1704,15 @@
return new Rect(left, top, right, bottom);
}
+ int runDisplayMoveStack(PrintWriter pw) throws RemoteException {
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ String displayIdStr = getNextArgRequired();
+ int displayId = Integer.parseInt(displayIdStr);
+ mInterface.moveStackToDisplay(stackId, displayId);
+ return 0;
+ }
+
int runStackStart(PrintWriter pw) throws RemoteException {
String displayIdStr = getNextArgRequired();
int displayId = Integer.parseInt(displayIdStr);
@@ -2450,10 +2472,13 @@
pw.println(" send-trim-memory [--user <USER_ID>] <PROCESS>");
pw.println(" [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]");
pw.println(" Send a memory trim event to a <PROCESS>.");
+ pw.println(" display [COMMAND] [...]: sub-commands for operating on displays.");
+ pw.println(" move-stack <STACK_ID> <DISPLAY_ID>");
+ pw.println(" Move <STACK_ID> from its current display to <DISPLAY_ID>.");
pw.println(" stack [COMMAND] [...]: sub-commands for operating on activity stacks.");
pw.println(" start <DISPLAY_ID> <INTENT>");
pw.println(" Start a new activity on <DISPLAY_ID> using <INTENT>");
- pw.println(" movetask <TASK_ID> <STACK_ID> [true|false]");
+ pw.println(" move-task <TASK_ID> <STACK_ID> [true|false]");
pw.println(" Move <TASK_ID> from its current stack to the top (true) or");
pw.println(" bottom (false) of <STACK_ID>.");
pw.println(" resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1c3a885..0d79980 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -449,10 +449,23 @@
? new LaunchingTaskPositioner() : null;
}
- void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+ /** Adds the stack to specified display and calls WindowManager to do the same. */
+ void addToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+ final Rect bounds = mWindowManager.addStackToDisplay(mStackId, activityDisplay.mDisplayId,
+ onTop);
+ postAddToDisplay(activityDisplay, bounds);
+ }
+
+ /**
+ * Updates internal state after adding to new display.
+ * @param activityDisplay New display to which this stack was attached.
+ * @param bounds Updated bounds.
+ */
+ private void postAddToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay,
+ Rect bounds) {
mDisplayId = activityDisplay.mDisplayId;
mStacks = activityDisplay.mStacks;
- mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
+ mBounds = bounds;
mFullscreen = mBounds == null;
if (mTaskPositioner != null) {
mTaskPositioner.setDisplay(activityDisplay.mDisplay);
@@ -468,7 +481,21 @@
}
}
- void remove() {
+ /**
+ * Moves the stack to specified display.
+ * @param activityDisplay Target display to move the stack to.
+ */
+ void moveToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay) {
+ removeFromDisplay();
+ final Rect bounds = mWindowManager.moveStackToDisplay(mStackId, activityDisplay.mDisplayId);
+ postAddToDisplay(activityDisplay, bounds);
+ }
+
+ /**
+ * Updates the inner state of the stack to remove it from its current parent, so it can be
+ * either destroyed completely or re-parented.
+ */
+ private void removeFromDisplay() {
mDisplayId = Display.INVALID_DISPLAY;
mStacks = null;
if (mTaskPositioner != null) {
@@ -480,6 +507,11 @@
mStackSupervisor.resizeDockedStackLocked(
null, null, null, null, null, PRESERVE_WINDOWS);
}
+ }
+
+ /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
+ void remove() {
+ removeFromDisplay();
mStackSupervisor.deleteActivityContainerRecord(mStackId);
mWindowManager.removeStack(mStackId);
onParentChanged();
@@ -696,11 +728,7 @@
}
mStacks.add(addIndex, this);
-
- // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
- if (isOnHomeDisplay()) {
- mStackSupervisor.setFocusStackUnchecked(reason, this);
- }
+ mStackSupervisor.setFocusStackUnchecked(reason, this);
if (task != null) {
insertTaskAtTop(task, null);
return;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index eed8dd7..6167671 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2300,7 +2300,7 @@
ActivityContainer activityContainer = new ActivityContainer(stackId);
mActivityContainers.put(stackId, activityContainer);
- activityContainer.attachToDisplayLocked(activityDisplay, onTop);
+ activityContainer.addToDisplayLocked(activityDisplay, onTop);
return activityContainer.mStack;
}
@@ -2364,6 +2364,40 @@
}
/**
+ * Move stack with all its existing content to specified display.
+ * @param stackId Id of stack to move.
+ * @param displayId Id of display to move stack to.
+ */
+ void moveStackToDisplayLocked(int stackId, int displayId) {
+ final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+ if (activityDisplay == null) {
+ throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId="
+ + displayId);
+ }
+ final ActivityContainer activityContainer = mActivityContainers.get(stackId);
+ if (activityContainer != null) {
+ if (activityContainer.isAttachedLocked()) {
+ if (activityContainer.getDisplayId() == displayId) {
+ throw new IllegalArgumentException("Trying to move stackId=" + stackId
+ + " to its current displayId=" + displayId);
+ }
+
+ activityContainer.moveToDisplayLocked(activityDisplay);
+ } else {
+ throw new IllegalStateException("moveStackToDisplayLocked: Stack with stackId="
+ + stackId + " is not attached to any display.");
+ }
+ } else {
+ throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown stackId="
+ + stackId);
+ }
+
+ ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+ !PRESERVE_WINDOWS);
+ // TODO(multi-display): resize stacks properly if moved from split-screen.
+ }
+
+ /**
* Moves the specified task record to the input stack id.
* WARNING: This method performs an unchecked/raw move of the task and
* can leave the system in an unstable state if used incorrectly.
@@ -4032,22 +4066,33 @@
}
}
- void attachToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
- if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
+ /**
+ * Adds the stack to specified display. Also calls WindowManager to do the same from
+ * {@link ActivityStack#addToDisplay(ActivityDisplay, boolean)}.
+ * @param activityDisplay The display to add the stack to.
+ * @param onTop If true the stack will be place at the top of the display, else at the
+ * bottom.
+ */
+ void addToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "addToDisplayLocked: " + this
+ " to display=" + activityDisplay + " onTop=" + onTop);
+ if (mActivityDisplay != null) {
+ throw new IllegalStateException("ActivityContainer is already attached, " +
+ "displayId=" + mActivityDisplay.mDisplayId);
+ }
mActivityDisplay = activityDisplay;
- mStack.attachDisplay(activityDisplay, onTop);
+ mStack.addToDisplay(activityDisplay, onTop);
activityDisplay.attachActivities(mStack, onTop);
}
@Override
- public void attachToDisplay(int displayId) {
+ public void addToDisplay(int displayId) {
synchronized (mService) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
return;
}
- attachToDisplayLocked(activityDisplay, true);
+ addToDisplayLocked(activityDisplay, true);
}
}
@@ -4103,16 +4148,44 @@
}
}
+ /** Remove the stack completely. */
void removeLocked() {
if (DEBUG_STACK) Slog.d(TAG_STACK, "removeLocked: " + this + " from display="
+ mActivityDisplay + " Callers=" + Debug.getCallers(2));
if (mActivityDisplay != null) {
- mActivityDisplay.detachActivitiesLocked(mStack);
- mActivityDisplay = null;
+ removeFromDisplayLocked();
}
mStack.remove();
}
+ /**
+ * Remove the stack from its current {@link ActivityDisplay}, so it can be either destroyed
+ * completely or re-parented.
+ */
+ private void removeFromDisplayLocked() {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "removeFromDisplayLocked: " + this
+ + " current displayId=" + mActivityDisplay.mDisplayId);
+
+ mActivityDisplay.detachActivitiesLocked(mStack);
+ mActivityDisplay = null;
+ }
+
+ /**
+ * Move the stack to specified display.
+ * @param activityDisplay Target display to move the stack to.
+ */
+ void moveToDisplayLocked(ActivityDisplay activityDisplay) {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveToDisplayLocked: " + this + " from display="
+ + mActivityDisplay + " to display=" + activityDisplay
+ + " Callers=" + Debug.getCallers(2));
+
+ removeFromDisplayLocked();
+
+ mActivityDisplay = activityDisplay;
+ mStack.moveToDisplay(activityDisplay);
+ activityDisplay.attachActivities(mStack, ON_TOP);
+ }
+
@Override
public final int startActivity(Intent intent) {
return mService.startActivity(intent, this);
@@ -4232,7 +4305,7 @@
new VirtualActivityDisplay(width, height, density);
mActivityDisplay = virtualActivityDisplay;
mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
- attachToDisplayLocked(virtualActivityDisplay, true);
+ addToDisplayLocked(virtualActivityDisplay, true);
}
if (mSurface != null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 243c4a5..450ed20 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -74,6 +74,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -184,6 +185,7 @@
// Accessed directly by all users.
private boolean mLayoutNeeded;
int pendingLayoutChanges;
+ // TODO(multi-display): remove some of the usages.
final boolean isDefaultDisplay;
/** Window tokens that are in the process of exiting, but still on screen for animations. */
@@ -535,9 +537,72 @@
out.set(mContentRect);
}
- /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
- void attachStack(TaskStack stack, boolean onTop) {
- mTaskStackContainers.attachStack(stack, onTop);
+ /**
+ * Adds the stack to this display.
+ * @see WindowManagerService#addStackToDisplay(int, int, boolean)
+ */
+ Rect addStackToDisplay(int stackId, boolean onTop) {
+ boolean attachedToDisplay = false;
+ TaskStack stack = mService.mStackIdToStack.get(stackId);
+ if (stack == null) {
+ if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
+ + mDisplayId);
+
+ stack = getStackById(stackId);
+ if (stack != null) {
+ // It's already attached to the display...clear mDeferRemoval and move stack to
+ // appropriate z-order on display as needed.
+ stack.mDeferRemoval = false;
+ moveStack(stack, onTop);
+ attachedToDisplay = true;
+ } else {
+ stack = new TaskStack(mService, stackId);
+ }
+
+ mService.mStackIdToStack.put(stackId, stack);
+ if (stackId == DOCKED_STACK_ID) {
+ mDividerControllerLocked.notifyDockedStackExistsChanged(true);
+ }
+ } else {
+ final DisplayContent currentDC = stack.getDisplayContent();
+ if (currentDC != null) {
+ throw new IllegalStateException("Trying to add stackId=" + stackId
+ + "to displayId=" + mDisplayId + ", but it's already attached to displayId="
+ + currentDC.getDisplayId());
+ }
+ }
+
+ if (!attachedToDisplay) {
+ mTaskStackContainers.addStackToDisplay(stack, onTop);
+ }
+
+ if (stack.getRawFullscreen()) {
+ return null;
+ }
+ final Rect bounds = new Rect();
+ stack.getRawBounds(bounds);
+ return bounds;
+ }
+
+ /** Removes the stack from the display and prepares for changing the parent. */
+ private void removeStackFromDisplay(TaskStack stack) {
+ mTaskStackContainers.removeStackFromDisplay(stack);
+ }
+
+ /** Moves the stack to this display and returns the updated bounds. */
+ Rect moveStackToDisplay(TaskStack stack) {
+ final DisplayContent currentDisplayContent = stack.getDisplayContent();
+ if (currentDisplayContent == null) {
+ throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
+ + " which is not currently attached to any display");
+ }
+ if (stack.getDisplayContent().getDisplayId() == mDisplayId) {
+ throw new IllegalArgumentException("Trying to move stackId=" + stack.mStackId
+ + " to its current displayId=" + mDisplayId);
+ }
+
+ currentDisplayContent.removeStackFromDisplay(stack);
+ return addStackToDisplay(stack.mStackId, true /* onTop */);
}
void moveStack(TaskStack stack, boolean toTop) {
@@ -2394,7 +2459,11 @@
if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
pendingLayoutChanges);
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ // TODO(multi-display): For now adjusting wallpaper only on primary display to avoid
+ // the wallpaper window jumping across displays.
+ // Remove check for default display when there will be support for multiple wallpaper
+ // targets (on different displays).
+ if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
adjustWallpaperWindows();
}
@@ -3078,7 +3147,11 @@
*/
private class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
- void attachStack(TaskStack stack, boolean onTop) {
+ /**
+ * Adds the stack to this container.
+ * @see WindowManagerService#addStackToDisplay(int, int, boolean)
+ */
+ void addStackToDisplay(TaskStack stack, boolean onTop) {
if (stack.mStackId == HOME_STACK_ID) {
if (mHomeStack != null) {
throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
@@ -3089,6 +3162,21 @@
stack.onDisplayChanged(DisplayContent.this);
}
+ /** Removes the stack from its container and prepare for changing the parent. */
+ void removeStackFromDisplay(TaskStack stack) {
+ removeChild(stack);
+ stack.onRemovedFromDisplay();
+ // TODO: remove when window list will be gone.
+ // Manually remove records from window list and tap excluded windows list.
+ for (int i = mWindows.size() - 1; i >= 0; --i) {
+ final WindowState windowState = mWindows.get(i);
+ if (stack == windowState.getStack()) {
+ mWindows.remove(i);
+ mTapExcludedWindows.remove(windowState);
+ }
+ }
+ }
+
void moveStack(TaskStack stack, boolean toTop) {
if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
// This stack is always-on-top silly...
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6325cda..f038135 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -215,49 +215,6 @@
return dc;
}
- /** Adds the input stack id to the input display id and returns the bounds of the added stack.*/
- Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
- final DisplayContent dc = getDisplayContent(displayId);
- if (dc == null) {
- Slog.w(TAG_WM, "addStackToDisplay: Trying to add stackId=" + stackId
- + " to unknown displayId=" + displayId + " callers=" + Debug.getCallers(6));
- return null;
- }
-
- boolean attachedToDisplay = false;
- TaskStack stack = mService.mStackIdToStack.get(stackId);
- if (stack == null) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
-
- stack = dc.getStackById(stackId);
- if (stack != null) {
- // It's already attached to the display...clear mDeferRemoval and move stack to
- // appropriate z-order on display as needed.
- stack.mDeferRemoval = false;
- dc.moveStack(stack, onTop);
- attachedToDisplay = true;
- } else {
- stack = new TaskStack(mService, stackId);
- }
-
- mService.mStackIdToStack.put(stackId, stack);
- if (stackId == DOCKED_STACK_ID) {
- dc.mDividerControllerLocked.notifyDockedStackExistsChanged(true);
- }
- }
-
- if (!attachedToDisplay) {
- dc.attachStack(stack, onTop);
- }
-
- if (stack.getRawFullscreen()) {
- return null;
- }
- final Rect bounds = new Rect();
- stack.getRawBounds(bounds);
- return bounds;
- }
-
boolean isLayoutNeeded() {
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 60ba025..a0270c6 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -793,6 +793,14 @@
void removeImmediately() {
super.removeImmediately();
+ onRemovedFromDisplay();
+ }
+
+ /**
+ * Removes the stack it from its current parent, so it can be either destroyed completely or
+ * re-parented.
+ */
+ void onRemovedFromDisplay() {
mDisplayContent.mDimLayerController.removeDimLayerUser(this);
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
@@ -800,15 +808,13 @@
mAnimationBackgroundSurface.destroySurface();
mAnimationBackgroundSurface = null;
}
- final DockedStackDividerController dividerController =
- mDisplayContent.mDividerControllerLocked;
- mDisplayContent = null;
-
- mService.mWindowPlacerLocked.requestTraversal();
if (mStackId == DOCKED_STACK_ID) {
- dividerController.notifyDockedStackExistsChanged(false);
+ mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false);
}
+
+ mDisplayContent = null;
+ mService.mWindowPlacerLocked.requestTraversal();
}
void resetAnimationBackgroundAnimator() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0abcd9f..91663b0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2721,11 +2721,11 @@
}
void setFocusTaskRegionLocked() {
- if (mFocusedApp != null) {
- final Task task = mFocusedApp.mTask;
- final DisplayContent displayContent = task.getDisplayContent();
+ final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
+ if (focusedTask != null) {
+ final DisplayContent displayContent = focusedTask.getDisplayContent();
if (displayContent != null) {
- displayContent.setTouchExcludeRegion(task);
+ displayContent.setTouchExcludeRegion(focusedTask);
}
}
}
@@ -3425,24 +3425,63 @@
}
/**
- * Create a new TaskStack and place it on a DisplayContent.
+ * Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with
+ * specified stackId.
* @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
- * @return The initial bounds the stack was created with. null means fullscreen.
+ * else at the bottom.
+ * @return The bounds that the stack has after adding. null means fullscreen.
*/
- public Rect attachStack(int stackId, int displayId, boolean onTop) {
+ public Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
- return mRoot.addStackToDisplay(stackId, displayId, onTop);
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ throw new IllegalArgumentException("Trying to add stackId=" + stackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ return dc.addStackToDisplay(stackId, onTop);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ /**
+ * Move a TaskStack from current DisplayContent to specified one.
+ * @param stackId The unique identifier of the new stack.
+ * @param displayId The unique identifier of the new display.
+ */
+ public Rect moveStackToDisplay(int stackId, int displayId) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mWindowMap) {
+ TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("Trying to move unknown stackId=" + stackId
+ + " to displayId=" + displayId);
+ }
+
+ final DisplayContent targetDisplayContent = mRoot.getDisplayContent(displayId);
+ if (targetDisplayContent == null) {
+ throw new IllegalArgumentException("Trying to move stackId=" + stackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ return targetDisplayContent.moveStackToDisplay(stack);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Remove a TaskStack completely.
+ * @param stackId The unique identifier of the stack.
+ */
public void removeStack(int stackId) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);