Fixed window ordering issue with TYPE_VOICE_INTERACTION.
WC.forAllWindows returns windows based on their token order in the hierarchy and the non-app windows are ordered in the hierarchy based on their types. For most window tokens their types is specified when the token is added, but for some others we use the type of the first window added to the token. This becomes a problem if various window types are added to the same token (sys-ui I am looking at you...) and someone adds another token with a window type that should be z-ordered in-between the windows of the first token. For now we work around the problem by collecting all the non-app windows and making sure they are in order before return any window to the caller. Long term we want to change sys-ui and other callers to use different window tokens based on the window types they are adding. Fixes: 33538278 Test: bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests Change-Id: I83357975c87c704af9d0702c939ca99984462365
This commit is contained in:
@@ -2622,6 +2622,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
* Apps. E.g. status bar.
|
||||
*/
|
||||
private final class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
|
||||
final LinkedList<WindowState> mTmpWindows = new LinkedList();
|
||||
|
||||
private final ToBooleanFunction<WindowState> mCollectWindowsInOrder = w -> {
|
||||
int addIndex = mTmpWindows.size();
|
||||
for (int i = mTmpWindows.size() - 1; i >= 0; --i) {
|
||||
final WindowState current = mTmpWindows.get(i);
|
||||
if (w.mBaseLayer > current.mBaseLayer) {
|
||||
break;
|
||||
}
|
||||
addIndex = i;
|
||||
}
|
||||
|
||||
mTmpWindows.add(addIndex, w);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two child window tokens returns -1 if the first is lesser than the second in
|
||||
* terms of z-order and 1 otherwise.
|
||||
@@ -2652,6 +2668,29 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
addChild(token, mWindowComparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean forAllWindows(ToBooleanFunction<WindowState> callback,
|
||||
boolean traverseTopToBottom) {
|
||||
// Hack to work around WindowToken containing windows of various types there by causing
|
||||
// the windows not to be returned in visual order if there is another token with a
|
||||
// window that should be z-order in-between the windows of the first token. This is an
|
||||
// issue due to the various window types sys-ui adds with its token.
|
||||
// TODO: Have a separate token for each type of window sys-ui wants to add. Would
|
||||
// require some changes to sys-ui on the token it uses for window creation vs. just
|
||||
// using the default token of its process.
|
||||
mTmpWindows.clear();
|
||||
super.forAllWindows(mCollectWindowsInOrder, false /* traverseTopToBottom */);
|
||||
|
||||
while(!mTmpWindows.isEmpty()) {
|
||||
final WindowState current = traverseTopToBottom
|
||||
? mTmpWindows.pollLast() : mTmpWindows.pollFirst();
|
||||
if (callback.apply(current)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getOrientation() {
|
||||
final WindowManagerPolicy policy = mService.mPolicy;
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.support.test.runner.AndroidJUnit4;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,8 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
assertEquals(sNavBarWindow, windows.get(2));
|
||||
assertEquals(sImeWindow, windows.get(1));
|
||||
assertEquals(sImeDialogWindow, windows.get(0));
|
||||
|
||||
exitingAppWindow.removeImmediately();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,4 +124,45 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
sWm.mInputMethodTarget = null;
|
||||
imeAppTarget.removeImmediately();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
|
||||
// This window is set-up to be z-ordered between some windows that go in the same token like
|
||||
// the nav bar and status bar.
|
||||
final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
|
||||
sDisplayContent, "voiceInteractionWindow");
|
||||
|
||||
final ArrayList<WindowState> windows = new ArrayList();
|
||||
|
||||
// Test forward traversal.
|
||||
sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
|
||||
|
||||
assertEquals(sWallpaperWindow, windows.get(0));
|
||||
assertEquals(sChildAppWindowBelow, windows.get(1));
|
||||
assertEquals(sAppWindow, windows.get(2));
|
||||
assertEquals(sChildAppWindowAbove, windows.get(3));
|
||||
assertEquals(sDockedDividerWindow, windows.get(4));
|
||||
assertEquals(voiceInteractionWindow, windows.get(5));
|
||||
assertEquals(sStatusBarWindow, windows.get(6));
|
||||
assertEquals(sNavBarWindow, windows.get(7));
|
||||
assertEquals(sImeWindow, windows.get(8));
|
||||
assertEquals(sImeDialogWindow, windows.get(9));
|
||||
|
||||
// Test backward traversal.
|
||||
windows.clear();
|
||||
sDisplayContent.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
|
||||
|
||||
assertEquals(sWallpaperWindow, windows.get(9));
|
||||
assertEquals(sChildAppWindowBelow, windows.get(8));
|
||||
assertEquals(sAppWindow, windows.get(7));
|
||||
assertEquals(sChildAppWindowAbove, windows.get(6));
|
||||
assertEquals(sDockedDividerWindow, windows.get(5));
|
||||
assertEquals(voiceInteractionWindow, windows.get(4));
|
||||
assertEquals(sStatusBarWindow, windows.get(3));
|
||||
assertEquals(sNavBarWindow, windows.get(2));
|
||||
assertEquals(sImeWindow, windows.get(1));
|
||||
assertEquals(sImeDialogWindow, windows.get(0));
|
||||
|
||||
voiceInteractionWindow.removeImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,11 @@ public class WindowTestsBase {
|
||||
sImeDialogWindow =
|
||||
createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
|
||||
sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
|
||||
final WindowToken statusBarToken = sStatusBarWindow.mToken;
|
||||
sNavBarWindow =
|
||||
createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow");
|
||||
createWindow(null, TYPE_NAVIGATION_BAR, statusBarToken, "sNavBarWindow");
|
||||
sDockedDividerWindow =
|
||||
createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
|
||||
createWindow(null, TYPE_DOCK_DIVIDER, statusBarToken, "sDockedDividerWindow");
|
||||
sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
|
||||
sChildAppWindowAbove = createWindow(sAppWindow,
|
||||
TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindowAbove");
|
||||
|
||||
Reference in New Issue
Block a user