Fixed some issues with resuming already resumed activity

- Don’t adjust focus stack when a stack is left empty because we moved
the last task in it to the stack that will be the new top (focused).
Focus can be temporarily adjusted to another stack which we don’t want.
- Protect against trying to resume an already resumed activity in
ASS.resumeFocusedStackTopActivityLocked. This will just cause a crash
on the client side.
- In ASS.moveTasksToFullscreenStackLocked defer resume activity call
until we are done moving all the tasks to the new stack.
- In ASS.moveTaskToStackUncheckedLocked check top running activity
instead of just the top activity when we are trying to determine if
the task as focus and resumed. It is possible the resumed activity
in the task isn’t the top most because the top most is still
initializing or going away.

Bug: 28219871
Change-Id: I8c1113503f6f83d39983375a4f92155ddc04f20f
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 21fc4d8..7eebe79 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -74,6 +74,7 @@
 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.am.ActivityStackSupervisor.MOVING;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
@@ -220,6 +221,17 @@
     // activities and there is a specific combination of stacks.
     static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
 
+    /* The various modes for the method {@link #removeTask}. */
+    // Task is being completely removed from all stacks in the system.
+    static final int REMOVE_TASK_MODE_DESTROYING = 0;
+    // Task is being removed from this stack so we can add it to another stack. In the case we are
+    // moving we don't want to perform some operations on the task like removing it from window
+    // manager or recents.
+    static final int REMOVE_TASK_MODE_MOVING = 1;
+    // Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new
+    // stack and the new stack will be on top of all stacks.
+    static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
+
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
     private final RecentTasks mRecentTasks;
@@ -4920,18 +4932,18 @@
     }
 
     void removeTask(TaskRecord task, String reason) {
-        removeTask(task, reason, !MOVING);
+        removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
     }
 
     /**
      * Removes the input task from this stack.
      * @param task to remove.
      * @param reason for removal.
-     * @param moving task to another stack. In the case we are moving we don't want to perform
-     *               some operations on the task like removing it from window manager or recents.
+     * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING},
+     *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
      */
-    void removeTask(TaskRecord task, String reason, boolean moving) {
-        if (!moving) {
+    void removeTask(TaskRecord task, String reason, int mode) {
+        if (mode == REMOVE_TASK_MODE_DESTROYING) {
             mStackSupervisor.removeLockedTaskLocked(task);
             mWindowManager.removeTask(task.taskId);
             if (!StackId.persistTaskBounds(mStackId)) {
@@ -4957,7 +4969,7 @@
         mTaskHistory.remove(task);
         updateTaskMovement(task, true);
 
-        if (!moving && task.mActivities.isEmpty()) {
+        if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
             // TODO: VI what about activity?
             final boolean isVoiceSession = task.voiceSession != null;
             if (isVoiceSession) {
@@ -4976,8 +4988,10 @@
 
         if (mTaskHistory.isEmpty()) {
             if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
-            // We only need to adjust focused stack if this stack is in focus.
-            if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
+            // We only need to adjust focused stack if this stack is in focus and we are not in the
+            // process of moving the task to the top of the stack that will be focused.
+            if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP
+                    && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
                 if (mFullscreen
                         || !adjustFocusToNextFocusableStackLocked(
@@ -5025,7 +5039,7 @@
     }
 
     void addTask(final TaskRecord task, final boolean toTop, String reason) {
-        final ActivityStack prevStack = preAddTask(task, reason);
+        final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
         task.stack = this;
         if (toTop) {
@@ -5040,7 +5054,7 @@
     void positionTask(final TaskRecord task, int position) {
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.stack.mResumedActivity;
-        final ActivityStack prevStack = preAddTask(task, "positionTask");
+        final ActivityStack prevStack = preAddTask(task, "positionTask", ON_TOP);
         task.stack = this;
         insertTaskAtPosition(task, position);
         postAddTask(task, prevStack);
@@ -5054,10 +5068,11 @@
         }
     }
 
-    private ActivityStack preAddTask(TaskRecord task, String reason) {
+    private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
         final ActivityStack prevStack = task.stack;
         if (prevStack != null && prevStack != this) {
-            prevStack.removeTask(task, reason, MOVING);
+            prevStack.removeTask(task, reason,
+                    toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
         }
         return prevStack;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 20ef0e8..4bf28b2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -167,6 +167,7 @@
 import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
 import static com.android.server.am.ActivityStack.STACK_VISIBLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
@@ -1785,7 +1786,10 @@
         if (targetStack != null && isFocusedStack(targetStack)) {
             return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
-        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
+        if (r == null || r.state != RESUMED) {
+            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        }
         return false;
     }
 
@@ -2134,8 +2138,11 @@
                 for (int i = 0; i < size; i++) {
                     moveTaskToStackLocked(tasks.get(i).taskId,
                             FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
-                            "moveTasksToFullscreenStack", ANIMATE);
+                            "moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME);
                 }
+
+                ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+                resumeFocusedStackTopActivityLocked();
             } else {
                 for (int i = size - 1; i >= 0; i--) {
                     positionTaskInStackLocked(tasks.get(i).taskId,
@@ -2338,7 +2345,7 @@
             }
             // Remove current stack association, so we can re-associate the task with the
             // right stack below.
-            task.stack.removeTask(task, "restoreRecentTaskLocked", MOVING);
+            task.stack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
         }
 
         final ActivityStack stack =
@@ -2381,7 +2388,7 @@
                     + "support multi-window task=" + task + " to stackId=" + stackId);
         }
 
-        final ActivityRecord r = task.getTopActivity();
+        final ActivityRecord r = task.topRunningActivityLocked();
         final ActivityStack prevStack = task.stack;
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = prevStack.mResumedActivity == r;