Fixed issue with IME displaying on-top of nav bar.

Caused by some recent refactoring. We now make sure the IME
has the higher animation layer in its base layer of the window
it is targeting.
Also, consolidated some of our test functions.

Bug: 32916670
Test: bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests
Change-Id: I0b1abd6fead981cfc810488cc785261abba5341d
(cherry picked from commit 44fbdf5b1e13398e35d4bafb7236d194a51ee7af)
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index c06e5cc..32373f9 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -23,6 +23,7 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -63,17 +64,19 @@
     private int mCurBaseLayer;
     private int mCurLayer;
     private boolean mAnyLayerChanged;
+    private int mHighestLayerInImeTargetBaseLayer;
+    private WindowState mImeTarget;
 
     final void assignWindowLayers(DisplayContent dc) {
         if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based",
                 new RuntimeException("here").fillInStackTrace());
 
-        clear();
+        reset();
         dc.forAllWindows((w) -> {
             boolean layerChanged = false;
 
             int oldLayer = w.mLayer;
-            if (w.mBaseLayer == mCurBaseLayer || w.mIsImWindow) {
+            if (w.mBaseLayer == mCurBaseLayer) {
                 mCurLayer += WINDOW_LAYER_MULTIPLIER;
             } else {
                 mCurBaseLayer = mCurLayer = w.mBaseLayer;
@@ -92,6 +95,11 @@
                 mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
                         w.mWinAnimator.mAnimLayer);
             }
+            if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) {
+                mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
+                        w.mWinAnimator.mAnimLayer);
+            }
+
             collectSpecialWindows(w);
 
             if (layerChanged) {
@@ -103,7 +111,7 @@
 
         //TODO (multidisplay): Magnification is supported only for the default display.
         if (mService.mAccessibilityController != null && mAnyLayerChanged
-                && dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
+                && dc.getDisplayId() == DEFAULT_DISPLAY) {
             mService.mAccessibilityController.onWindowLayersChangedLocked();
         }
 
@@ -120,7 +128,7 @@
         }, false /* traverseTopToBottom */);
     }
 
-    private void clear() {
+    private void reset() {
         mHighestApplicationLayer = 0;
         mPinnedWindows.clear();
         mInputMethodWindows.clear();
@@ -132,6 +140,9 @@
         mCurBaseLayer = 0;
         mCurLayer = 0;
         mAnyLayerChanged = false;
+
+        mImeTarget = mService.mInputMethodTarget;
+        mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
     }
 
     private void collectSpecialWindows(WindowState w) {
@@ -174,22 +185,10 @@
 
         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
 
-        boolean onTopLauncherVisible = !mOnTopLauncherWindows.isEmpty();
         while (!mOnTopLauncherWindows.isEmpty()) {
             layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
         }
 
-        // Make sure IME windows are showing above the dock divider and on-top launcher windows.
-        if ((mDockDivider != null && mDockDivider.isVisibleLw()) || onTopLauncherVisible) {
-            while (!mInputMethodWindows.isEmpty()) {
-                final WindowState w = mInputMethodWindows.remove();
-                // Only ever move IME windows up, else we brake IME for windows above the divider.
-                if (layer > w.mLayer) {
-                    layer = assignAndIncreaseLayerIfNeeded(w, layer);
-                }
-            }
-        }
-
         // We know that we will be animating a relaunching window in the near future, which will
         // receive a z-order increase. We want the replaced window to immediately receive the same
         // treatment, e.g. to be above the dock divider.
@@ -200,12 +199,26 @@
         while (!mPinnedWindows.isEmpty()) {
             layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
         }
+
+        // Make sure IME is the highest window in the base layer of it's target.
+        if (mImeTarget != null) {
+            if (mImeTarget.mAppToken == null) {
+                // For non-app ime targets adjust the layer we start from to match what we found
+                // when assigning layers. Otherwise, just use the highest app layer we have some far.
+                layer = mHighestLayerInImeTargetBaseLayer + WINDOW_LAYER_MULTIPLIER;
+            }
+
+            while (!mInputMethodWindows.isEmpty()) {
+                layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer);
+            }
+        }
+
     }
 
     private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
         if (win != null) {
             assignAnimLayer(win, layer);
-            // Make sure we leave space inbetween normal windows for dims and such.
+            // Make sure we leave space in-between normal windows for dims and such.
             layer += WINDOW_LAYER_MULTIPLIER;
         }
         return layer;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c11003d..661df9cd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1905,9 +1905,7 @@
     }
 
     int getAnimLayerAdjustment() {
-        final boolean isImeType =
-                mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
-        if (isImeType && mService.mInputMethodTarget != null) {
+        if (mIsImWindow && mService.mInputMethodTarget != null) {
             final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
             if (appToken != null) {
                 return appToken.mAppAnimator.animLayerAdjustment;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 402bcfb..a2eebc3 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -176,21 +176,6 @@
     }
 
     /**
-     * Recursive search through a WindowList and all of its windows' children.
-     * @param target The window to search for.
-     * @return The index of win in windows or of the window that is an ancestor of win.
-     */
-    int getWindowIndex(WindowState target) {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState w = mChildren.get(i);
-            if (w == target || w.hasChild(target)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
      * Returns true if the new window is considered greater than the existing window in terms of
      * z-order.
      */
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 772b2a2..207939f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -45,16 +45,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class AppWindowTokenTests {
-
-    private static WindowManagerService sWm = null;
-    private final IWindow mIWindow = new TestIWindow();
-
-    @Before
-    public void setUp() throws Exception {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
-    }
+public class AppWindowTokenTests extends WindowTestsBase {
 
     @Test
     public void testAddWindow_Order() throws Exception {
@@ -62,10 +53,11 @@
 
         assertEquals(0, token.getWindowsCount());
 
-        final WindowState win1 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token);
-        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token);
-        final WindowState win4 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1");
+        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token,
+                "startingWin");
+        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
+        final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
 
         token.addWindow(win1);
         token.addWindow(startingWin);
@@ -92,24 +84,18 @@
 
         assertNull(token.findMainWindow());
 
-        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token);
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        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");
         token.addWindow(window1);
         assertEquals(window1, token.findMainWindow());
         window1.mAnimatingExit = true;
         assertEquals(window1, token.findMainWindow());
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token);
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
         token.addWindow(window2);
         assertEquals(window2, token.findMainWindow());
     }
 
-    private WindowState createWindow(WindowState parent, int type, WindowToken token) {
-        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
-        return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0);
-    }
-
     /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
     private class TestAppWindowToken extends AppWindowToken {
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 225dc5d2..0801a88 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,28 +16,15 @@
 
 package com.android.server.wm;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.WindowManager;
 
 import java.util.ArrayList;
 
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.AppOpsManager.OP_NONE;
-import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -47,7 +34,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
 
 /**
  * Tests for the {@link DisplayContent} class.
@@ -58,21 +44,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class DisplayContentTests {
-
-    private static WindowManagerService sWm = null;
-    private final IWindow mIWindow = new TestIWindow();
-    private final Session mMockSession = mock(Session.class);
-    private Display mDisplay;
-    private int mNextStackId = FIRST_DYNAMIC_STACK_ID;
-    private int mNextTaskId = 0;
-
-    @Before
-    public void setUp() throws Exception {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
-        mDisplay = context.getDisplay();
-    }
+public class DisplayContentTests extends WindowTestsBase {
 
     @Test
     public void testForAllWindows() throws Exception {
@@ -124,36 +96,4 @@
         assertEquals(imeWindow, windows.get(1));
         assertEquals(imeDialogWindow, windows.get(0));
     }
-
-    private WindowToken createWindowToken(DisplayContent dc, int type) {
-        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
-            return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
-        }
-
-        final int stackId = mNextStackId++;
-        dc.addStackToDisplay(stackId, true);
-        final TaskStack stack = sWm.mStackIdToStack.get(stackId);
-        final Task task = new Task(mNextTaskId++, stack, 0, sWm, null, EMPTY, false);
-        stack.addTask(task, true);
-        final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
-        task.addAppToken(0, token, 0, false);
-        return token;
-    }
-
-    private WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
-        final WindowToken token = createWindowToken(dc, type);
-        return createWindow(parent, type, token, name);
-    }
-
-    private WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
-        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-        attrs.setTitle(name);
-
-        final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
-                0, attrs, 0, 0);
-        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
-        // adding it to the token...
-        token.addWindow(w);
-        return w;
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
new file mode 100644
index 0000000..5a035d6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
@@ -0,0 +1,149 @@
+/*
+ * 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.Before;
+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.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
+/**
+ * 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 {
+
+    private static boolean sOneTimeSetupDone = false;
+    private static WindowLayersController sLayersController;
+    private static DisplayContent sDisplayContent;
+    private static WindowState sImeWindow;
+    private static WindowState sImeDialogWindow;
+    private static WindowState sStatusBarWindow;
+    private static WindowState sDockedDividerWindow;
+    private static WindowState sNavBarWindow;
+    private static WindowState sAppWindow;
+    private static WindowState sChildAppWindow;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        if (sOneTimeSetupDone) {
+            return;
+        }
+        sOneTimeSetupDone = true;
+        sLayersController = new WindowLayersController(sWm);
+        sDisplayContent =
+                new DisplayContent(mDisplay, sWm, sLayersController, new WallpaperController(sWm));
+        final WindowState wallpaperWindow =
+                createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
+        sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
+        sImeDialogWindow =
+                createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
+        sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
+        sNavBarWindow =
+                createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow");
+        sDockedDividerWindow =
+                createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
+        sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
+        sChildAppWindow = createWindow(sAppWindow,
+                TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindow");
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+        sWm.mInputMethodTarget = null;
+        sLayersController.assignWindowLayers(sDisplayContent);
+
+        // 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(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+        assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+        assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
+        sWm.mInputMethodTarget = imeAppTarget;
+        sLayersController.assignWindowLayers(sDisplayContent);
+
+        // Ime should be above all app windows and below system windows if it is targeting an app
+        // window.
+        assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+        assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+        assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+    }
+
+    @Test
+    public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+        final WindowState imeSystemOverlayTarget =
+                createWindow(null, TYPE_SYSTEM_OVERLAY, sDisplayContent, "imeSystemOverlayTarget");
+
+        sWm.mInputMethodTarget = imeSystemOverlayTarget;
+        sLayersController.assignWindowLayers(sDisplayContent);
+
+        // 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(sImeWindow, imeSystemOverlayTarget);
+        assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+        assertWindowLayerGreaterThan(sImeWindow, sStatusBarWindow);
+        assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+
+        // And, IME dialogs should always have an higher layer than the IME.
+        assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+    }
+
+    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/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 4499275..50e5a22 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -46,25 +46,25 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class WindowStateTests {
+public class WindowStateTests extends WindowTestsBase {
 
-    private static WindowManagerService sWm = null;
     private WindowToken mWindowToken;
-    private final IWindow mIWindow = new TestIWindow();
 
     @Before
     public void setUp() throws Exception {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+        super.setUp();
         mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
                 sWm.getDefaultDisplayContentLocked());
     }
 
     @Test
     public void testIsParentWindowHidden() throws Exception {
-        final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
-        final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
-        final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
+        final WindowState parentWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+        final WindowState child1 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+        final WindowState child2 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
 
         assertFalse(parentWindow.mHidden);
         assertFalse(parentWindow.isParentWindowHidden());
@@ -79,10 +79,14 @@
 
     @Test
     public void testIsChildWindow() throws Exception {
-        final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
-        final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
-        final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
-        final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
+        final WindowState parentWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+        final WindowState child1 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+        final WindowState child2 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
+        final WindowState randomWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
 
         assertFalse(parentWindow.isChildWindow());
         assertTrue(child1.isChildWindow());
@@ -92,12 +96,13 @@
 
     @Test
     public void testHasChild() throws Exception {
-        final WindowState win1 = createWindow(null, TYPE_APPLICATION);
-        final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW);
-        final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW);
-        final WindowState win2 = createWindow(null, TYPE_APPLICATION);
-        final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW);
-        final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
+        final WindowState win1 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win1");
+        final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win11");
+        final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win12");
+        final WindowState win2 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win2");
+        final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW, mWindowToken, "win21");
+        final WindowState randomWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
 
         assertTrue(win1.hasChild(win11));
         assertTrue(win1.hasChild(win12));
@@ -113,23 +118,28 @@
 
     @Test
     public void testGetBottomChild() throws Exception {
-        final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
+        final WindowState parentWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
         assertNull(parentWindow.getBottomChild());
 
-        final WindowState child1 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
+        final WindowState child1 =
+                createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child1");
         assertEquals(child1, parentWindow.getBottomChild());
 
-        final WindowState child2 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
+        final WindowState child2 =
+                createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child2");
         // Since child1 and child2 are at the same layer, then child2 is expect to be added on top
         // on child1
         assertEquals(child1, parentWindow.getBottomChild());
 
-        final WindowState child3 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
+        final WindowState child3 =
+                createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child3");
         // Since child3 is a negative layer, we would expect it to be added below current children
         // with positive layers.
         assertEquals(child3, parentWindow.getBottomChild());
 
-        final WindowState child4 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
+        final WindowState child4 =
+                createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child4");
         // We would also expect additional negative layers to be added below existing negative
         // layers.
         assertEquals(child4, parentWindow.getBottomChild());
@@ -137,9 +147,12 @@
 
     @Test
     public void testGetParentWindow() throws Exception {
-        final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
-        final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
-        final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
+        final WindowState parentWindow =
+                createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+        final WindowState child1 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+        final WindowState child2 =
+                createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
 
         assertNull(parentWindow.getParentWindow());
         assertEquals(parentWindow, child1.getParentWindow());
@@ -148,9 +161,9 @@
 
     @Test
     public void testGetTopParentWindow() throws Exception {
-        final WindowState root = createWindow(null, TYPE_APPLICATION);
-        final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW);
-        final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW);
+        final WindowState root = createWindow(null, TYPE_APPLICATION, mWindowToken, "root");
+        final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, mWindowToken, "child1");
+        final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, mWindowToken, "child2");
 
         assertEquals(root, root.getTopParentWindow());
         assertEquals(root, child1.getTopParentWindow());
@@ -160,16 +173,10 @@
 
     @Test
     public void testIsOnScreen_hiddenByPolicy() {
-        final WindowState window = createWindow(null, TYPE_APPLICATION);
+        final WindowState window = createWindow(null, TYPE_APPLICATION, mWindowToken, "window");
         window.setHasSurface(true);
         assertTrue(window.isOnScreen());
         window.hideLw(false /* doAnimation */);
         assertFalse(window.isOnScreen());
     }
-
-    private WindowState createWindow(WindowState parent, int type) {
-        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
-        return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0, 0);
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
new file mode 100644
index 0000000..9681bd2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -0,0 +1,90 @@
+/*
+ * 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.Assert;
+import org.junit.Before;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.support.test.InstrumentationRegistry;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.res.Configuration.EMPTY;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Common base class for window manager unit test classes.
+ */
+public class WindowTestsBase {
+    static WindowManagerService sWm = null;
+    private final IWindow mIWindow = new TestIWindow();
+    private final Session mMockSession = mock(Session.class);
+    Display mDisplay;
+    private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
+    private static int sNextTaskId = 0;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+        mDisplay = context.getDisplay();
+    }
+
+    /** Asserts that the first entry is greater than the second entry. */
+    void assertGreaterThan(int first, int second) throws Exception {
+        Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
+    }
+
+    WindowToken createWindowToken(DisplayContent dc, int type) {
+        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
+            return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
+        }
+
+        final int stackId = sNextStackId++;
+        dc.addStackToDisplay(stackId, true);
+        final TaskStack stack = sWm.mStackIdToStack.get(stackId);
+        final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false);
+        stack.addTask(task, true);
+        final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
+        task.addAppToken(0, token, 0, false);
+        return token;
+    }
+
+    WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
+        final WindowToken token = createWindowToken(dc, type);
+        return createWindow(parent, type, token, name);
+    }
+
+    WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+        attrs.setTitle(name);
+
+        final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
+                0, attrs, 0, 0);
+        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
+        // adding it to the token...
+        token.addWindow(w);
+        return w;
+    }
+}
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 d12d672a..d6bfa17 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -47,17 +47,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class WindowTokenTests {
-
-    private WindowManagerService mWm = null;
-    private final IWindow mIWindow = new TestIWindow();
-    private final Session mMockSession = mock(Session.class);
-
-    @Before
-    public void setUp() throws Exception {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
-    }
+public class WindowTokenTests extends WindowTestsBase {
 
     @Test
     public void testAddWindow() throws Exception {
@@ -65,11 +55,11 @@
 
         assertEquals(0, token.getWindowsCount());
 
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+        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");
 
         token.addWindow(window1);
         // NOTE: Child windows will not be added to the token as window containers can only
@@ -91,12 +81,12 @@
     @Test
     public void testChildRemoval() throws Exception {
         final TestWindowToken token = new TestWindowToken();
-        final DisplayContent dc = mWm.getDefaultDisplayContentLocked();
+        final DisplayContent dc = sWm.getDefaultDisplayContentLocked();
 
         assertEquals(token, dc.getWindowToken(token.token));
 
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
         token.addWindow(window1);
         token.addWindow(window2);
 
@@ -113,11 +103,11 @@
     @Test
     public void testAdjustAnimLayer() throws Exception {
         final TestWindowToken token = new TestWindowToken();
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
-        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+        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");
 
         token.addWindow(window1);
         token.addWindow(window2);
@@ -136,60 +126,11 @@
         assertEquals(window3StartLayer + adj, highestLayer);
     }
 
-    @Test
-    public void testGetTopWindow() throws Exception {
-        final TestWindowToken token = new TestWindowToken();
-
-        assertNull(token.getTopWindow());
-
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
-        token.addWindow(window1);
-        assertEquals(window1, token.getTopWindow());
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        assertEquals(window12, token.getTopWindow());
-
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
-        token.addWindow(window2);
-        // Since new windows are added to the bottom of the token, we would still expect the
-        // previous one to the top.
-        assertEquals(window12, token.getTopWindow());
-    }
-
-    @Test
-    public void testGetWindowIndex() throws Exception {
-        final TestWindowToken token = new TestWindowToken();
-
-        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
-        assertEquals(-1, token.getWindowIndex(window1));
-        token.addWindow(window1);
-        assertEquals(0, token.getWindowIndex(window1));
-        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
-        // Child windows should report the same index as their parents.
-        assertEquals(0, token.getWindowIndex(window11));
-        assertEquals(0, token.getWindowIndex(window12));
-
-        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
-        assertEquals(-1, token.getWindowIndex(window2));
-        token.addWindow(window2);
-        // Since new windows are added to the bottom of the token, we would expect the added window
-        // to be at index 0.
-        assertEquals(0, token.getWindowIndex(window2));
-        assertEquals(1, token.getWindowIndex(window1));
-    }
-
-    private WindowState createWindow(WindowState parent, int type, WindowToken token) {
-        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
-        return new WindowState(mWm, mMockSession, mIWindow, token, parent, OP_NONE, 0, attrs, 0, 0);
-    }
-
     /* Used so we can gain access to some protected members of the {@link WindowToken} class */
     private class TestWindowToken extends WindowToken {
 
         TestWindowToken() {
-            super(mWm, mock(IBinder.class), 0, false, mWm.getDefaultDisplayContentLocked());
+            super(sWm, mock(IBinder.class), 0, false, sWm.getDefaultDisplayContentLocked());
         }
 
         int getWindowsCount() {