OSDN Git Service

Transfer starting windows more aggressively
authorJorim Jaggi <jjaggi@google.com>
Thu, 1 Feb 2018 18:21:07 +0000 (19:21 +0100)
committerJorim Jaggi <jjaggi@google.com>
Tue, 13 Mar 2018 13:03:34 +0000 (13:03 +0000)
We currently transfer starting windows when starting another
activity on top of the previous one. However, that's not enough:

Sometimes we also need to transfer back in case the one on top
finishes itself/gets hidden for other reasons.

This fixes an issue where some animations are aborted in the
middle of the animation because the trampoline activity contained
the starting window but then the trampoline activity was finished.

Test: go/wm-smoke
Test: Open Drive, Reopen Drive 100x
Test: Open Hangouts, Receive notification, open it, reopen
hangouts from launcher 100x
Test: AppWindowContainerControllerTests
Bug: 72301120

Change-Id: I6711ce0bc35de430aac03f7b8b39ceac26e595e7

services/core/java/com/android/server/wm/AppWindowContainerController.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/WindowSurfacePlacer.java
services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java

index 40f772a..1170148 100644 (file)
@@ -379,6 +379,8 @@ public class AppWindowContainerController
 
                 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
index 2672337..b2f153a 100644 (file)
@@ -187,6 +187,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
     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 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
         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) {
index 4179590..40ee552 100644 (file)
@@ -559,7 +559,8 @@ class WindowSurfacePlacer {
                         + wtoken.allDrawn + " startingDisplayed="
                         + wtoken.startingDisplayed + " startingMoved="
                         + wtoken.startingMoved + " isRelaunching()="
-                        + wtoken.isRelaunching());
+                        + wtoken.isRelaunching() + " startingWindow="
+                        + wtoken.startingWindow);
 
 
                 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
index 76e4e89..e0645b1 100644 (file)
@@ -20,11 +20,9 @@ import android.support.test.filters.FlakyTest;
 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.assertNotNull;
 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 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
     }
 
     @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);