Merge "Fixed issues with child windows been IME targets"

This commit is contained in:
TreeHugger Robot
2017-02-21 19:44:45 +00:00
committed by Android (Google) Code Review
4 changed files with 194 additions and 144 deletions

View File

@@ -3889,7 +3889,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private boolean forAllWindowBottomToTop(ToBooleanFunction<WindowState> callback) {
// We want to consumer the negative sublayer children first because they need to appear
// We want to consume the negative sublayer children first because they need to appear
// below the parent, then this window (the parent), and then the positive sublayer children
// because they need to appear above the parent.
int i = 0;
@@ -3897,7 +3897,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
WindowState child = mChildren.get(i);
while (i < count && child.mSubLayer < 0) {
if (callback.apply(child)) {
if (child.applyInOrderWithImeWindows(callback, false /* traverseTopToBottom */)) {
return true;
}
i++;
@@ -3912,7 +3912,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
while (i < count) {
if (callback.apply(child)) {
if (child.applyInOrderWithImeWindows(callback, false /* traverseTopToBottom */)) {
return true;
}
i++;
@@ -3926,14 +3926,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private boolean forAllWindowTopToBottom(ToBooleanFunction<WindowState> callback) {
// We want to consumer the positive sublayer children first because they need to appear
// We want to consume the positive sublayer children first because they need to appear
// above the parent, then this window (the parent), and then the negative sublayer children
// because they need to appear above the parent.
int i = mChildren.size() - 1;
WindowState child = mChildren.get(i);
while (i >= 0 && child.mSubLayer >= 0) {
if (callback.apply(child)) {
if (child.applyInOrderWithImeWindows(callback, true /* traverseTopToBottom */)) {
return true;
}
--i;
@@ -3948,7 +3948,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
while (i >= 0) {
if (callback.apply(child)) {
if (child.applyInOrderWithImeWindows(callback, true /* traverseTopToBottom */)) {
return true;
}
--i;
@@ -3991,10 +3991,43 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
WindowState getWindow(Predicate<WindowState> callback) {
if (mChildren.isEmpty()) {
return callback.test(this) ? this : null;
}
// We want to consume the positive sublayer children first because they need to appear
// above the parent, then this window (the parent), and then the negative sublayer children
// because they need to appear above the parent.
int i = mChildren.size() - 1;
WindowState child = mChildren.get(i);
while (i >= 0 && child.mSubLayer >= 0) {
if (callback.test(child)) {
return child;
}
--i;
if (i < 0) {
break;
}
child = mChildren.get(i);
}
if (callback.test(this)) {
return this;
}
return super.getWindow(callback);
while (i >= 0) {
if (callback.test(child)) {
return child;
}
--i;
if (i < 0) {
break;
}
child = mChildren.get(i);
}
return null;
}
boolean isWindowAnimationSet() {

View File

@@ -16,24 +16,25 @@
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
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_VOICE_INTERACTION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import android.content.res.Configuration;
import android.hardware.display.DisplayManagerGlobal;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Display;
import android.view.DisplayInfo;
import java.util.ArrayList;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Tests for the {@link DisplayContent} class.
@@ -54,38 +55,17 @@ public class DisplayContentTests extends WindowTestsBase {
exitingAppToken.mIsExiting = true;
exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken);
final ArrayList<WindowState> windows = new ArrayList();
// Test forward traversal.
sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
assertEquals(sWallpaperWindow, windows.get(0));
assertEquals(exitingAppWindow, windows.get(1));
assertEquals(sChildAppWindowBelow, windows.get(2));
assertEquals(sAppWindow, windows.get(3));
assertEquals(sChildAppWindowAbove, windows.get(4));
assertEquals(sDockedDividerWindow, 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(exitingAppWindow, windows.get(8));
assertEquals(sChildAppWindowBelow, windows.get(7));
assertEquals(sAppWindow, windows.get(6));
assertEquals(sChildAppWindowAbove, windows.get(5));
assertEquals(sDockedDividerWindow, windows.get(4));
assertEquals(sStatusBarWindow, windows.get(3));
assertEquals(sNavBarWindow, windows.get(2));
assertEquals(sImeWindow, windows.get(1));
assertEquals(sImeDialogWindow, windows.get(0));
exitingAppWindow.removeImmediately();
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
exitingAppWindow,
sChildAppWindowBelow,
sAppWindow,
sChildAppWindowAbove,
sDockedDividerWindow,
sStatusBarWindow,
sNavBarWindow,
sImeWindow,
sImeDialogWindow));
}
@Test
@@ -95,78 +75,49 @@ public class DisplayContentTests extends WindowTestsBase {
sWm.mInputMethodTarget = imeAppTarget;
final ArrayList<WindowState> windows = new ArrayList();
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
sChildAppWindowBelow,
sAppWindow,
sChildAppWindowAbove,
imeAppTarget,
sImeWindow,
sImeDialogWindow,
sDockedDividerWindow,
sStatusBarWindow,
sNavBarWindow));
}
// Test forward traversal.
sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
@Test
public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
sWm.mInputMethodTarget = sChildAppWindowAbove;
assertEquals(sWallpaperWindow, windows.get(0));
assertEquals(sChildAppWindowBelow, windows.get(1));
assertEquals(sAppWindow, windows.get(2));
assertEquals(sChildAppWindowAbove, windows.get(3));
assertEquals(imeAppTarget, windows.get(4));
assertEquals(sImeWindow, windows.get(5));
assertEquals(sImeDialogWindow, windows.get(6));
assertEquals(sDockedDividerWindow, windows.get(7));
assertEquals(sStatusBarWindow, windows.get(8));
assertEquals(sNavBarWindow, 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(imeAppTarget, windows.get(5));
assertEquals(sImeWindow, windows.get(4));
assertEquals(sImeDialogWindow, windows.get(3));
assertEquals(sDockedDividerWindow, windows.get(2));
assertEquals(sStatusBarWindow, windows.get(1));
assertEquals(sNavBarWindow, windows.get(0));
// Clean-up
sWm.mInputMethodTarget = null;
imeAppTarget.removeImmediately();
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
sChildAppWindowBelow,
sAppWindow,
sChildAppWindowAbove,
sImeWindow,
sImeDialogWindow,
sDockedDividerWindow,
sStatusBarWindow,
sNavBarWindow));
}
@Test
public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
sWm.mInputMethodTarget = sStatusBarWindow;
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(sStatusBarWindow, windows.get(5));
assertEquals(sImeWindow, windows.get(6));
assertEquals(sImeDialogWindow, windows.get(7));
assertEquals(sNavBarWindow, windows.get(8));
// Test backward traversal.
windows.clear();
sDisplayContent.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
assertEquals(sWallpaperWindow, windows.get(8));
assertEquals(sChildAppWindowBelow, windows.get(7));
assertEquals(sAppWindow, windows.get(6));
assertEquals(sChildAppWindowAbove, windows.get(5));
assertEquals(sDockedDividerWindow, windows.get(4));
assertEquals(sStatusBarWindow, windows.get(3));
assertEquals(sImeWindow, windows.get(2));
assertEquals(sImeDialogWindow, windows.get(1));
assertEquals(sNavBarWindow, windows.get(0));
// Clean-up
sWm.mInputMethodTarget = null;
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
sChildAppWindowBelow,
sAppWindow,
sChildAppWindowAbove,
sDockedDividerWindow,
sStatusBarWindow,
sImeWindow,
sImeDialogWindow,
sNavBarWindow));
}
@Test
@@ -176,38 +127,35 @@ public class DisplayContentTests extends WindowTestsBase {
final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
sDisplayContent, "voiceInteractionWindow");
final ArrayList<WindowState> windows = new ArrayList();
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
sChildAppWindowBelow,
sAppWindow,
sChildAppWindowAbove,
sDockedDividerWindow,
voiceInteractionWindow,
sStatusBarWindow,
sNavBarWindow,
sImeWindow,
sImeDialogWindow));
}
// Test forward traversal.
sDisplayContent.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
@Test
public void testComputeImeTarget() throws Exception {
// Verify that an app window can be an ime target.
final WindowState appWin = createWindow(null, TYPE_APPLICATION, sDisplayContent, "appWin");
appWin.setHasSurface(true);
assertTrue(appWin.canBeImeTarget());
WindowState imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
assertEquals(appWin, imeTarget);
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();
// Verify that an child window can be an ime target.
final WindowState childWin = createWindow(appWin,
TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
childWin.setHasSurface(true);
assertTrue(childWin.canBeImeTarget());
imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
assertEquals(childWin, imeTarget);
}
/**
@@ -284,4 +232,24 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(currentOverrideConfig.densityDpi, globalConfig.densityDpi);
assertEquals(currentOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
}
private void assertForAllWindowsOrder(List<WindowState> expectedWindows) {
final LinkedList<WindowState> actualWindows = new LinkedList();
// Test forward traversal.
sDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
assertEquals(expectedWindows.size(), actualWindows.size());
for (WindowState w : expectedWindows) {
assertEquals(w, actualWindows.pollFirst());
}
assertTrue(actualWindows.isEmpty());
// Test backward traversal.
sDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
assertEquals(expectedWindows.size(), actualWindows.size());
for (WindowState w : expectedWindows) {
assertEquals(w, actualWindows.pollLast());
}
assertTrue(actualWindows.isEmpty());
}
}

View File

@@ -23,10 +23,17 @@ import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import java.util.LinkedList;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
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_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -167,4 +174,34 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(appWindow.canBeImeTarget());
assertFalse(imeWindow.canBeImeTarget());
}
@Test
public void testGetWindow() throws Exception {
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
final WindowState mediaChild = createWindow(root, TYPE_APPLICATION_MEDIA, "mediaChild");
final WindowState mediaOverlayChild = createWindow(root,
TYPE_APPLICATION_MEDIA_OVERLAY, "mediaOverlayChild");
final WindowState attachedDialogChild = createWindow(root,
TYPE_APPLICATION_ATTACHED_DIALOG, "attachedDialogChild");
final WindowState subPanelChild = createWindow(root,
TYPE_APPLICATION_SUB_PANEL, "subPanelChild");
final WindowState aboveSubPanelChild = createWindow(root,
TYPE_APPLICATION_ABOVE_SUB_PANEL, "aboveSubPanelChild");
final LinkedList<WindowState> windows = new LinkedList();
root.getWindow(w -> {
windows.addLast(w);
return false;
});
// getWindow should have returned candidate windows in z-order.
assertEquals(aboveSubPanelChild, windows.pollFirst());
assertEquals(subPanelChild, windows.pollFirst());
assertEquals(attachedDialogChild, windows.pollFirst());
assertEquals(root, windows.pollFirst());
assertEquals(mediaOverlayChild, windows.pollFirst());
assertEquals(mediaChild, windows.pollFirst());
assertTrue(windows.isEmpty());
}
}

View File

@@ -44,6 +44,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.EMPTY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
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_OVERLAY;
@@ -60,6 +61,7 @@ import static org.mockito.Mockito.mock;
import com.android.server.AttributeCache;
import java.util.HashSet;
import java.util.LinkedList;
/**
* Common base class for window manager unit test classes.
@@ -120,6 +122,7 @@ class WindowTestsBase {
sCommonWindows = new HashSet();
sWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
sImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "sImeWindow");
sWm.mInputMethodWindow = sImeWindow;
sImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "sImeDialogWindow");
sStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "sStatusBarWindow");
sNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "sNavBarWindow");
@@ -133,16 +136,25 @@ class WindowTestsBase {
@After
public void tearDown() throws Exception {
final LinkedList<WindowState> nonCommonWindows = new LinkedList();
sWm.mRoot.forAllWindows(w -> {
if (!sCommonWindows.contains(w)) {
w.removeImmediately();
nonCommonWindows.addLast(w);
}
}, true /* traverseTopToBottom */);
while (!nonCommonWindows.isEmpty()) {
nonCommonWindows.pollLast().removeImmediately();
}
sWm.mInputMethodTarget = null;
}
private static WindowState createCommonWindow(WindowState parent, int type, String name) {
final WindowState win = createWindow(parent, type, name);
sCommonWindows.add(win);
// Prevent common windows from been IMe targets
win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
return win;
}