Each displays can have individual app transition.

Include below refectoring items to support per display AppTransition:

WMS / AM refectoring parts:
- Move AppTransition related stuff from WMS into DisplayContent.
- Move WMS.prepareAppTransition into DisplayWindowController.
- Move WMS.executeAppTransition to DisplayWindowController.
- Move ATM.isNextTransitionForward to DisplayWindowController.
- Move WMS.getPendingAppTransition to DisplayWindowController.
- Move WMS.overrideAppTransition like APIs to DisplayWindowController.
- Move ActivityRecord.applyOptionsLocked to AppContainerController.
- Support tracing all display's AppTransition status for
  DisplayContent.pendingLayoutChanges & window hierachy update.
- Modify logics for AppTransition related caller parts.
- Move WindowSurfacePlacer.handleAppTransitionReadyLocked related
  stuffs into added class AppTransitionController.

WM unit test parts:
- Add test case for verifying app transition state per display:
  - AppTransitionTests.testAppTransitionStateForMultiDisplay
  - AppTransitionTests.testCleanAppTransitionWhenTaskStackReparent
- Rename WindowSurfacePlacerTest to AppTransitionControllerTest since
  the test is related handle AppTransition flow.

Bug: 111362605
Test: go/wm-smoke
Test: atest ActivityManagerTransitionSelectionTests
Test: atest ActivityManagerMultiDisplayTests
Test: atest FrameworksServicesTests for DisplayContent / AppTransition
      related tests.
Change-Id: Ic1793aa794eb161bec31fda57847a6ba2ff4f84f
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
similarity index 79%
rename from services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
rename to services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
index 057f047..aa495f7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -36,14 +36,14 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class WindowSurfacePlacerTest extends WindowTestsBase {
+public class AppTransitionControllerTest extends WindowTestsBase {
 
-    private WindowSurfacePlacer mWindowSurfacePlacer;
+    private AppTransitionController mAppTransitionController;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        mWindowSurfacePlacer = new WindowSurfacePlacer(sWm);
+        mAppTransitionController = new AppTransitionController(sWm, mDisplayContent);
     }
 
     @Test
@@ -55,10 +55,11 @@
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             translucentOpening.setFillsParent(false);
             translucentOpening.setHidden(true);
-            sWm.mOpeningApps.add(behind);
-            sWm.mOpeningApps.add(translucentOpening);
+            mDisplayContent.mOpeningApps.add(behind);
+            mDisplayContent.mOpeningApps.add(translucentOpening);
             assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
-                    mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_OPEN));
+                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+                            TRANSIT_TASK_OPEN));
         }
     }
 
@@ -70,9 +71,10 @@
             final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             translucentClosing.setFillsParent(false);
-            sWm.mClosingApps.add(translucentClosing);
+            mDisplayContent.mClosingApps.add(translucentClosing);
             assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
-                    mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_CLOSE));
+                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+                            TRANSIT_TASK_CLOSE));
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index 3053c41..ee6fbac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -16,22 +16,33 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.IApplicationToken;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -43,51 +54,142 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class AppTransitionTests {
+public class AppTransitionTests extends WindowTestsBase {
 
-    @Rule
-    public final WindowManagerServiceRule mRule = new WindowManagerServiceRule();
-    private WindowManagerService mWm;
+    private DisplayContent mDc;
 
     @Before
     public void setUp() throws Exception {
+        super.setUp();
         final Context context = InstrumentationRegistry.getTargetContext();
-        mWm = mRule.getWindowManagerService();
+        mDc = sWm.getDefaultDisplayContentLocked();
+        // For unit test,  we don't need to test performSurfacePlacement to prevent some
+        // abnormal interaction with surfaceflinger native side.
+        sWm.mRoot = spy(sWm.mRoot);
+        doNothing().when(sWm.mRoot).performSurfacePlacement(anyBoolean());
     }
 
     @Test
     public void testKeyguardOverride() throws Exception {
-        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
-        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
-        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
     public void testKeyguardKeep() throws Exception {
-        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
-        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
-        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
     public void testForceOverride() throws Exception {
-        mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
-        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */,
-                0 /* flags */, true /* forceOverride */);
-        assertEquals(TRANSIT_ACTIVITY_OPEN, mWm.mAppTransition.getAppTransition());
+        sWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
+        mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+                false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+        assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
     public void testCrashing() throws Exception {
-        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
-        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
-        assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mWm.mAppTransition.getAppTransition());
+        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
     public void testKeepKeyguard_withCrashing() throws Exception {
-        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
-        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
-        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
+    }
+
+    @Test
+    public void testAppTransitionStateForMultiDisplay() throws Exception {
+        // Create 2 displays & presume both display the state is ON for ready to display & animate.
+        final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
+        final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+
+        // Create 2 app window tokens to represent 2 activity window.
+        final WindowTestUtils.TestAppWindowToken token1 = createTestAppWindowToken(dc1,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+
+        // Set TestAppWindowContainerController & assign first app token state to be good to go.
+        final WindowTestUtils.TestAppWindowContainerController controller1 =
+                createAppWindowController(dc1, token1.appToken);
+        final WindowTestUtils.TestAppWindowContainerController controller2 =
+                createAppWindowController(dc1, token2.appToken);
+        controller1.setContainer(token1);
+        token1.allDrawn = true;
+        token1.startingDisplayed = true;
+        token1.startingMoved = true;
+        controller2.setContainer(token2);
+
+        // Simulate activity resume / finish flows to prepare app transition & set visibility,
+        // make sure transition is set as expected for each display.
+        dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+                false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+        assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
+        dc2.getController().prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
+                false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+        assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
+        // One activity window is visible for resuming & the other activity window is invisible
+        // for finishing in different display.
+        controller1.setVisibility(true, false);
+        controller2.setVisibility(false, false);
+
+        // Make sure each display is in animating stage.
+        assertTrue(dc1.mOpeningApps.size() > 0);
+        assertTrue(dc2.mClosingApps.size() > 0);
+        assertTrue(dc1.isAppAnimating());
+        assertTrue(dc2.isAppAnimating());
+    }
+
+    @Test
+    public void testCleanAppTransitionWhenTaskStackReparent() throws Exception {
+        // Create 2 displays & presume both display the state is ON for ready to display & animate.
+        final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
+        final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+
+        final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+        final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+        final WindowTestUtils.TestAppWindowToken token1 =
+                WindowTestUtils.createTestAppWindowToken(dc1);
+        task1.addChild(token1, 0);
+
+        // Simulate same app is during opening / closing transition set stage.
+        dc1.mClosingApps.add(token1);
+        assertTrue(dc1.mClosingApps.size() > 0);
+
+        dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+                false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+        assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
+        assertTrue(dc1.mAppTransition.isTransitionSet());
+
+        dc1.mOpeningApps.add(token1);
+        assertTrue(dc1.mOpeningApps.size() > 0);
+
+        // Move stack to another display.
+        stack1.getController().reparent(dc2.getDisplayId(),  new Rect(), true);
+
+        // Verify if token are cleared from both pending transition list in former display.
+        assertFalse(dc1.mOpeningApps.contains(token1));
+        assertFalse(dc1.mOpeningApps.contains(token1));
+    }
+
+    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+            DisplayContent dc, IApplicationToken token) {
+        return createAppWindowController(
+                new WindowTestUtils.TestTaskWindowContainerController(
+                        createStackControllerOnDisplay(dc)), token);
+    }
+
+    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+            WindowTestUtils.TestTaskWindowContainerController taskController,
+            IApplicationToken token) {
+        return new WindowTestUtils.TestAppWindowContainerController(taskController, token);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index e6e08bb..d65055c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -90,7 +92,7 @@
         private AppTransitionListener mListener;
 
         MockAppTransition(Context context) {
-            super(context, sWm);
+            super(context, sWm, mDisplayContent);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 7d19baa..ae92984 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -85,7 +85,7 @@
     @Test
     public void testRun() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        sWm.mOpeningApps.add(win.mAppToken);
+        mDisplayContent.mOpeningApps.add(win.mAppToken);
         try {
             final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
                     new Point(50, 100), new Rect(50, 100, 150, 150));
@@ -113,7 +113,7 @@
             finishedCaptor.getValue().onAnimationFinished();
             verify(mFinishedCallback).onAnimationFinished(eq(adapter));
         } finally {
-            sWm.mOpeningApps.clear();
+            mDisplayContent.mOpeningApps.clear();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 53a1185..cb5c1cd 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -74,7 +74,7 @@
         appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
 
         assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation());
-        sWm.mClosingApps.add(appWindowToken2);
+        mDisplayContent.mClosingApps.add(appWindowToken2);
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, stack.getOrientation());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 3ac97027..54456fb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -40,50 +40,50 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        sWm.mUnknownAppVisibilityController.clear();
+        mDisplayContent.mUnknownAppVisibilityController.clear();
     }
 
     @Test
     public void testFlow() throws Exception {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
-        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
-        sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+        mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
+        mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
 
         // Make sure our handler processed the message.
         Thread.sleep(100);
-        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+        assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testMultiple() throws Exception {
         final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
-        sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
-        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
-        sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
-        sWm.mUnknownAppVisibilityController.notifyRelayouted(token1);
-        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
-        sWm.mUnknownAppVisibilityController.notifyRelayouted(token2);
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token1);
+        mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token2);
+        mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token1);
+        mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
+        mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
 
         // Make sure our handler processed the message.
         Thread.sleep(100);
-        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+        assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testClear() throws Exception {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
-        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        sWm.mUnknownAppVisibilityController.clear();;
-        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+        mDisplayContent.mUnknownAppVisibilityController.clear();;
+        assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testAppRemoved() throws Exception {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
-        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        sWm.mUnknownAppVisibilityController.appRemovedOrHidden(token);
-        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+        mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(token);
+        assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 389eba5..012c4be 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -33,6 +33,7 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
+import android.view.Display;
 import android.view.InputChannel;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
@@ -114,7 +115,7 @@
                         runnable.run();
                     }
                     return null;
-                }).when(atm).notifyKeyguardFlagsChanged(any());
+                }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt());
 
                 InputManagerService ims = mock(InputManagerService.class);
                 // InputChannel is final and can't be mocked.
@@ -142,11 +143,11 @@
 
                 mService.onInitReady();
 
+                final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+                final DisplayWindowController dcw = new DisplayWindowController(display, mService);
                 // Display creation is driven by the ActivityManagerService via ActivityStackSupervisor.
                 // We emulate those steps here.
-                mService.mRoot.createDisplayContent(
-                        mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY),
-                        mock(DisplayWindowController.class));
+                mService.mRoot.createDisplayContent(display, dcw);
             }
 
             private void removeServices() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index d0a81b2..dcfe556 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -181,9 +181,12 @@
                         displayContent.removeImmediately();
                     }
                 }
+                // Remove app transition & window freeze timeout callbacks to prevent unnecessary
+                // actions after test.
+                sWm.getDefaultDisplayContentLocked().mAppTransition
+                        .removeAppTransitionTimeoutCallbacks();
+                sWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
                 sWm.mInputMethodTarget = null;
-                sWm.mClosingApps.clear();
-                sWm.mOpeningApps.clear();
             }
 
             // Wait until everything is really cleaned up.
@@ -354,6 +357,32 @@
         }
     }
 
+    /**
+     * Creates a {@link DisplayContent} with given display state and adds it to the system.
+     *
+     * Unlike {@link #createNewDisplay()} that uses a mock {@link DisplayWindowController} to
+     * initialize {@link DisplayContent}, this method used real controller object when the test
+     * need to verify its related flows.
+     *
+     * @param displayState For initializing the state of the display. See
+     *                     {@link Display#getState()}.
+     */
+    DisplayContent createNewDisplayWithController(int displayState) {
+        // Leverage main display info & initialize it with display state for given displayId.
+        DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.copyFrom(mDisplayInfo);
+        displayInfo.state = displayState;
+        final int displayId = sNextDisplayId++;
+        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+                displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+        final DisplayWindowController dcw = new DisplayWindowController(display, sWm);
+        synchronized (sWm.mWindowMap) {
+            // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
+            // We skip those steps here.
+            return sWm.mRoot.createDisplayContent(display, dcw);
+        }
+    }
+
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
             WindowToken token) {