diff options
4 files changed, 196 insertions, 146 deletions
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 65e1f84eae35..4cd1af9e5d8d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3876,7 +3876,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; @@ -3884,7 +3884,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++; @@ -3899,7 +3899,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } while (i < count) { - if (callback.apply(child)) { + if (child.applyInOrderWithImeWindows(callback, false /* traverseTopToBottom */)) { return true; } i++; @@ -3913,14 +3913,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; @@ -3935,7 +3935,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } while (i >= 0) { - if (callback.apply(child)) { + if (child.applyInOrderWithImeWindows(callback, true /* traverseTopToBottom */)) { return true; } --i; @@ -3978,10 +3978,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() { 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 30f99e58d887..bd3271b32715 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -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(); - - // 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(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)); + assertForAllWindowsOrder(Arrays.asList( + sWallpaperWindow, + sChildAppWindowBelow, + sAppWindow, + sChildAppWindowAbove, + imeAppTarget, + sImeWindow, + sImeDialogWindow, + sDockedDividerWindow, + sStatusBarWindow, + sNavBarWindow)); + } - // 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(); + @Test + public void testForAllWindows_WithChildWindowImeTarget() throws Exception { + sWm.mInputMethodTarget = sChildAppWindowAbove; + + 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(); - - // 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)); + assertForAllWindowsOrder(Arrays.asList( + sWallpaperWindow, + sChildAppWindowBelow, + sAppWindow, + sChildAppWindowAbove, + sDockedDividerWindow, + voiceInteractionWindow, + sStatusBarWindow, + sNavBarWindow, + sImeWindow, + sImeDialogWindow)); + } - // 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(); + @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); + + // 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()); + } } 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 df35b7eedaf6..5f5189825deb 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -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()); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index e5e351226306..52e10a542238 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -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; } |