Merge "Add windows to window tokens in expected z-order"

This commit is contained in:
TreeHugger Robot
2016-10-28 21:52:14 +00:00
committed by Android (Google) Code Review
5 changed files with 116 additions and 26 deletions

View File

@@ -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);

View File

@@ -1085,12 +1085,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return null;
}
int addAppWindowToWindowList(final WindowState win) {
void addAppWindowToWindowList(final WindowState win) {
final IWindow client = win.mClient;
WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken);
if (!tokenWindowList.isEmpty()) {
return addAppWindowExisting(win, tokenWindowList);
addAppWindowExisting(win, tokenWindowList);
return;
}
// No windows from this token on this display
@@ -1128,7 +1129,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
addWindowToListBefore(win, pos);
return 0;
return;
}
// Continue looking down until we find the first token that has windows on this display.
@@ -1154,7 +1155,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
addWindowToListAfter(win, pos);
return 0;
return;
}
// Just search for the start of this layer.
@@ -1175,7 +1176,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
+ mWindows.size());
mWindows.add(i + 1, win);
mService.mWindowsChanged = true;
return 0;
}
/** Adds this non-app window to the window list. */
@@ -1778,23 +1778,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mLayoutNeeded;
}
private int addAppWindowExisting(WindowState win, WindowList tokenWindowList) {
private void addAppWindowExisting(WindowState win, WindowList tokenWindowList) {
int tokenWindowsPos;
// If this application has existing windows, we simply place the new window on top of
// them... but keep the starting window on top.
if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
// Base windows go behind everything else.
final WindowState lowestWindow = tokenWindowList.get(0);
addWindowToListBefore(win, lowestWindow);
tokenWindowsPos = win.mToken.getWindowIndex(lowestWindow);
} else {
final AppWindowToken atoken = win.mAppToken;
final int windowListPos = tokenWindowList.size();
final WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
if (atoken != null && lastWindow == atoken.startingWindow) {
addWindowToListBefore(win, lastWindow);
tokenWindowsPos = win.mToken.getWindowIndex(lastWindow);
} else {
int newIdx = findIdxBasedOnAppTokens(win);
// There is a window above this one associated with the same apptoken note that the
@@ -1804,16 +1801,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
"not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
+ mWindows.size());
mWindows.add(newIdx + 1, win);
if (newIdx < 0) {
// No window from token found on win's display.
tokenWindowsPos = 0;
} else {
tokenWindowsPos = win.mToken.getWindowIndex(mWindows.get(newIdx)) + 1;
}
mService.mWindowsChanged = true;
}
}
return tokenWindowsPos;
}
/** Places the first input window after the second input window in the window list. */

View File

@@ -24,6 +24,7 @@ import android.util.Slog;
import android.view.DisplayInfo;
import java.io.PrintWriter;
import java.util.Comparator;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -82,6 +83,26 @@ class WindowToken extends WindowContainer<WindowState> {
// 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<WindowState> 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<WindowState> {
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);

View File

@@ -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();
}
}
}

View File

@@ -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