Allow stacks to hold tasks on various sizes.

Tasks are now resizeable just like stacks. Adjusting the size
of a stack will also adjust the size of all it's containing
tasks. This model allows us to be more flexible
in using stacks as workspaces (like you would have in a
desktop environment) and tasks as the resizeable windows
within the workspace.

Also added "adb shell dumpsys window visible-apps" for
getting the list of visible app windows.

Bug: 22068114
Bug: 19182363

Change-Id: I5bf77063252a5abae4e327f6fc42e607091749f9
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b1ac7ee..e7f28c5 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -99,6 +99,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -1283,7 +1284,7 @@
             app.forceProcessStateUpTo(mService.mTopProcessState);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
-                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
+                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                     task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                     newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
 
@@ -2871,9 +2872,54 @@
             return;
         }
 
-        final Configuration overrideConfig = mWindowManager.resizeStack(stackId, bounds);
-        if (stack.updateOverrideConfiguration(overrideConfig)) {
+        final IntArray changedTaskIds = new IntArray(stack.numTasks());
+        final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
+        stack.mFullscreen =
+                mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs);
+        for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
+            final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
+            if (task == null) {
+                Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
+                continue;
+            }
+            task.updateOverrideConfiguration(newTaskConfigs.get(i));
+        }
+
+        if (r != null) {
+            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
+            // And we need to make sure at this point that all other activities
+            // are made visible with the correct configuration.
+            ensureActivitiesVisibleLocked(r, 0);
+            if (!updated) {
+                resumeTopActivitiesLocked(stack, null, null);
+            }
+        }
+    }
+
+    void resizeTaskLocked(TaskRecord task, Rect bounds) {
+        if (!task.mResizeable) {
+            Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
+            return;
+        }
+
+        if (task.mBounds != null && task.mBounds.equals(bounds)) {
+            // Nothing to do here...
+            return;
+        }
+
+        task.mBounds = new Rect(bounds);
+
+        if (!mWindowManager.isValidTaskId(task.taskId)) {
+            // Task doesn't exist in window manager yet (e.g. was restored from recents).
+            // No need to do anything else until we add the task to window manager.
+            return;
+        }
+
+        final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
+        if (task.updateOverrideConfiguration(overrideConfig)) {
+            ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
+                final ActivityStack stack = task.stack;
                 final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
@@ -2885,48 +2931,6 @@
         }
     }
 
-    /** Makes sure the input task is in a stack with the specified bounds by either resizing the
-     * current task stack if it only has one entry, moving the task to a stack that matches the
-     * bounds, or creating a new stack with the required bounds. Also, makes the task resizeable.*/
-    void resizeTaskLocked(TaskRecord task, Rect bounds) {
-        task.mResizeable = true;
-        final ActivityStack currentStack = task.stack;
-        if (currentStack.isHomeStack()) {
-            // Can't move task off the home stack. Sorry!
-            return;
-        }
-
-        final int matchingStackId = mWindowManager.getStackIdWithBounds(bounds);
-        if (matchingStackId != -1) {
-            // There is already a stack with the right bounds!
-            if (currentStack != null && currentStack.mStackId == matchingStackId) {
-                // Nothing to do here. Already in the right stack...
-                return;
-            }
-            // Move task to stack with matching bounds.
-            moveTaskToStackLocked(task.taskId, matchingStackId, true);
-            return;
-        }
-
-        if (currentStack != null && currentStack.numTasks() == 1) {
-            // Just resize the current stack since this is the task in it.
-            resizeStackLocked(currentStack.mStackId, bounds);
-            return;
-        }
-
-        // Create new stack and move the task to it.
-        final int displayId = (currentStack != null && currentStack.mDisplayId != -1)
-                ? currentStack.mDisplayId : Display.DEFAULT_DISPLAY;
-        ActivityStack newStack = createStackOnDisplay(getNextStackId(), displayId);
-
-        if (newStack == null) {
-            Slog.e(TAG, "resizeTaskLocked: Can't create stack for task=" + task);
-            return;
-        }
-        moveTaskToStackLocked(task.taskId, newStack.mStackId, true);
-        resizeStackLocked(newStack.mStackId, bounds);
-    }
-
     ActivityStack createStackOnDisplay(int stackId, int displayId) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2962,7 +2966,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
+                if (!tmpStack.isHomeStack()) {
                     stack = tmpStack;
                     break;
                 }
@@ -3789,6 +3793,7 @@
         final int numTasks = tasks.size();
         int[] taskIds = new int[numTasks];
         String[] taskNames = new String[numTasks];
+        Rect[] taskBounds = new Rect[numTasks];
         for (int i = 0; i < numTasks; ++i) {
             final TaskRecord task = tasks.get(i);
             taskIds[i] = task.taskId;
@@ -3796,6 +3801,8 @@
                     : task.realActivity != null ? task.realActivity.flattenToString()
                     : task.getTopActivity() != null ? task.getTopActivity().packageName
                     : "unknown";
+            taskBounds[i] = new Rect();
+            mWindowManager.getTaskBounds(task.taskId, taskBounds[i]);
         }
         info.taskIds = taskIds;
         info.taskNames = taskNames;
@@ -3811,7 +3818,7 @@
     }
 
     ArrayList<StackInfo> getAllStackInfosLocked() {
-        ArrayList<StackInfo> list = new ArrayList<StackInfo>();
+        ArrayList<StackInfo> list = new ArrayList<>();
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {