Merge "Do not resume activities that were launched behind" into qt-dev
am: 35885e0769

Change-Id: Ifd866c6957b3cd9cfdb979c76b42396d57984943
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index b3b6efe..d18875f 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2383,7 +2383,11 @@
                 r.setVisible(true);
             }
             if (r != starting) {
-                mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
+                // We should not resume activities that being launched behind because these
+                // activities are actually behind other fullscreen activities, but still required
+                // to be visible (such as performing Recents animation).
+                mStackSupervisor.startSpecificActivityLocked(r, andResume && !r.mLaunchTaskBehind,
+                        true /* checkConfig */);
                 return true;
             }
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 8f41a42..1f8b33e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -24,14 +24,18 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -107,6 +111,39 @@
     }
 
     @Test
+    public void testRestartRecentsActivity() throws Exception {
+        // Have a recents activity that is not attached to its process (ActivityRecord.app = null).
+        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        ActivityStack recentsStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_RECENTS, true /* onTop */);
+        ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
+                mRecentsComponent).setCreateTask(true).setStack(recentsStack).build();
+        WindowProcessController app = recentActivity.app;
+        recentActivity.app = null;
+
+        // Start an activity on top.
+        new ActivityBuilder(mService).setCreateTask(true).build().getActivityStack().moveToFront(
+                "testRestartRecentsActivity");
+
+        doCallRealMethod().when(mRootActivityContainer).ensureActivitiesVisible(
+                any() /* starting */, anyInt() /* configChanges */,
+                anyBoolean() /* preserveWindows */);
+        doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt());
+        ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+        doNothing().when(lifecycleManager).scheduleTransaction(any());
+        AppWarnings appWarnings = mService.getAppWarningsLocked();
+        spyOn(appWarnings);
+        doNothing().when(appWarnings).onStartActivity(any());
+
+        startRecentsActivity();
+
+        // Recents activity must be restarted, but not be resumed while running recents animation.
+        verify(mRootActivityContainer.mStackSupervisor).startSpecificActivityLocked(
+                eq(recentActivity), eq(false), anyBoolean());
+        assertThat(recentActivity.getState()).isEqualTo(PAUSED);
+    }
+
+    @Test
     public void testSetLaunchTaskBehindOfTargetActivity() {
         ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);