Add retrieval of StackBox info for more flexibility

First step in permitting StackBoxes to be manipulated by user.
Necessary for Configuration changes coming down.

Change-Id: I4029926a35e4fdc59a5759fd9e4bae10bb308413
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index cc69176..4055832 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,6 +19,7 @@
 package com.android.commands.am;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityController;
 import android.app.IActivityManager;
@@ -105,7 +106,7 @@
                 "       am stack create <TASK_ID> <RELATIVE_STACK_ID> <POSITION> <WEIGHT>\n" +
                 "       am stack movetask <STACK_ID> <TASK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <WEIGHT>\n" +
-                "       am stack dump\n" +
+                "       am stack boxes\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -202,7 +203,7 @@
                 "\n" +
                 "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
                 "\n" +
-                "am stack dump: list the hierarchy of stacks.\n" +
+                "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
                 "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -1120,8 +1121,7 @@
         }
 
         @Override
-        public int systemNotResponding(String message)
-                throws RemoteException {
+        public int systemNotResponding(String message) {
             synchronized (this) {
                 System.out.println("** ERROR: PROCESS NOT RESPONDING");
                 System.out.println("message: " + message);
@@ -1486,8 +1486,8 @@
             runStackMoveTask();
         } else if (op.equals("resize")) {
             runStackResize();
-        } else if (op.equals("dump")) {
-            runStackDump();
+        } else if (op.equals("boxes")) {
+            runStackBoxes();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
@@ -1545,11 +1545,11 @@
         }
     }
 
-    private void runStackDump() throws Exception {
+    private void runStackBoxes() throws Exception {
         try {
-            List<ActivityManager.StackInfo> stacks = mAm.getStacks();
-            for (ActivityManager.StackInfo stack : stacks) {
-                System.out.println(stack);
+            List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
+            for (StackBoxInfo info : stackBoxes) {
+                System.out.println(info);
             }
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1f6f421..63ac42e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1238,6 +1238,97 @@
         }
     }
 
+    /**
+     * Information you can retrieve about the WindowManager StackBox hierarchy.
+     * @hide
+     */
+    public static class StackBoxInfo implements Parcelable {
+        public int stackBoxId;
+        public float weight;
+        public boolean vertical;
+        public Rect bounds;
+        public StackBoxInfo[] children;
+        public int stackId;
+        public StackInfo stack;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(stackBoxId);
+            dest.writeFloat(weight);
+            dest.writeInt(vertical ? 1 : 0);
+            bounds.writeToParcel(dest, flags);
+            dest.writeInt(stackId);
+            if (children != null) {
+                children[0].writeToParcel(dest, flags);
+                children[1].writeToParcel(dest, flags);
+            } else {
+                stack.writeToParcel(dest, flags);
+            }
+        }
+
+        public void readFromParcel(Parcel source) {
+            stackBoxId = source.readInt();
+            weight = source.readFloat();
+            vertical = source.readInt() == 1;
+            bounds = Rect.CREATOR.createFromParcel(source);
+            stackId = source.readInt();
+            if (stackId == -1) {
+                children = new StackBoxInfo[2];
+                children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
+                children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
+            } else {
+                stack = StackInfo.CREATOR.createFromParcel(source);
+            }
+        }
+
+        public static final Creator<StackBoxInfo> CREATOR =
+                new Creator<ActivityManager.StackBoxInfo>() {
+
+            @Override
+            public StackBoxInfo createFromParcel(Parcel source) {
+                return new StackBoxInfo(source);
+            }
+
+            @Override
+            public StackBoxInfo[] newArray(int size) {
+                return new StackBoxInfo[size];
+            }
+        };
+
+        public StackBoxInfo() {
+        }
+
+        public StackBoxInfo(Parcel source) {
+            readFromParcel(source);
+        }
+
+        public String toString(String prefix) {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
+            sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
+            sb.append("\n");
+            if (children != null) {
+                sb.append(prefix); sb.append("First child=\n");
+                sb.append(children[0].toString(prefix + "  "));
+                sb.append(prefix); sb.append("Second child=\n");
+                sb.append(children[1].toString(prefix + "  "));
+            } else {
+                sb.append(prefix); sb.append("Stack=\n");
+                sb.append(stack.toString(prefix + "  "));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public String toString() {
+            return toString("");
+        }
+    }
 
     /**
      * Information you can retrieve about an ActivityStack in the system.
@@ -1249,9 +1340,6 @@
         public int[] taskIds;
         public String[] taskNames;
 
-        public StackInfo() {
-        }
-
         @Override
         public int describeContents() {
             return 0;
@@ -1287,22 +1375,29 @@
             }
         };
 
+        public StackInfo() {
+        }
+
         private StackInfo(Parcel source) {
             readFromParcel(source);
         }
 
-        @Override
-        public String toString() {
+        public String toString(String prefix) {
             StringBuilder sb = new StringBuilder(256);
-            sb.append("Stack id="); sb.append(stackId);
+            sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
                     sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
-            final String prefix = "  ";
+            prefix = prefix + "  ";
             for (int i = 0; i < taskIds.length; ++i) {
                 sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
                         sb.append(": "); sb.append(taskNames[i]); sb.append("\n");
             }
             return sb.toString();
         }
+
+        @Override
+        public String toString() {
+            return toString("");
+        }
     }
 
     /**
@@ -1378,10 +1473,12 @@
         public ProcessErrorStateInfo() {
         }
 
+        @Override
         public int describeContents() {
             return 0;
         }
 
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(condition);
             dest.writeString(processName);
@@ -1392,7 +1489,7 @@
             dest.writeString(longMsg);
             dest.writeString(stackTrace);
         }
-        
+
         public void readFromParcel(Parcel source) {
             condition = source.readInt();
             processName = source.readString();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b197f90..84f2c46 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -647,6 +649,14 @@
             return true;
         }
 
+        case GET_STACK_BOXES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            List<StackBoxInfo> list = getStackBoxes();
+            reply.writeNoException();
+            reply.writeTypedList(list);
+            return true;
+        }
+
         case SET_FOCUSED_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int stackId = data.readInt();
@@ -2657,15 +2667,27 @@
         reply.recycle();
     }
     @Override
-    public List<ActivityManager.StackInfo> getStacks() throws RemoteException
+    public List<StackInfo> getStacks() throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         mRemote.transact(GET_STACKS_TRANSACTION, data, reply, 0);
         reply.readException();
-        ArrayList<ActivityManager.StackInfo> list
-                = reply.createTypedArrayList(ActivityManager.StackInfo.CREATOR);
+        ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR);
+        data.recycle();
+        reply.recycle();
+        return list;
+    }
+    @Override
+    public List<StackBoxInfo> getStackBoxes() throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR);
         data.recycle();
         reply.recycle();
         return list;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 334a304..61b81cf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.RunningServiceInfo;
+import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
@@ -119,6 +120,7 @@
             throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
     public void resizeStack(int stackId, float weight) throws RemoteException;
+    public List<StackBoxInfo> getStackBoxes() throws RemoteException;
     public List<StackInfo> getStacks() throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
@@ -663,4 +665,5 @@
     int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
     int GET_STACKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
     int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
+    int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index dcb2984..603a6ed 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -58,6 +58,8 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -6352,7 +6354,7 @@
     }
 
     @Override
-    public List<ActivityManager.StackInfo> getStacks() {
+    public List<StackInfo> getStacks() {
         synchronized (this) {
             ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>();
             ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks();
@@ -6381,6 +6383,34 @@
         }
     }
 
+    private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) {
+        final int stackId = stackBoxInfo.stackId;
+        if (stackId >= 0) {
+            for (StackInfo stackInfo : stackInfos) {
+                if (stackId == stackInfo.stackId) {
+                    stackBoxInfo.stack = stackInfo;
+                    stackInfos.remove(stackInfo);
+                    return;
+                }
+            }
+        } else {
+            addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos);
+            addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos);
+        }
+    }
+
+    @Override
+    public List<StackBoxInfo> getStackBoxes() {
+        List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
+        synchronized (this) {
+            List<StackInfo> stackInfos = getStacks();
+            for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
+                addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
+            }
+        }
+        return stackBoxInfos;
+    }
+
     @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized(this) {
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 0dbcfb8..8ad2ef1 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 
+import android.app.ActivityManager.StackBoxInfo;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.util.Slog;
@@ -284,6 +285,32 @@
         mStackBoxes.remove(box);
     }
 
+    StackBoxInfo getStackBoxInfo(StackBox box) {
+        StackBoxInfo info = new StackBoxInfo();
+        info.stackBoxId = box.mStackBoxId;
+        info.weight = box.mWeight;
+        info.vertical = box.mVertical;
+        info.bounds = new Rect(box.mBounds);
+        if (box.mStack != null) {
+            info.stackId = box.mStack.mStackId;
+            // ActivityManagerService will fill in the StackInfo.
+        } else {
+            info.stackId = -1;
+            info.children = new StackBoxInfo[2];
+            info.children[0] = getStackBoxInfo(box.mFirst);
+            info.children[1] = getStackBoxInfo(box.mSecond);
+        }
+        return info;
+    }
+
+    ArrayList<StackBoxInfo> getStackBoxInfos() {
+        ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
+        }
+        return list;
+    }
+
     /**
      * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
      * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index 3bd1d4c..e2fd105e 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -39,6 +39,11 @@
     /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
     public static final int TASK_STACK_GOES_UNDER = 5;
 
+    static int sCurrentBoxId = 0;
+
+    /** Unique id for this box */
+    final int mStackBoxId;
+
     /** The service */
     final WindowManagerService mService;
 
@@ -74,6 +79,10 @@
     Rect mTmpRect = new Rect();
 
     StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
+        synchronized (StackBox.class) {
+            mStackBoxId = sCurrentBoxId++;
+        }
+
         mService = service;
         mDisplayContent = displayContent;
         mParent = parent;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3ebe083..d19fb2d 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -43,6 +43,7 @@
 import com.android.server.power.ShutdownThread;
 
 import android.Manifest;
+import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
@@ -4882,6 +4883,12 @@
         }
     }
 
+    public ArrayList<StackBoxInfo> getStackBoxInfos() {
+        synchronized(mWindowMap) {
+            return getDefaultDisplayContentLocked().getStackBoxInfos();
+        }
+    }
+
     public Rect getStackBounds(int stackId) {
         DisplayContentsIterator iterator = new DisplayContentsIterator();
         while (iterator.hasNext()) {