From ee2a7ed3d971f83134a2b28258dd2e56f9634f94 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Wed, 15 Feb 2017 21:38:57 -0800 Subject: [PATCH] Allow setImeWindowStatus with null startInputToken This is a follow up CL to my previous CL [1], which caused an unexpected side effect that leads the current IME to crash due to a too strict requiremnt. It turns out that it was too early for us to start requiring non-null StartInputToken in InputMethodManagerService#setImeWindowStatus() because in many places we have assumed that an IME can show/hide its software keyboard even before an IME target window is associated with the IME. There are two major cases that we missed: - InputMethodManager#showSoftInputFromInputMethod(IBinder, int): This method does not require that the calling IME is already bound to an IME target window. - InputMethodManager#showSoftInputUnchecked(int ,ResultReceiver): This @hide method allows the caller application to let current IME show the software keyboard with bypassing all the normal focus management tasks in InputMethodManager. We should seriously consider to deprecate this @hide method, but to do that we have to clean up some internal components and SearchView in the support library that still rely on this method. Bug 35395372 is triggered by the second scenario, but until we sort out all the possible corner cases, we should allow null startInputToken as a valid request, like we had have done so before the CL [1] introduced such a validation. [1]: I9921b381e02106dbffff5e0b3d13f0a1245ce807 6db3bfe33d92127d203ec872a0b353585a99f256 Test: Made sure Bug 35395372 is no longer reproducible, that is, 1. Flash a new image and complete the setup wizard on a direct-boot unaware device. 2. Set a device password and require it upon each device boot. 3. adb reboot 4. Observe the default IME does not crash because of InvalidParameterException thrown by IMMS. Test: Made sure IMM#showSoftInputFromInputMethod(IBinder, int) does not throw an InvalidParameterException even in an extreme case. 1. Rebuild LatinIME with the following code in LatinIME.java @Override public AbstractInputMethodImpl onCreateInputMethodInterface() { return new InputMethodService.InputMethodImpl() { @Override public void attachToken(IBinder token) { super.attachToken(token); final InputMethodManager imm = getSystemService(InputMethodManager.class); final IBinder imeToken = getWindow().getWindow().getAttributes().token; imm.showSoftInputFromInputMethod(imeToken, 0); } }; } 2. adb install -r LatinIME.apk 3. adb shell ime enable com.android.inputmethod.latin/.LatinIME 4. adb shell ime set com.android.inputmethod.latin/.LatinIME 5. Tap any text field. 4. Observe LatinIME does not crash because of InvalidParameterException thrown by IMMS. Bug: 34628091 Bug: 35079353 Fixes: 35395372 Change-Id: Ib9448c551d9a30776a999c27a5ff20f1a095633a --- core/java/android/view/WindowManagerInternal.java | 7 +++++-- .../java/com/android/server/InputMethodManagerService.java | 12 +++--------- .../java/com/android/server/wm/WindowManagerService.java | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 7a5e670c02bd..a541a4cd3b1e 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -296,9 +296,12 @@ public abstract class WindowManagerInternal { * to corresponding API calls. Note that this state is not guaranteed * to be synchronized with state in WindowManagerService. * @param targetWindowToken token to identify the target window that the IME is associated with. + * {@code null} when application, system, or the IME itself decided to + * change its window visibility before being associated with any target + * window. */ - public abstract void updateInputMethodWindowStatus(IBinder imeToken, boolean imeWindowVisible, - IBinder targetWindowToken); + public abstract void updateInputMethodWindowStatus(@NonNull IBinder imeToken, + boolean imeWindowVisible, @Nullable IBinder targetWindowToken); /** * Returns true when the hardware keyboard is available. diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index e6f6e5764d95..8442c111edd4 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2033,10 +2033,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void setImeWindowStatus(IBinder token, IBinder startInputToken, int vis, int backDisposition) { - if (startInputToken == null) { - throw new InvalidParameterException("startInputToken cannot be null"); - } - if (!calledWithValidToken(token)) { return; } @@ -2044,15 +2040,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final StartInputInfo info; synchronized (mMethodMap) { info = mStartInputMap.get(startInputToken); - if (info == null) { - throw new InvalidParameterException("Unknown startInputToken=" + startInputToken); - } mImeWindowVis = vis; mBackDisposition = backDisposition; updateSystemUiLocked(token, vis, backDisposition); } - mWindowManagerInternal.updateInputMethodWindowStatus(info.mImeToken, - (vis & InputMethodService.IME_VISIBLE) != 0, info.mTargetWindow); + mWindowManagerInternal.updateInputMethodWindowStatus(token, + (vis & InputMethodService.IME_VISIBLE) != 0, + token != null ? info.mTargetWindow : null); } private void updateSystemUi(IBinder token, int vis, int backDisposition) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a53102f0abbf..78568fc8eea9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7914,8 +7914,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void updateInputMethodWindowStatus(IBinder imeToken, boolean imeWindowVisible, - IBinder targetWindowToken) { + public void updateInputMethodWindowStatus(@NonNull IBinder imeToken, + boolean imeWindowVisible, @Nullable IBinder targetWindowToken) { // TODO (b/34628091): Use this method to address the window animation issue. if (DEBUG_INPUT_METHOD) { Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken=" + imeToken -- 2.11.0