API for moving top activity in a stack to pinned stack.

* AMS.moveTopStackActivityToPinnedStack can be used to move the top
activity in a stack to the pinned stack and also specify the bounds
the pinned stack should be sized to.
* 'am stack move-top-activity-to-pinned-stack' command for testing
AMS.moveTopStackActivityToPinnedStack API

Bug: 25006507
Change-Id: I8392b4c39d8542153e691be7a627b7f35fd44884
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ed3a1c2..99539e4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4642,6 +4642,51 @@
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
+    void setFocusAndResumeStateIfNeeded(
+            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
+        // If the activity had focus before move focus to this stack.
+        if (setFocus) {
+            // If the activity owns the last resumed activity, transfer that together,
+            // so that we don't resume the same activity again in the new stack.
+            // Apps may depend on onResume()/onPause() being called in pairs.
+            if (setResume) {
+                mResumedActivity = r;
+                // Move the stack in which we are placing the activity to the front. We don't use
+                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
+                // already focused, the call will short-circuit and do nothing.
+                moveToFront(reason);
+            } else {
+                // We need to not only move the stack to the front, but also have the activity
+                // focused. This will achieve both goals.
+                mService.setFocusedActivityLocked(r, reason);
+            }
+        }
+    }
+
+    /**
+     * Moves the input activity from its current stack to this one.
+     * NOTE: The current task of the activity isn't moved to this stack. Instead a new task is
+     * created on this stack which the activity is added to.
+     * */
+    void moveActivityToStack(ActivityRecord r) {
+        final ActivityStack prevStack = r.task.stack;
+        if (prevStack.mStackId == mStackId) {
+            // You are already in the right stack silly...
+            return;
+        }
+
+        final boolean wasFocused = mStackSupervisor.isFrontStack(prevStack)
+                && (mStackSupervisor.topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+
+        final TaskRecord task = createTaskRecord(
+                mStackSupervisor.getNextTaskId(), r.info, r.intent, null, null, true);
+        r.setTask(task, null);
+        task.addActivityToTop(r);
+        setAppTask(r, task);
+        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+    }
+
     private void setAppTask(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
         task.updateOverrideConfiguration(bounds);