Merge "Transfer starting windows more aggressively" into pi-dev
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 40f772a..1170148 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -379,6 +379,8 @@
 
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
                 wtoken.mAppStopped = false;
+
+                mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
             }
 
             // If we are preparing an app transition, then delay changing
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2672337..b2f153a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -187,6 +187,7 @@
     StartingSurface startingSurface;
     boolean startingDisplayed;
     boolean startingMoved;
+
     // True if the hidden state of this token was forced to false due to a transferred starting
     // window.
     private boolean mHiddenSetFromTransferredStartingWindow;
@@ -1136,6 +1137,25 @@
         stopFreezingScreen(true, true);
     }
 
+    /**
+     * Tries to transfer the starting window from a token that's above ourselves in the task but
+     * not visible anymore. This is a common scenario apps use: Trampoline activity T start main
+     * activity M in the same task. Now, when reopening the task, T starts on top of M but then
+     * immediately finishes after, so we have to transfer T to M.
+     */
+    void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
+        final Task task = getTask();
+        for (int i = task.mChildren.size() - 1; i >= 0; i--) {
+            final AppWindowToken fromToken = task.mChildren.get(i);
+            if (fromToken == this) {
+                return;
+            }
+            if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) {
+                return;
+            }
+        }
+    }
+
     boolean transferStartingWindow(IBinder transferFrom) {
         final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
         if (fromToken == null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4179590..40ee552 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -559,7 +559,8 @@
                         + wtoken.allDrawn + " startingDisplayed="
                         + wtoken.startingDisplayed + " startingMoved="
                         + wtoken.startingMoved + " isRelaunching()="
-                        + wtoken.isRelaunching());
+                        + wtoken.isRelaunching() + " startingWindow="
+                        + wtoken.startingWindow);
 
 
                 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 76e4e89..e0645b1 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -20,11 +20,9 @@
 import org.junit.Test;
 
 import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.SecurityTest;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.WindowManager;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -36,13 +34,12 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
-import java.util.function.Consumer;
+import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController;
 
 /**
  * Test class for {@link AppWindowContainerController}.
  *
- * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ * atest FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
  */
 @SmallTest
 @Presubmit
@@ -176,6 +173,33 @@
     }
 
     @Test
+    public void testTryTransferStartingWindowFromHiddenAboveToken() throws Exception {
+
+        // Add two tasks on top of each other.
+        TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(this);
+        final WindowTestUtils.TestAppWindowContainerController controllerTop =
+                createAppWindowController(taskController);
+        final WindowTestUtils.TestAppWindowContainerController controllerBottom =
+                createAppWindowController(taskController);
+
+        // Add a starting window.
+        controllerTop.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false, false);
+        waitUntilHandlersIdle();
+
+        // Make the top one invisible, and try transfering the starting window from the top to the
+        // bottom one.
+        controllerTop.setVisibility(false, false);
+        controllerBottom.mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
+
+        // Assert that the bottom window now has the starting window.
+        assertNoStartingWindow(controllerTop.getAppWindowToken(mDisplayContent));
+        assertHasStartingWindow(controllerBottom.getAppWindowToken(mDisplayContent));
+    }
+
+    @Test
     public void testReparent() throws Exception {
         final StackWindowController stackController =
             createStackControllerOnDisplay(mDisplayContent);