From 50dbc983bf86727cf29a3e5a55f7ecc75791e506 Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 19 May 2020 13:57:43 -0700 Subject: [PATCH] Check embedded windows for IME target When checking IME target, if the main window can't be IME target but the embedded window can be, the IME will not be z ordered correctly. The IME should be updated so it's z ordered to the embedded window. Since the embedded window is in a different display, we set the IME target to the host to avoid any issues with IME target being on a different display. Test: WindowStateTests#testCanWindowWithEmbeddedDisplayBeImeTarget Test: Host window with flag FLAG_NOT_FOCUSABLE and embedded without. IME can be shown for the embedded window Bug: 156785479 Change-Id: Id46dc8be16f1a00dd31d79cc61bfcb83a2515888 --- .../com/android/server/wm/WindowState.java | 22 +++++++++++++++++++ .../android/server/wm/WindowStateTests.java | 20 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e925ce5c2dac8..1089c6633795d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2262,7 +2262,29 @@ class WindowState extends WindowContainer implements WindowManagerP mHasSurface = hasSurface; } + /** + * Checks whether one of the Windows in a Display embedded in this Window can be an IME target. + */ + private boolean canWindowInEmbeddedDisplayBeImeTarget() { + final int embeddedDisplayContentsSize = mEmbeddedDisplayContents.size(); + for (int i = embeddedDisplayContentsSize - 1; i >= 0; i--) { + final DisplayContent edc = mEmbeddedDisplayContents.valueAt(i); + if (edc.forAllWindows(WindowState::canBeImeTarget, true)) { + return true; + } + } + return false; + } + boolean canBeImeTarget() { + // If any of the embedded windows can be the IME target, this window will be the final IME + // target. This is because embedded windows are on a different display in WM so it would + // cause confusion trying to set the IME to a window on a different display. Instead, just + // make the host window the IME target. + if (canWindowInEmbeddedDisplayBeImeTarget()) { + return true; + } + if (mIsImWindow) { // IME windows can't be IME targets. IME targets are required to be below the IME // windows and that wouldn't be possible if the IME window is its own target...silly. diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 0346329eccd47..8ce5daa635f2e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -269,6 +269,26 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(stack.shouldIgnoreInput()); } + @Test + public void testCanWindowWithEmbeddedDisplayBeImeTarget() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow"); + + imeWindow.setHasSurface(true); + appWindow.setHasSurface(true); + + appWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE; + assertFalse(appWindow.canBeImeTarget()); + + DisplayContent secondDisplay = createNewDisplay(); + final WindowState embeddedWindow = createWindow(null, TYPE_APPLICATION, secondDisplay, + "embeddedWindow"); + appWindow.addEmbeddedDisplayContent(secondDisplay); + embeddedWindow.setHasSurface(true); + embeddedWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE; + assertTrue(appWindow.canBeImeTarget()); + } + @Test public void testGetWindow() { final WindowState root = createWindow(null, TYPE_APPLICATION, "root");