Loading services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +5 −2 Original line number Diff line number Diff line Loading @@ -116,8 +116,10 @@ public abstract class InputMethodManagerInternal { * * @param windowToken the window token that is now in control, or {@code null} if no client * window is in control of the IME. * @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent * will end up to change later, or {@code false} otherwise. */ public abstract void reportImeControl(@Nullable IBinder windowToken); public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged); /** * Destroys the IME surface. Loading Loading @@ -176,7 +178,8 @@ public abstract class InputMethodManagerInternal { } @Override public void reportImeControl(@Nullable IBinder windowToken) { public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { } @Override Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +9 −3 Original line number Diff line number Diff line Loading @@ -4934,13 +4934,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken); } private void reportImeControl(@Nullable IBinder windowToken) { private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { synchronized (mMethodMap) { if (mCurFocusedWindow != windowToken) { // mCurPerceptible was set by the focused window, but it is no longer in control, // so we reset mCurPerceptible. mCurPerceptible = true; } if (imeParentChanged) { // Hide the IME method menu earlier when the IME surface parent will change in // case seeing the dialog dismiss flickering during the next focused window // starting the input connection. mMenuController.hideInputMethodMenu(); } } } Loading Loading @@ -4998,8 +5004,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override public void reportImeControl(@Nullable IBinder windowToken) { mService.reportImeControl(windowToken); public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { mService.reportImeControl(windowToken, imeParentChanged); } @Override Loading services/core/java/com/android/server/wm/DisplayContent.java +16 −7 Original line number Diff line number Diff line Loading @@ -733,14 +733,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 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 // However, in case IME created a child window or the IME selection dialog 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 && (mImeLayeringTarget == null || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) { if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { return false; } if (w.isChildWindow()) { return false; } } final ActivityRecord activity = w.mActivityRecord; if (focusedApp == null) { Loading Loading @@ -3993,7 +4000,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Update Ime parent when IME insets leash created or the new IME layering target might // updated from setImeLayeringTarget, which is the best time that default IME visibility // has been settled down after IME control target changed. if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) { final boolean imeParentChanged = prevImeControlTarget != mImeControlTarget || forceUpdateImeParent; if (imeParentChanged) { updateImeParent(); } Loading @@ -4001,7 +4010,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final IBinder token = win != null ? win.mClient.asBinder() : null; // Note: not allowed to call into IMMS with the WM lock held, hence the post. mWmService.mH.post(() -> InputMethodManagerInternal.get().reportImeControl(token) InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged) ); } Loading services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +26 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_ 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_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; Loading Loading @@ -2204,6 +2205,31 @@ public class DisplayContentTests extends WindowTestsBase { assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); } @UseTestDisplay(addWindows = W_INPUT_METHOD) @Test public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() { final WindowState imeMenuDialog = createWindow(mImeWindow, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog"); makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow); assertTrue(imeMenuDialog.canReceiveKeys()); mDisplayContent.setInputMethodWindowLocked(mImeWindow); // Verify imeMenuDialog 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(imeMenuDialog, mDisplayContent.findFocusedWindow()); // Verify imeMenuDialog 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(imeMenuDialog, mDisplayContent.findFocusedWindow()); } private void removeRootTaskTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, Loading Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +5 −2 Original line number Diff line number Diff line Loading @@ -116,8 +116,10 @@ public abstract class InputMethodManagerInternal { * * @param windowToken the window token that is now in control, or {@code null} if no client * window is in control of the IME. * @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent * will end up to change later, or {@code false} otherwise. */ public abstract void reportImeControl(@Nullable IBinder windowToken); public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged); /** * Destroys the IME surface. Loading Loading @@ -176,7 +178,8 @@ public abstract class InputMethodManagerInternal { } @Override public void reportImeControl(@Nullable IBinder windowToken) { public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { } @Override Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +9 −3 Original line number Diff line number Diff line Loading @@ -4934,13 +4934,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken); } private void reportImeControl(@Nullable IBinder windowToken) { private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { synchronized (mMethodMap) { if (mCurFocusedWindow != windowToken) { // mCurPerceptible was set by the focused window, but it is no longer in control, // so we reset mCurPerceptible. mCurPerceptible = true; } if (imeParentChanged) { // Hide the IME method menu earlier when the IME surface parent will change in // case seeing the dialog dismiss flickering during the next focused window // starting the input connection. mMenuController.hideInputMethodMenu(); } } } Loading Loading @@ -4998,8 +5004,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override public void reportImeControl(@Nullable IBinder windowToken) { mService.reportImeControl(windowToken); public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) { mService.reportImeControl(windowToken, imeParentChanged); } @Override Loading
services/core/java/com/android/server/wm/DisplayContent.java +16 −7 Original line number Diff line number Diff line Loading @@ -733,14 +733,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 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 // However, in case IME created a child window or the IME selection dialog 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 && (mImeLayeringTarget == null || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) { if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { return false; } if (w.isChildWindow()) { return false; } } final ActivityRecord activity = w.mActivityRecord; if (focusedApp == null) { Loading Loading @@ -3993,7 +4000,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Update Ime parent when IME insets leash created or the new IME layering target might // updated from setImeLayeringTarget, which is the best time that default IME visibility // has been settled down after IME control target changed. if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) { final boolean imeParentChanged = prevImeControlTarget != mImeControlTarget || forceUpdateImeParent; if (imeParentChanged) { updateImeParent(); } Loading @@ -4001,7 +4010,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final IBinder token = win != null ? win.mClient.asBinder() : null; // Note: not allowed to call into IMMS with the WM lock held, hence the post. mWmService.mH.post(() -> InputMethodManagerInternal.get().reportImeControl(token) InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged) ); } Loading
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +26 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_ 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_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; Loading Loading @@ -2204,6 +2205,31 @@ public class DisplayContentTests extends WindowTestsBase { assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); } @UseTestDisplay(addWindows = W_INPUT_METHOD) @Test public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() { final WindowState imeMenuDialog = createWindow(mImeWindow, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog"); makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow); assertTrue(imeMenuDialog.canReceiveKeys()); mDisplayContent.setInputMethodWindowLocked(mImeWindow); // Verify imeMenuDialog 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(imeMenuDialog, mDisplayContent.findFocusedWindow()); // Verify imeMenuDialog 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(imeMenuDialog, mDisplayContent.findFocusedWindow()); } private void removeRootTaskTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, Loading