Added support for docked stack

Docked stacks occupy a dedicated region on a display.
When a docked stack is present all other static stacks bounds
are restricted to the region of the screen not occupied by
the docked stack.

Change-Id: I6aec3aa19c41a7e756375002f3a925977b5533b5
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a449baf..5a338af 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -184,6 +184,9 @@
     // (e.g. stack) is due to it moving to another container.
     static final boolean MOVING = true;
 
+    // Force the focus to change to the stack we are moving a task to..
+    static final boolean FORCE_FOCUS = true;
+
     // Activity actions an app cannot start if it uses a permission which is not granted.
     private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
             new ArrayMap<>();
@@ -328,6 +331,9 @@
     /** Used to keep resumeTopActivityLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
+    // temp. rect used during resize calculation so we don't need to create a new object each time.
+    private final Rect tempRect = new Rect();
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -2908,16 +2914,13 @@
             return;
         }
 
-        final ActivityRecord r = stack.topRunningActivityLocked(null);
-        if (r != null && !r.task.mResizeable) {
-            Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable.");
-            return;
-        }
+        ActivityRecord r = stack.topRunningActivityLocked(null);
+        final boolean resizeTasks = r != null && r.task.mResizeable;
 
         final IntArray changedTaskIds = new IntArray(stack.numTasks());
         final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
-        stack.mFullscreen =
-                mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs);
+        stack.mFullscreen = mWindowManager.resizeStack(
+                stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
         for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
             final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
             if (task == null) {
@@ -2927,6 +2930,55 @@
             task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
         }
 
+        if (stack.mStackId == DOCKED_STACK_ID) {
+            // Dock stack funness...Yay!
+            if (stack.mFullscreen) {
+                // The dock stack went fullscreen which is kinda like dismissing it.
+                // In this case we make all other static stacks fullscreen and move all
+                // docked stack tasks to the fullscreen stack.
+                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                    if (i != DOCKED_STACK_ID) {
+                        resizeStackLocked(i, null);
+                    }
+                }
+
+                final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                final int count = tasks.size();
+                for (int i = 0; i < count; i++) {
+                    moveTaskToStackLocked(tasks.get(i).taskId,
+                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS);
+                }
+
+                // stack shouldn't contain anymore activities, so nothing to resume.
+                r = null;
+            } else {
+                // Docked stacks occupy a dedicated region on screen so the size of all other
+                // static stacks need to be adjusted so they don't overlap with the docked stack.
+                final int leftChange = stack.mBounds.left - bounds.left;
+                final int rightChange = stack.mBounds.right - bounds.right;
+                final int topChange = stack.mBounds.top - bounds.top;
+                final int bottomChange = stack.mBounds.bottom - bounds.bottom;
+
+                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                    if (i != DOCKED_STACK_ID) {
+                        ActivityStack otherStack = getStack(i);
+                        if (otherStack != null) {
+                            tempRect.set(otherStack.mBounds);
+                            // We adjust the opposing sides of the other stacks to
+                            // the side in the dock stack that changed.
+                            tempRect.left -= rightChange;
+                            tempRect.right -= leftChange;
+                            tempRect.top -= bottomChange;
+                            tempRect.bottom -= topChange;
+                            resizeStackLocked(i, tempRect);
+                        }
+                    }
+                }
+
+            }
+        }
+        stack.mBounds = stack.mFullscreen ? null : new Rect(bounds);
+
         if (r != null) {
             final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
             // And we need to make sure at this point that all other activities
@@ -2968,7 +3020,8 @@
         final boolean wasFrontStack = isFrontStack(task.stack);
         if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) {
             stackId = FULLSCREEN_WORKSPACE_STACK_ID;
-        } else if (bounds != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+        } else if (bounds != null
+                && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
             stackId = FREEFORM_WORKSPACE_STACK_ID;
         }
         if (stackId != task.stack.mStackId) {
@@ -3069,8 +3122,7 @@
      */
     private ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, String reason) {
-        final ActivityStack stack =
-                getStack(stackId, CREATE_IF_NEEDED, toTop);
+        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
         mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
         if (task.stack != null) {
             task.stack.removeTask(task, reason, MOVING);
@@ -3079,26 +3131,39 @@
         return stack;
     }
 
-    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
+    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
             return;
         }
-        ActivityStack stack =
-                moveTaskToStackUncheckedLocked(task, stackId, toTop, "moveTaskToStack");
+        final String reason = "moveTaskToStack";
+        final ActivityRecord top = task.topRunningActivityLocked(null);
+        final boolean adjustFocus = forceFocus || mService.mFocusedActivity == top;
+        final ActivityStack stack =
+                moveTaskToStackUncheckedLocked(task, stackId, toTop, reason);
 
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-            resizeTaskLocked(task, null);
+            resizeTaskLocked(task, stack.mBounds);
         } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
                 && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
             resizeTaskLocked(task, task.mLastNonFullscreenBounds);
+        } else if (stackId == DOCKED_STACK_ID) {
+            resizeTaskLocked(task, stack.mBounds);
+        }
+
+        if (top != null && adjustFocus) {
+            if (mService.mFocusedActivity != top) {
+                mService.setFocusedActivityLocked(top, reason);
+            } else {
+                setFocusedStack(top, reason);
+            }
         }
 
         // 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);
+        ensureActivitiesVisibleLocked(null, 0);
         resumeTopActivitiesLocked();
     }
 
@@ -3659,6 +3724,10 @@
                 stackHeader.append("  Stack #");
                 stackHeader.append(stack.mStackId);
                 stackHeader.append(":");
+                stackHeader.append("\n");
+                stackHeader.append("  mFullscreen=" + stack.mFullscreen);
+                stackHeader.append("\n");
+                stackHeader.append("  mBounds=" + stack.mBounds);
                 printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
                         needSep, stackHeader.toString());
                 printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false,
@@ -4313,7 +4382,9 @@
             mStack.mStacks = activityDisplay.mStacks;
 
             activityDisplay.attachActivities(mStack, onTop);
-            mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
+            mStack.mBounds =
+                    mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
+            mStack.mFullscreen = mStack.mBounds == null;
         }
 
         @Override