Re-implement Z-ordering based off SurfaceControl hierarchy.

First steps in using the SurfaceControl hierarchy pervasively through
the WindowManager. For each level of the WindowContainer hierarchy
we instantiate a buffer-less SurfaceControl which is used to apply
constraints to all of it's children. For now we use full-screen surfaces
at every non-leaf level and so the only constraint we apply is Z-ordering.

Calculation of Z-ordering is done through the WindowContainer#assignLayers
pass and begins with DisplayContent. Changes are accumulated in-to a pending
transaction which is applied as part of prepareSurfaces (which now applies
to each level of the WindowContainer hierarchy rather than just windows).

Bug: 64815723
Test: Existing tests pass. go/wm-smoke. ZOrderTests.
Change-Id: Ib31bc3107c7fa398cf2ed72430fcb7596fad6fd5
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 6060881..b55c79b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -129,6 +129,9 @@
             controller.removeStartingWindow();
             waitUntilHandlersIdle();
             assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
+
+            controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
+            mDisplayContent.onPendingTransactionApplied();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index bb88264..d9ab5c8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -51,71 +51,77 @@
 @RunWith(AndroidJUnit4.class)
 public class AppWindowTokenTests extends WindowTestsBase {
 
+    TaskStack mStack;
+    Task mTask;
+    WindowTestUtils.TestAppWindowToken mToken;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mStack = createTaskStackOnDisplay(mDisplayContent);
+        mTask = createTaskInStack(mStack, 0 /* userId */);
+        mToken = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+
+        mTask.addChild(mToken, 0);
+    }
+
     @Test
     @Presubmit
     public void testAddWindow_Order() throws Exception {
-        final WindowTestUtils.TestAppWindowToken token =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+        assertEquals(0, mToken.getWindowsCount());
 
-        assertEquals(0, token.getWindowsCount());
-
-        final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1");
-        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token,
+        final WindowState win1 = createWindow(null, TYPE_APPLICATION, mToken, "win1");
+        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, mToken,
                 "startingWin");
-        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
-        final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
+        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, mToken, "baseWin");
+        final WindowState win4 = createWindow(null, TYPE_APPLICATION, mToken, "win4");
 
         // Should not contain the windows that were added above.
-        assertEquals(4, token.getWindowsCount());
-        assertTrue(token.hasWindow(win1));
-        assertTrue(token.hasWindow(startingWin));
-        assertTrue(token.hasWindow(baseWin));
-        assertTrue(token.hasWindow(win4));
+        assertEquals(4, mToken.getWindowsCount());
+        assertTrue(mToken.hasWindow(win1));
+        assertTrue(mToken.hasWindow(startingWin));
+        assertTrue(mToken.hasWindow(baseWin));
+        assertTrue(mToken.hasWindow(win4));
 
         // The starting window should be on-top of all other windows.
-        assertEquals(startingWin, token.getLastChild());
+        assertEquals(startingWin, mToken.getLastChild());
 
         // The base application window should be below all other windows.
-        assertEquals(baseWin, token.getFirstChild());
-        token.removeImmediately();
+        assertEquals(baseWin, mToken.getFirstChild());
+        mToken.removeImmediately();
     }
 
     @Test
     @Presubmit
     public void testFindMainWindow() throws Exception {
-        final WindowTestUtils.TestAppWindowToken token =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+        assertNull(mToken.findMainWindow());
 
-        assertNull(token.findMainWindow());
-
-        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
-        assertEquals(window1, token.findMainWindow());
+        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, mToken, "window11");
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, mToken, "window12");
+        assertEquals(window1, mToken.findMainWindow());
         window1.mAnimatingExit = true;
-        assertEquals(window1, token.findMainWindow());
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
-        assertEquals(window2, token.findMainWindow());
-        token.removeImmediately();
+        assertEquals(window1, mToken.findMainWindow());
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, mToken, "window2");
+        assertEquals(window2, mToken.findMainWindow());
+        mToken.removeImmediately();
     }
 
     @Test
     @Presubmit
     public void testGetTopFullscreenWindow() throws Exception {
-        final WindowTestUtils.TestAppWindowToken token =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+        assertNull(mToken.getTopFullscreenWindow());
 
-        assertNull(token.getTopFullscreenWindow());
-
-        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
-        final WindowState window11 = createWindow(null, TYPE_APPLICATION, token, "window11");
-        final WindowState window12 = createWindow(null, TYPE_APPLICATION, token, "window12");
-        assertEquals(window12, token.getTopFullscreenWindow());
+        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
+        final WindowState window11 = createWindow(null, TYPE_APPLICATION, mToken, "window11");
+        final WindowState window12 = createWindow(null, TYPE_APPLICATION, mToken, "window12");
+        assertEquals(window12, mToken.getTopFullscreenWindow());
         window12.mAttrs.width = 500;
-        assertEquals(window11, token.getTopFullscreenWindow());
+        assertEquals(window11, mToken.getTopFullscreenWindow());
         window11.mAttrs.width = 500;
-        assertEquals(window1, token.getTopFullscreenWindow());
-        token.removeImmediately();
+        assertEquals(window1, mToken.getTopFullscreenWindow());
+        mToken.removeImmediately();
     }
 
     @Test
@@ -124,27 +130,21 @@
         sWm.mDisplayReady = true;
         sWm.mDisplayEnabled = true;
 
-        // Create an app window with token on a display.
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
-        final Task task = createTaskInStack(stack, 0 /* userId */);
-        final WindowTestUtils.TestAppWindowToken appWindowToken =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
-        task.addChild(appWindowToken, 0);
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.setTitle("AppWindow");
-        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
-        appWindowToken.addWindow(appWindow);
+        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken);
+        mToken.addWindow(appWindow);
 
         // Set initial orientation and update.
-        appWindowToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
                 mDisplayContent.getDisplayId());
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
         appWindow.resizeReported = false;
 
         // Update the orientation to perform 180 degree rotation and check that resize was reported.
-        appWindowToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+        mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
         sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
                 mDisplayContent.getDisplayId());
         sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
@@ -159,18 +159,11 @@
         sWm.mDisplayReady = true;
         sWm.mDisplayEnabled = true;
 
-        // Create an app window with token on a display.
-        final DisplayContent defaultDisplayContent = sWm.getDefaultDisplayContentLocked();
-        final TaskStack stack = createTaskStackOnDisplay(defaultDisplayContent);
-        final Task task = createTaskInStack(stack, 0 /* userId */);
-        final WindowTestUtils.TestAppWindowToken appWindowToken =
-                new WindowTestUtils.TestAppWindowToken(defaultDisplayContent);
-        task.addChild(appWindowToken, 0);
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.setTitle("AppWindow");
-        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
-        appWindowToken.addWindow(appWindow);
+        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken);
+        mToken.addWindow(appWindow);
 
         // Set initial orientation and update.
         performRotation(Surface.ROTATION_90);
@@ -193,53 +186,49 @@
     @Test
     @Presubmit
     public void testGetOrientation() throws Exception {
-        final WindowTestUtils.TestAppWindowToken token =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
-        token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
-        token.setFillsParent(false);
+        mToken.setFillsParent(false);
         // Can specify orientation if app doesn't fill parent.
-        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
 
-        token.setFillsParent(true);
-        token.hidden = true;
-        token.sendingToBottom = true;
+        mToken.setFillsParent(true);
+        mToken.hidden = true;
+        mToken.sendingToBottom = true;
         // Can not specify orientation if app isn't visible even though it fills parent.
-        assertEquals(SCREEN_ORIENTATION_UNSET, token.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
         // Can specify orientation if the current orientation candidate is orientation behind.
-        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation(SCREEN_ORIENTATION_BEHIND));
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation(SCREEN_ORIENTATION_BEHIND));
 
-        token.sendingToBottom = false;
-        token.setIsOnTop(true);
-        // Allow for token to provide orientation hidden if on top and not being sent to bottom.
-        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
+        mToken.sendingToBottom = false;
+        mToken.setIsOnTop(true);
+        // Allow for mToken to provide orientation hidden if on top and not being sent to bottom.
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
     }
 
     @Test
     @Presubmit
     public void testKeyguardFlagsDuringRelaunch() throws Exception {
-        final WindowTestUtils.TestAppWindowToken token =
-                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
         attrs.setTitle("AppWindow");
-        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, token);
+        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken);
 
         // Add window with show when locked flag
-        token.addWindow(appWindow);
-        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
+        mToken.addWindow(appWindow);
+        assertTrue(mToken.containsShowWhenLockedWindow() && mToken.containsDismissKeyguardWindow());
 
         // Start relaunching
-        token.startRelaunching();
-        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
+        mToken.startRelaunching();
+        assertTrue(mToken.containsShowWhenLockedWindow() && mToken.containsDismissKeyguardWindow());
 
         // Remove window and make sure that we still report back flag
-        token.removeChild(appWindow);
-        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
+        mToken.removeChild(appWindow);
+        assertTrue(mToken.containsShowWhenLockedWindow() && mToken.containsDismissKeyguardWindow());
 
         // Finish relaunching and ensure flag is now not reported
-        token.finishRelaunching();
-        assertFalse(token.containsShowWhenLockedWindow() || token.containsDismissKeyguardWindow());
+        mToken.finishRelaunching();
+        assertFalse(mToken.containsShowWhenLockedWindow() || mToken.containsDismissKeyguardWindow());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 887def7..873a01b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -66,7 +66,7 @@
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
 
         mPositioner = new TaskPositioner(sWm);
-        mPositioner.register(display);
+        mPositioner.register(mDisplayContent);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 53d0bfb..a45695f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -568,11 +568,6 @@
     }
 
     @Override
-    public boolean canMagnifyWindow(int windowType) {
-        return false;
-    }
-
-    @Override
     public boolean isTopLevelWindow(int windowType) {
         return false;
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
deleted file mode 100644
index 3c3514f..0000000
--- a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-
-/**
- * Tests for the {@link WindowLayersController} class.
- *
- * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests
- */
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class WindowLayersControllerTests extends WindowTestsBase {
-
-    @Test
-    public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
-        sWm.mInputMethodTarget = null;
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        // The Ime has an higher base layer than app windows and lower base layer than system
-        // windows, so it should be above app windows and below system windows if there isn't an IME
-        // target.
-        assertWindowLayerGreaterThan(mImeWindow, mChildAppWindowAbove);
-        assertWindowLayerGreaterThan(mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mDockedDividerWindow);
-        assertWindowLayerGreaterThan(mNavBarWindow, mImeWindow);
-        assertWindowLayerGreaterThan(mStatusBarWindow, mImeWindow);
-
-        // And, IME dialogs should always have an higher layer than the IME.
-        assertWindowLayerGreaterThan(mImeDialogWindow, mImeWindow);
-    }
-
-    @Test
-    public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
-        final WindowState imeAppTarget =
-                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
-        sWm.mInputMethodTarget = imeAppTarget;
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        // Ime should be above all app windows and below system windows if it is targeting an app
-        // window.
-        assertWindowLayerGreaterThan(mImeWindow, imeAppTarget);
-        assertWindowLayerGreaterThan(mImeWindow, mChildAppWindowAbove);
-        assertWindowLayerGreaterThan(mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mDockedDividerWindow);
-        assertWindowLayerGreaterThan(mNavBarWindow, mImeWindow);
-        assertWindowLayerGreaterThan(mStatusBarWindow, mImeWindow);
-
-        // And, IME dialogs should always have an higher layer than the IME.
-        assertWindowLayerGreaterThan(mImeDialogWindow, mImeWindow);
-    }
-
-    @Test
-    public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
-        final WindowState imeAppTarget =
-                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
-        final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
-                TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
-                "imeAppTargetChildAboveWindow");
-        final WindowState imeAppTargetChildBelowWindow = createWindow(imeAppTarget,
-                TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
-                "imeAppTargetChildBelowWindow");
-
-        sWm.mInputMethodTarget = imeAppTarget;
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        // Ime should be above all app windows except for child windows that are z-ordered above it
-        // and below system windows if it is targeting an app window.
-        assertWindowLayerGreaterThan(mImeWindow, imeAppTarget);
-        assertWindowLayerGreaterThan(imeAppTargetChildAboveWindow, mImeWindow);
-        assertWindowLayerGreaterThan(mImeWindow, imeAppTargetChildBelowWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mChildAppWindowAbove);
-        assertWindowLayerGreaterThan(mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mDockedDividerWindow);
-        assertWindowLayerGreaterThan(mNavBarWindow, mImeWindow);
-        assertWindowLayerGreaterThan(mStatusBarWindow, mImeWindow);
-
-        // And, IME dialogs should always have an higher layer than the IME.
-        assertWindowLayerGreaterThan(mImeDialogWindow, mImeWindow);
-    }
-
-    @Test
-    public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
-        final WindowState appBelowImeTarget =
-                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appBelowImeTarget");
-        final WindowState imeAppTarget =
-                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
-        final WindowState appAboveImeTarget =
-                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appAboveImeTarget");
-
-        sWm.mInputMethodTarget = imeAppTarget;
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        // Ime should be above all app windows except for non-fullscreen app window above it and
-        // below system windows if it is targeting an app window.
-        assertWindowLayerGreaterThan(mImeWindow, imeAppTarget);
-        assertWindowLayerGreaterThan(mImeWindow, appBelowImeTarget);
-        assertWindowLayerGreaterThan(appAboveImeTarget, mImeWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mChildAppWindowAbove);
-        assertWindowLayerGreaterThan(mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mDockedDividerWindow);
-        assertWindowLayerGreaterThan(mNavBarWindow, mImeWindow);
-        assertWindowLayerGreaterThan(mStatusBarWindow, mImeWindow);
-
-        // And, IME dialogs should always have an higher layer than the IME.
-        assertWindowLayerGreaterThan(mImeDialogWindow, mImeWindow);
-    }
-
-    @Test
-    public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
-        final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
-                mDisplayContent, "imeSystemOverlayTarget",
-                true /* ownerCanAddInternalSystemWindow */);
-
-        sWm.mInputMethodTarget = imeSystemOverlayTarget;
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        // The IME target base layer is higher than all window except for the nav bar window, so the
-        // IME should be above all windows except for the nav bar.
-        assertWindowLayerGreaterThan(mImeWindow, imeSystemOverlayTarget);
-        assertWindowLayerGreaterThan(mImeWindow, mChildAppWindowAbove);
-        assertWindowLayerGreaterThan(mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mDockedDividerWindow);
-        assertWindowLayerGreaterThan(mImeWindow, mStatusBarWindow);
-        assertWindowLayerGreaterThan(mNavBarWindow, mImeWindow);
-
-        // And, IME dialogs should always have an higher layer than the IME.
-        assertWindowLayerGreaterThan(mImeDialogWindow, mImeWindow);
-    }
-
-    @Test
-    public void testStackLayers() throws Exception {
-        WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
-                ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "pinnedStackWindow");
-        WindowState dockedStackWindow = createWindowOnStack(null,
-                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
-                mDisplayContent, "dockedStackWindow");
-        WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
-                mDisplayContent, "assistantStackWindow");
-
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        assertWindowLayerGreaterThan(dockedStackWindow, mAppWindow);
-        assertWindowLayerGreaterThan(assistantStackWindow, dockedStackWindow);
-        assertWindowLayerGreaterThan(pinnedStackWindow, assistantStackWindow);
-    }
-
-    private void assertWindowLayerGreaterThan(WindowState first, WindowState second)
-            throws Exception {
-        assertGreaterThan(first.mWinAnimator.mAnimLayer, second.mWinAnimator.mAnimLayer);
-    }
-
-}
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 0980f7e..4c5e291 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -73,7 +73,6 @@
     private static boolean sOneTimeSetupDone = false;
     DisplayContent mDisplayContent;
     DisplayInfo mDisplayInfo = new DisplayInfo();
-    WindowLayersController mLayersController;
     WindowState mWallpaperWindow;
     WindowState mImeWindow;
     WindowState mImeDialogWindow;
@@ -98,8 +97,9 @@
 
         final Context context = InstrumentationRegistry.getTargetContext();
         AttributeCache.init(context);
+
         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
-        mLayersController = new WindowLayersController(sWm);
+        beforeCreateDisplay();
 
         context.getDisplay().getDisplayInfo(mDisplayInfo);
         mDisplayContent = createNewDisplay();
@@ -126,6 +126,10 @@
         waitUntilHandlersIdle();
     }
 
+    void beforeCreateDisplay() {
+        // Called before display is created.
+    }
+
     @After
     public void tearDown() throws Exception {
         final LinkedList<WindowState> nonCommonWindows = new LinkedList();
@@ -149,6 +153,14 @@
         waitUntilHandlersIdle();
     }
 
+    /**
+     * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
+     *         set-up (or null).
+     */
+    SurfaceBuilderFactory getSurfaceBuilderFactory() {
+        return null;
+    }
+
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
         final WindowState win = createWindow(parent, type, name);
         mCommonWindows.add(win);
@@ -162,6 +174,11 @@
         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
     }
 
+    /** Asserts that the first entry is greater than the second entry. */
+    void assertLessThan(int first, int second) throws Exception {
+        Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
+    }
+
     /**
      * Waits until the main handler for WM has processed all messages.
      */
@@ -264,7 +281,7 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        return new DisplayContent(display, sWm, mLayersController, new WallpaperController(sWm));
+        return new DisplayContent(display, sWm, new WallpaperController(sWm));
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 692e08b..7219104 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -94,43 +94,6 @@
         assertEquals(null, dc.getWindowToken(token.token));
     }
 
-    @Test
-    public void testAdjustAnimLayer() throws Exception {
-        final WindowTestUtils.TestWindowToken token =
-                new WindowTestUtils.TestWindowToken(0, mDisplayContent);
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
-        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
-
-        window2.mLayer = 100;
-        window3.mLayer = 200;
-
-        // We assign layers once, to get the base values computed by
-        // the controller.
-        mLayersController.assignWindowLayers(mDisplayContent);
-
-        final int window1StartLayer = window1.mWinAnimator.mAnimLayer;
-        final int window11StartLayer = window11.mWinAnimator.mAnimLayer;
-        final int window12StartLayer = window12.mWinAnimator.mAnimLayer;
-        final int window2StartLayer = window2.mWinAnimator.mAnimLayer;
-        final int window3StartLayer = window3.mWinAnimator.mAnimLayer;
-
-        // Then we set an adjustment, and assign them again, they should
-        // be offset.
-        int adj = token.adj = 50;
-        mLayersController.assignWindowLayers(mDisplayContent);
-        final int highestLayer = token.getHighestAnimLayer();
-
-        assertEquals(window1StartLayer + adj, window1.mWinAnimator.mAnimLayer);
-        assertEquals(window11StartLayer + adj, window11.mWinAnimator.mAnimLayer);
-        assertEquals(window12StartLayer + adj, window12.mWinAnimator.mAnimLayer);
-        assertEquals(window2StartLayer + adj, window2.mWinAnimator.mAnimLayer);
-        assertEquals(window3StartLayer + adj, window3.mWinAnimator.mAnimLayer);
-        assertEquals(window3StartLayer + adj, highestLayer);
-    }
-
     /**
      * Test that a window token isn't orphaned by the system when it is requested to be removed.
      * Tokens should only be removed from the system when all their windows are gone.
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
new file mode 100644
index 0000000..f7c4b1f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.util.Log;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+
+/**
+ * Tests for the {@link WindowLayersController} class.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ZOrderingTests extends WindowTestsBase {
+
+    private class LayerRecordingTransaction extends SurfaceControl.Transaction {
+        HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap();
+        HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap();
+
+        @Override
+        public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
+            mRelativeLayersForControl.remove(sc);
+            mLayersForControl.put(sc, layer);
+            return super.setLayer(sc, layer);
+        }
+
+        @Override
+        public SurfaceControl.Transaction setRelativeLayer(SurfaceControl sc,
+                SurfaceControl relativeTo,
+                int layer) {
+            mRelativeLayersForControl.put(sc, relativeTo);
+            mLayersForControl.put(sc, layer);
+            return super.setRelativeLayer(sc, relativeTo, layer);
+        }
+
+        int getLayer(SurfaceControl sc) {
+            return mLayersForControl.get(sc);
+        }
+
+        SurfaceControl getRelativeLayer(SurfaceControl sc) {
+            return mRelativeLayersForControl.get(sc);
+        }
+    };
+
+    // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
+    // such that we can keep track of the parents of Surfaces as they are constructed.
+    private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap();
+
+    private class HierarchyRecorder extends SurfaceControl.Builder {
+        SurfaceControl mPendingParent;
+
+        HierarchyRecorder(SurfaceSession s) {
+            super(s);
+        }
+
+        public SurfaceControl.Builder setParent(SurfaceControl sc) {
+            mPendingParent = sc;
+            return super.setParent(sc);
+        }
+        public SurfaceControl build() {
+            SurfaceControl sc = super.build();
+            mParentFor.put(sc, mPendingParent);
+            mPendingParent = null;
+            return sc;
+        }
+    };
+
+    class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+        public SurfaceControl.Builder make(SurfaceSession s) {
+            return new HierarchyRecorder(s);
+        }
+    };
+
+    private LayerRecordingTransaction mTransaction;
+
+    @Override
+    void beforeCreateDisplay() {
+        // We can't use @Before here because it may happen after WindowTestsBase @Before
+        // which is after construction of the DisplayContent, meaning the HierarchyRecorder
+        // would miss construction of the top-level layers.
+        mTransaction = new LayerRecordingTransaction();
+        sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory();
+    }
+
+    @After
+    public void after() {
+        mTransaction.close();
+        mParentFor.clear();
+    }
+
+    LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
+        LinkedList<SurfaceControl> p = new LinkedList();
+        SurfaceControl current = sc;
+        do {
+            p.addLast(current);
+
+            SurfaceControl rs = t.getRelativeLayer(current);
+            if (rs != null) {
+                current = rs;
+            } else {
+                current = mParentFor.get(current);
+            }
+        } while (current != null);
+        return p;
+    }
+
+    void assertZOrderGreaterThan(LayerRecordingTransaction t,
+            SurfaceControl left, SurfaceControl right) throws Exception {
+        final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
+        final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
+
+        SurfaceControl commonAncestor = null;
+        SurfaceControl leftTop = leftParentChain.peekLast();
+        SurfaceControl rightTop = rightParentChain.peekLast();
+        while (leftTop != null && rightTop != null && leftTop == rightTop) {
+            commonAncestor = leftParentChain.removeLast();
+            rightParentChain.removeLast();
+            leftTop = leftParentChain.peekLast();
+            rightTop = rightParentChain.peekLast();
+        }
+
+        if (rightTop == null) { // right is the parent of left.
+            assertGreaterThan(t.getLayer(leftTop), 0);
+        } else if (leftTop == null) { // left is the parent of right.
+            assertGreaterThan(0, t.getLayer(rightTop));
+        } else {
+            assertGreaterThan(t.getLayer(leftTop),
+                    t.getLayer(rightTop));
+        }
+    }
+
+    void assertWindowLayerGreaterThan(LayerRecordingTransaction t,
+            WindowState left, WindowState right) throws Exception {
+        assertZOrderGreaterThan(t, left.getSurfaceControl(), right.getSurfaceControl());
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+        sWm.mInputMethodTarget = null;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        // The Ime has an higher base layer than app windows and lower base layer than system
+        // windows, so it should be above app windows and below system windows if there isn't an IME
+        // target.
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
+        assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+        sWm.mInputMethodTarget = imeAppTarget;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        // Ime should be above all app windows and below system windows if it is targeting an app
+        // window.
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+        final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
+                TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
+                "imeAppTargetChildAboveWindow");
+        final WindowState imeAppTargetChildBelowWindow = createWindow(imeAppTarget,
+                TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
+                "imeAppTargetChildBelowWindow");
+
+        sWm.mInputMethodTarget = imeAppTarget;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        // Ime should be above all app windows except for child windows that are z-ordered above it
+        // and below system windows if it is targeting an app window.
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(mTransaction, imeAppTargetChildAboveWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+        final WindowState appBelowImeTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appBelowImeTarget");
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+        final WindowState appAboveImeTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appAboveImeTarget");
+
+        sWm.mInputMethodTarget = imeAppTarget;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        // Ime should be above all app windows except for non-fullscreen app window above it and
+        // below system windows if it is targeting an app window.
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, appBelowImeTarget);
+        assertWindowLayerGreaterThan(mTransaction, appAboveImeTarget, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+        final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
+                mDisplayContent, "imeSystemOverlayTarget",
+                true /* ownerCanAddInternalSystemWindow */);
+
+        sWm.mInputMethodTarget = imeSystemOverlayTarget;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        // The IME target base layer is higher than all window except for the nav bar window, so the
+        // IME should be above all windows except for the nav bar.
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeSystemOverlayTarget);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
+
+        // The IME has a higher base layer than the status bar so we may expect it to go
+        // above the status bar once they are both in the Non-App layer, as past versions of this
+        // test enforced. However this seems like the wrong behavior unless the status bar is the
+        // IME target.
+        assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
+        assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForStatusBarImeTarget() throws Exception {
+        sWm.mInputMethodTarget = mStatusBarWindow;
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
+        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mStatusBarWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+    }
+
+    @Test
+    public void testStackLayers() throws Exception {
+        final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
+                ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
+                "pinnedStackWindow");
+        final WindowState dockedStackWindow = createWindowOnStack(null,
+                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
+                mDisplayContent, "dockedStackWindow");
+        final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+                mDisplayContent, "assistantStackWindow");
+
+        mDisplayContent.assignChildLayers(mTransaction);
+
+        assertWindowLayerGreaterThan(mTransaction, dockedStackWindow, mAppWindow);
+        assertWindowLayerGreaterThan(mTransaction, assistantStackWindow, dockedStackWindow);
+        assertWindowLayerGreaterThan(mTransaction, pinnedStackWindow, assistantStackWindow);
+    }
+}