From 07bcab787ea7ce65081dffe7da196f872a1be37a Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Fri, 14 Oct 2016 15:30:09 -0700 Subject: [PATCH] Add windows to window tokens in expected z-order Decouple the logic for adding window to a position in the parent window token from the position we are adding the window to in the window list. The window token now adds the windows in order based on the rules the rest of the system is using which makes the code a little more straightforward to follow. Test: bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests Change-Id: Ic9b724fba02279a0c4e92508d39e5e35171b6d8d --- .../com/android/server/wm/AppWindowToken.java | 28 +++++++++++ .../com/android/server/wm/DisplayContent.java | 22 +++------ .../com/android/server/wm/WindowToken.java | 41 +++++++++++++++-- .../server/wm/AppWindowTokenTests.java | 46 +++++++++++++++++-- .../android/server/wm/WindowTokenTests.java | 5 +- 5 files changed, 116 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index d46b535386437..a3f7ac6d6c0d4 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -676,6 +676,34 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mPendingRelaunchCount = 0; } + /** + * Returns true if the new child window we are adding to this token is considered greater than + * the existing child window in this token in terms of z-order. + */ + @Override + protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, + WindowState existingWindow) { + final int type1 = newWindow.mAttrs.type; + final int type2 = existingWindow.mAttrs.type; + + // Base application windows should be z-ordered BELOW all other windows in the app token. + if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) { + return false; + } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) { + return true; + } + + // Starting windows should be z-ordered ABOVE all other windows in the app token. + if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) { + return true; + } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) { + return false; + } + + // Otherwise the new window is greater than the existing window. + return true; + } + @Override void addWindow(WindowState w) { super.addWindow(w); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 7cd99714c00cb..0b39d65c9407b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1085,12 +1085,13 @@ class DisplayContent extends WindowContainer { // The display this token is on. private DisplayContent mDisplayContent; + /** + * Compares two child window of this token and returns -1 if the first is lesser than the + * second in terms of z-order and 1 otherwise. + */ + private final Comparator mWindowComparator = + (WindowState newWindow, WindowState existingWindow) -> { + final WindowToken token = WindowToken.this; + if (newWindow.mToken != token) { + throw new IllegalArgumentException("newWindow=" + newWindow + + " is not a child of token=" + token); + } + + if (existingWindow.mToken != token) { + throw new IllegalArgumentException("existingWindow=" + existingWindow + + " is not a child of token=" + token); + } + + return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1; + }; + WindowToken(WindowManagerService service, IBinder _token, int type, boolean _explicit, DisplayContent dc) { mService = service; @@ -168,19 +189,31 @@ class WindowToken extends WindowContainer { return -1; } + /** + * Returns true if the new window is considered greater than the existing window in terms of + * z-order. + */ + protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, + WindowState existingWindow) { + // By default the first window isn't greater than the second to preserve existing logic of + // how new windows are added to the token + return false; + } + void addWindow(final WindowState win) { - if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindow: win=" + win + " Callers=" + Debug.getCallers(5)); + if (DEBUG_FOCUS) Slog.d(TAG_WM, + "addWindow: win=" + win + " Callers=" + Debug.getCallers(5)); if (!win.isChildWindow()) { - int tokenWindowsPos = 0; if (asAppWindowToken() != null) { - tokenWindowsPos = mDisplayContent.addAppWindowToWindowList(win); + mDisplayContent.addAppWindowToWindowList(win); } else { mDisplayContent.addNonAppWindowToWindowList(win); } + if (!mChildren.contains(win)) { if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this); - addChild(win, tokenWindowsPos); + addChild(win, mWindowComparator); } } else { mDisplayContent.addChildWindowToWindowList(win); 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 74e8c9d52836e..d933cb377ef08 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -29,17 +29,19 @@ import android.view.IWindow; import android.view.WindowManager; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * Tests for the {@link WindowState} class. * - * Build: mmma -j32 frameworks/base/services/tests/servicestests - * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -w -e class com.android.server.wm.AppWindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests */ @SmallTest @Presubmit @@ -55,6 +57,36 @@ public class AppWindowTokenTests { sWm = TestWindowManagerPolicy.getWindowManagerService(context); } + @Test + public void testAddWindow_Order() throws Exception { + final TestAppWindowToken token = new TestAppWindowToken(); + + 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); + + token.addWindow(win1); + token.addWindow(startingWin); + token.addWindow(baseWin); + token.addWindow(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)); + + // The starting window should be on-top of all other windows. + assertEquals(startingWin, token.getLastChild()); + + // The base application window should be below all other windows. + assertEquals(baseWin, token.getFirstChild()); + } + @Test public void testFindMainWindow() throws Exception { final TestAppWindowToken token = new TestAppWindowToken(); @@ -93,5 +125,13 @@ public class AppWindowTokenTests { boolean hasWindow(WindowState w) { return mChildren.contains(w); } + + WindowState getFirstChild() { + return mChildren.getFirst(); + } + + WindowState getLastChild() { + return mChildren.getLast(); + } } } 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 546c7da0a013e..5326a192bf73f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java @@ -41,9 +41,8 @@ import static org.mockito.Mockito.mock; /** * Tests for the {@link WindowState} class. * - * Build: mmma -j32 frameworks/base/services/tests/servicestests - * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -w -e class com.android.server.wm.WindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests */ @SmallTest @Presubmit