From f4c200f56cdc538cd695a5b70524f958c8e8dd07 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Wed, 12 May 2021 20:48:44 +0800 Subject: [PATCH] Don't give the IME child window focus when switching tasks When switching the app task, we keep the IME window visibility for better transitioning experiences. However, in case IME created a child window without dismissing during the task switching to keep the window focus because the IME window has higher window hierarchy. Hence, we don't give it focus if the next IME layering target doesn't actually request the IME visible. Fix: 186329504 Test: manual as issue steps: 1) Tap any text box to bring up Gboard. 2) Tap access point -> '..' -> Share Gboard or Quality Bug Report. 3) Swipe up to Home screen. 4) Tap another text box. 6) Verify if the IME can shown as expected after editor focused Test: atest DisplayContentTests#\ testImeChildWindowFocusWhenImeLayeringTargetChanges Change-Id: I72618745542f33bcbb1001bd3b812e79f7652dda --- .../com/android/server/wm/DisplayContent.java | 10 +++++++ .../server/wm/DisplayContentTests.java | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 52317d9477aaa..01aa712b7855c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -724,6 +724,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return false; } + // When switching the app task, we keep the IME window visibility for better + // transitioning experiences. + // However, in case IME created a child window without dismissing during the task + // switching to keep the window focus because IME window has higher window hierarchy, + // we don't give it focus if the next IME layering target doesn't request IME visible. + if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null + || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) { + return false; + } + final ActivityRecord activity = w.mActivityRecord; if (focusedApp == null) { 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 ff4e5a60faac0..5fbe0a04e70b8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -31,6 +31,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_PRIVATE; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; +import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.Surface.ROTATION_0; @@ -2136,6 +2137,31 @@ public class DisplayContentTests extends WindowTestsBase { ACTIVITY_TYPE_STANDARD)); } + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeChildWindowFocusWhenImeLayeringTargetChanges() { + final WindowState imeChildWindow = + createWindow(mImeWindow, TYPE_APPLICATION_ATTACHED_DIALOG, "imeChildWindow"); + makeWindowVisibleAndDrawn(imeChildWindow, mImeWindow); + assertTrue(imeChildWindow.canReceiveKeys()); + mDisplayContent.setInputMethodWindowLocked(mImeWindow); + + // Verify imeChildWindow can be focused window if the next IME target requests IME visible. + final WindowState imeAppTarget = + createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); + mDisplayContent.setImeLayeringTarget(imeAppTarget); + spyOn(imeAppTarget); + doReturn(true).when(imeAppTarget).getRequestedVisibility(ITYPE_IME); + assertEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); + + // Verify imeChildWindow doesn't be focused window if the next IME target does not + // request IME visible. + final WindowState nextImeAppTarget = + createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget"); + mDisplayContent.setImeLayeringTarget(nextImeAppTarget); + assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); + } + private void removeRootTaskTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,