Modify StackBox and TaskStack methods.
Also add dump() throughout.
Change-Id: I5369d2e71262645d9b1015bd4e72fad395cc7547
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f98d2d2..69ba3bb 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1991,7 +1991,7 @@
group.tokens.add(r.appToken);
}
}
- mService.mWindowManager.validateAppTokens(mValidateAppTokens);
+ mService.mWindowManager.validateAppTokens(mStackId, mValidateAppTokens);
}
/**
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 0cd3136..bcefc41 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -80,7 +80,7 @@
*/
final AppTokenList mExitingAppTokens = new AppTokenList();
- ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
+ private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
/**
* Sorted most recent at top, oldest at [0].
@@ -113,6 +113,11 @@
return mDisplayInfo;
}
+ /**
+ * Retrieve the tasks on this display in stack order from the topmost TaskStack down.
+ * Note that the order of TaskStacks in the same StackBox is defined within StackBox.
+ * @return All the Tasks, in order, on this display.
+ */
ArrayList<Task> getTasks() {
mTmpTasks.clear();
int numBoxes = mStackBoxes.size();
@@ -126,6 +131,7 @@
mDisplay.getDisplayInfo(mDisplayInfo);
}
+ /** @return The number of tokens in all of the Tasks on this display. */
int numTokens() {
getTasks();
int count = 0;
@@ -135,6 +141,7 @@
return count;
}
+ /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
TaskStack createStack(int stackId, int relativeStackId, int position, float weight) {
TaskStack newStack = null;
if (mStackBoxes.isEmpty()) {
@@ -150,8 +157,7 @@
if (position == StackBox.TASK_STACK_GOES_OVER
|| position == StackBox.TASK_STACK_GOES_UNDER) {
// Position indicates a new box is added at top level only.
- final TaskStack stack = box.mStack;
- if (stack != null && stack.mStackId == relativeStackId) {
+ if (box.contains(relativeStackId)) {
final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
StackBox newBox = new StackBox(this, box.mBounds);
newStack = new TaskStack(stackId, newBox);
@@ -167,13 +173,15 @@
}
}
}
- if (stackBoxNdx >= 0) {
- throw new IllegalArgumentException("createStack: stackId " + stackId + " not found.");
+ if (stackBoxNdx < 0) {
+ throw new IllegalArgumentException("createStack: stackId " + relativeStackId
+ + " not found.");
}
}
return newStack;
}
+ /** Refer to {@link WindowManagerService#resizeStack(int, float)} */
boolean resizeStack(int stackId, float weight) {
int stackBoxNdx;
for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
@@ -185,6 +193,24 @@
return false;
}
+ /**
+ * Reorder a StackBox within mStackBox. The StackBox to reorder is the one containing the
+ * specified TaskStack.
+ * @param stackId The TaskStack to reorder.
+ * @param toTop Move to the top of all StackBoxes if true, to the bottom if false. Only the
+ * topmost layer of StackBoxes, those in mStackBoxes can be reordered.
+ */
+ void moveStackBox(int stackId, boolean toTop) {
+ for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+ final StackBox box = mStackBoxes.get(stackBoxNdx);
+ if (box.contains(stackId)) {
+ mStackBoxes.remove(box);
+ mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
+ return;
+ }
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
final String subPrefix = " " + prefix;
@@ -209,6 +235,10 @@
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
+ for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
+ pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
+ mStackBoxes.get(boxNdx).dump(prefix + " ", pw);
+ }
int ndx = numTokens();
if (ndx > 0) {
pw.println();
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index bd007e5..4bdb406 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
+import java.io.PrintWriter;
import java.util.ArrayList;
public class StackBox {
@@ -29,15 +30,32 @@
public static final int TASK_STACK_GOES_OVER = 4;
public static final int TASK_STACK_GOES_UNDER = 5;
+ /** The display this box sits in. */
final DisplayContent mDisplayContent;
+
+ /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
+ * is this entire size of mDisplayContent. */
StackBox mParent;
- boolean mVertical;
+
+ /** First child, this is null exactly when mStack is non-null. */
StackBox mFirst;
+
+ /** Second child, this is null exactly when mStack is non-null. */
StackBox mSecond;
- float mWeight;
+
+ /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
TaskStack mStack;
+
+ /** Content limits relative to the DisplayContent this sits in. */
Rect mBounds;
+
+ /** Relative orientation of mFirst and mSecond. */
+ boolean mVertical;
+
+ /** Dirty flag. Something inside this or some descendant of this has changed. */
boolean layoutNeeded;
+
+ /** Used to keep from reallocating a temporary array to hold the list of Tasks below */
ArrayList<Task> mTmpTasks = new ArrayList<Task>();
StackBox(DisplayContent displayContent, Rect bounds) {
@@ -62,6 +80,28 @@
}
}
+ /**
+ * Detremine if a particular TaskStack is in this StackBox or any of its descendants.
+ * @param stackId The TaskStack being considered.
+ * @return true if the specified TaskStack is in this box or its descendants. False otherwise.
+ */
+ boolean contains(int stackId) {
+ if (mStack != null) {
+ return mStack.mStackId == stackId;
+ }
+ return mFirst.contains(stackId) || mSecond.contains(stackId);
+ }
+
+ /**
+ * Create a new TaskStack relative to a specified one by splitting the StackBox containing
+ * the specified TaskStack into two children. The size and position each of the new StackBoxes
+ * is determined by the passed parameters.
+ * @param stackId The id of the new TaskStack to create.
+ * @param relativeStackId The id of the TaskStack to place the new one next to.
+ * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
+ * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
+ * @return The new TaskStack.
+ */
TaskStack split(int stackId, int relativeStackId, int position, float weight) {
if (mStack != null) {
if (mStack.mStackId == relativeStackId) {
@@ -112,6 +152,7 @@
mStack = null;
return stack;
}
+ // Not the intended TaskStack.
return null;
}
@@ -123,51 +164,11 @@
return mSecond.split(stackId, relativeStackId, position, weight);
}
- TaskStack merge(int position) {
- TaskStack stack = null;
- if (mFirst != null) {
- switch (position) {
- default:
- case TASK_STACK_GOES_BEFORE:
- case TASK_STACK_GOES_ABOVE:
- stack = mFirst.merge(position);
- stack.merge(mSecond.merge(position));
- break;
- case TASK_STACK_GOES_AFTER:
- case TASK_STACK_GOES_BELOW:
- stack = mSecond.merge(position);
- stack.merge(mFirst.merge(position));
- break;
- }
- return stack;
- }
- return mStack;
- }
-
- boolean merge(int stackId, int position, StackBox primary, StackBox secondary) {
- TaskStack stack = primary.mStack;
- if (stack != null && stack.mStackId == stackId) {
- stack.merge(secondary.merge(position));
- mStack = stack;
- mFirst = null;
- mSecond = null;
- return true;
- }
- return false;
- }
-
- boolean merge(int stackId, int position) {
- if (mFirst != null) {
- if (merge(stackId, position, mFirst, mSecond)
- || merge(stackId, position, mSecond, mFirst)
- || mFirst.merge(stackId, position)
- || mSecond.merge(stackId, position)) {
- return true;
- }
- }
- return false;
- }
-
+ /**
+ * @return List of all Tasks underneath this StackBox. The order is currently mFirst followed
+ * by mSecond putting mSecond Tasks more recent than mFirst Tasks.
+ * TODO: Change to MRU ordering.
+ */
ArrayList<Task> getTasks() {
mTmpTasks.clear();
if (mStack != null) {
@@ -179,37 +180,55 @@
return mTmpTasks;
}
- void absorb(StackBox box) {
- mFirst = box.mFirst;
- mSecond = box.mSecond;
- mStack = box.mStack;
+ /** Combine a child StackBox into its parent.
+ * @param child The surviving child to be merge up into this StackBox. */
+ void absorb(StackBox child) {
+ mFirst = child.mFirst;
+ mSecond = child.mSecond;
+ mStack = child.mStack;
layoutNeeded = true;
}
- void removeStack() {
- if (mParent != null) {
- if (mParent.mFirst == this) {
- mParent.absorb(mParent.mSecond);
- } else {
- mParent.absorb(mParent.mFirst);
- }
- mParent.makeDirty();
- }
- }
-
- boolean addTaskToStack(Task task, int stackId, boolean toTop) {
+ /** Return the stackId of the first mFirst StackBox with a non-null mStack */
+ int getStackId() {
if (mStack != null) {
- if (mStack.mStackId == stackId) {
- mStack.addTask(task, toTop);
- return true;
- }
- return false;
+ return mStack.mStackId;
}
- return mFirst.addTaskToStack(task, stackId, toTop)
- || mSecond.addTaskToStack(task, stackId, toTop);
+ return mFirst.getStackId();
}
+ /** Remove this box and propagate its sibling's content up to their parent.
+ * @return The first stackId of the resulting StackBox. */
+ int removeStack() {
+ if (mParent.mFirst == this) {
+ mParent.absorb(mParent.mSecond);
+ } else {
+ mParent.absorb(mParent.mFirst);
+ }
+ mParent.makeDirty();
+ return getStackId();
+ }
+
+ /** TODO: */
boolean resize(int stackId, float weight) {
return false;
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mParent="); pw.println(mParent);
+ pw.print(prefix); pw.print("mFirst="); pw.println(mFirst);
+ pw.print(prefix); pw.print("mSecond="); pw.println(mSecond);
+ pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
+ pw.print("mVertical="); pw.print(mVertical);
+ pw.print("layoutNeeded="); pw.println(layoutNeeded);
+ if (mStack != null) {
+ pw.print(prefix); pw.print("mStack="); pw.println(mStack);
+ mStack.dump(prefix + " ", pw);
+ } else {
+ pw.print(prefix); pw.print("mFirst="); pw.println(mStack);
+ mFirst.dump(prefix + " ", pw);
+ pw.print(prefix); pw.print("mSecond="); pw.println(mStack);
+ mSecond.dump(prefix + " ", pw);
+ }
+ }
}
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 4d34b36..753ef0d 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -16,14 +16,22 @@
package com.android.server.wm;
+import java.io.PrintWriter;
import java.util.ArrayList;
public class TaskStack {
+ /** Unique identifier */
final int mStackId;
- final DisplayContent mDisplayContent;
+
+ /** The display this stack sits under. */
+ private final DisplayContent mDisplayContent;
+
+ /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
+ * mTaskHistory in the ActivityStack with the same mStackId */
private ArrayList<Task> mTasks = new ArrayList<Task>();
- int mLayer;
- StackBox mParent;
+
+ /** The StackBox this sits in. */
+ private final StackBox mParent;
TaskStack(int stackId, StackBox parent) {
mStackId = stackId;
@@ -46,9 +54,15 @@
return taskLists;
}
+ /**
+ * Put a Task in this stack. Used for adding and moving.
+ * @param task The task to add.
+ * @param toTop Whether to add it to the top or bottom.
+ */
void addTask(Task task, boolean toTop) {
mParent.makeDirty();
mTasks.add(toTop ? mTasks.size() : 0, task);
+ mDisplayContent.moveStackBox(mStackId, toTop);
}
void moveTaskToTop(Task task) {
@@ -61,6 +75,12 @@
addTask(task, false);
}
+ /**
+ * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from
+ * its parent StackBox and merge the parent.
+ * @param task The Task to delete.
+ * @return True if #task was in this stack.
+ */
boolean removeTask(Task task) {
mParent.makeDirty();
if (mTasks.remove(task)) {
@@ -72,6 +92,10 @@
return false;
}
+ int remove() {
+ return mParent.removeStack();
+ }
+
int numTokens() {
int count = 0;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -79,4 +103,11 @@
}
return count;
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
+ for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
+ pw.print(prefix); pw.println(mTasks.get(taskNdx));
+ }
+ }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d586f7b..0b42a2d 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3169,7 +3169,7 @@
// Application Window Tokens
// -------------------------------------------------------------
- public void validateAppTokens(List<TaskGroup> tasks) {
+ public void validateAppTokens(int stackId, List<TaskGroup> tasks) {
synchronized (mWindowMap) {
int t = tasks.size() - 1;
if (t < 0) {
@@ -3186,7 +3186,7 @@
return;
}
- final ArrayList<Task> localTasks = displayContent.getTasks();
+ final ArrayList<Task> localTasks = mStackIdToStack.get(stackId).getTasks();
int taskNdx;
for (taskNdx = localTasks.size() - 1; taskNdx >= 0 && t >= 0; --taskNdx, --t) {
AppTokenList localTokens = localTasks.get(taskNdx).mAppTokens;
@@ -3230,6 +3230,10 @@
}
}
+ public void validateStackOrder(Integer[] remoteStackIds) {
+ // TODO:
+ }
+
boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -4685,10 +4689,18 @@
TaskStack stack = getDefaultDisplayContentLocked().createStack(stackId,
relativeStackId, position, weight);
mStackIdToStack.put(stackId, stack);
- performLayoutAndPlaceSurfacesLocked();
}
}
+ public int removeStack(int stackId) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack != null) {
+ mStackIdToStack.delete(stackId);
+ return stack.remove();
+ }
+ return -1;
+ }
+
public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);