From 417823dabc9b80c7789083277b842a8b35bc8593 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Thu, 25 Jun 2020 16:27:35 +0200 Subject: [PATCH] IME: Fix broken IME target calculation for child windows When the IME target ends up being a starting window, we try to use the window behind it - but fail to take into account the child windows of the window behind, which may also be candidates for IME targets. Also unifies the treatment of TYPE_APPLICATION_STARTING regardless of the surface format (currently, starting windows always have alpha, so this is a no-op change, but unblocks testing and prevents accidentially triggering the other code path should we change the screenshot format). Fixes: 159267713 Bug: 159290973 Test: atest 'DisplayContentTests#testComputeImeTarget_startingWindow' Change-Id: Iedd5f7407926167f4891ce9b7e9a79e22751e668 --- .../com/android/server/wm/ActivityRecord.java | 6 ++-- .../com/android/server/wm/WindowState.java | 12 +++---- .../server/wm/DisplayContentTests.java | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 319fd18faca5d..2a68a194b369f 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3556,10 +3556,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A WindowState getImeTargetBelowWindow(WindowState w) { final int index = mChildren.indexOf(w); if (index > 0) { - final WindowState target = mChildren.get(index - 1); - if (target.canBeImeTarget()) { - return target; - } + return mChildren.get(index - 1) + .getWindow(WindowState::canBeImeTarget); } return null; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 26a1fea1732b3..0cf941eb8e6dd 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2385,23 +2385,23 @@ class WindowState extends WindowContainer implements WindowManagerP return false; } - if (PixelFormat.formatHasAlpha(mAttrs.format)) { + if (mAttrs.type == TYPE_APPLICATION_STARTING) { + // Ignore mayUseInputMethod for starting window for now. + // TODO(b/159911356): Remove this special casing (originally added in commit e75d872). + } else if (PixelFormat.formatHasAlpha(mAttrs.format)) { // Support legacy use cases where transparent windows can still be ime target with // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set. // Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to // manually synchronize app content to IME animation b/144619551. // TODO(b/145812508): remove this once new focus management is complete b/141738570 final int fl = mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM); - final int type = mAttrs.type; // Can only be an IME target if both FLAG_NOT_FOCUSABLE and FLAG_ALT_FOCUSABLE_IM are // set or both are cleared...and not a starting window. - if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM) - && type != TYPE_APPLICATION_STARTING) { + if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM)) { return false; } - } else if (!WindowManager.LayoutParams.mayUseInputMethod(mAttrs.flags) - || mAttrs.type == TYPE_APPLICATION_STARTING) { + } else if (!WindowManager.LayoutParams.mayUseInputMethod(mAttrs.flags)) { // Can be an IME target only if: // 1. FLAG_NOT_FOCUSABLE is not set // 2. FLAG_ALT_FOCUSABLE_IM is not set diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 689674011d30d..d459064c568e9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -43,6 +43,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA 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_APPLICATION_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; @@ -273,6 +274,38 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(childWin, imeTarget); } + @Test + public void testComputeImeTarget_startingWindow() { + ActivityRecord activity = createActivityRecord(mDisplayContent, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); + + final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, + "startingWin"); + startingWin.setHasSurface(true); + assertTrue(startingWin.canBeImeTarget()); + + WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); + assertEquals(startingWin, imeTarget); + startingWin.mHidden = false; + + // Verify that an app window launching behind the starting window becomes the target + final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "appWin"); + appWin.setHasSurface(true); + assertTrue(appWin.canBeImeTarget()); + + imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); + assertEquals(appWin, imeTarget); + appWin.mHidden = false; + + // Verify that an child window can be an ime target even behind a launching app window + final WindowState childWin = createWindow(appWin, + TYPE_APPLICATION_ATTACHED_DIALOG, "childWin"); + childWin.setHasSurface(true); + assertTrue(childWin.canBeImeTarget()); + imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); + assertEquals(childWin, imeTarget); + } + /** * This tests stack movement between displays and proper stack's, task's and app token's display * container references updates.