From 1ef07dffe372e853873a4425345a9e532d520732 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Fri, 14 Aug 2020 01:11:25 +0800 Subject: [PATCH] Fix showing keyboard without editor focused in some cases (1/2) Starts from CL[1] that reporting focus change is now driven by input instead window manager, so the window focus sequence for the activity with EditTextPreference dialog after device unlock in between android Q and android R will be: [Android Q]: activity main window (with softInputMode STATE_UNSPECIFIED) -> EditTextPreference (with softInputMode STATE_ALWAYS_VISIBLE) [Android R]: Only EditTextPreference focused after device unlocked since the window is the last touched window. Since in Q, the softInputMode of activity main window is STATE_UNSPECIFIED , so by default InputMethodManagerService will hide soft-keyboard if there is no editor focused according this softInputMode flag. However, in R, because no main window focused, so after EditTextPerference focused and started the input connection, this will hit a logic to show soft-keyboard, if mShowRequested is true after the input session created. Since IMMS#mShowRequested originally is used to show soft-input while showSoftInput is called but IME service has been unbounded (e.g. switch IME or IME service killed), so use this flag can show soft-input aftter service re-connected. For the issue case, we should ignore STATE_ALWAYS_VISIBLE since the app's targetSdkVersion is P+ and no editor focus as CL[2] expectation. To fix that, first in IMMS side, we need to make sure to check startInputFlag and showSoftInputFlag again, even the focused window of the next start input is same, we still need to check its flag to show / hide keyboard, once the flags changed or the view focus cleared. [1]: Iff0b88a05441b29834741aa3dfae31d55871ddd6 [2]: I56682c7dee71d461687b9e80ab746d382fd55e0c Bug: 161506356 Fix: 162444230 Test: atest CtsInputMethodTestCases Change-Id: I37ae6e30d1de581ba15131c2a90396b3a522a4d6 --- .../InputMethodManagerService.java | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 9ab410d258ccf..c65e842363834 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3274,6 +3274,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { + if (mCurClient == null || mCurClient.curSession == null) { + return false; + } if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 && (mShowExplicitlyRequested || mShowForced)) { if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide"); @@ -3458,7 +3461,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // pre-rendering not supported on low-ram devices. cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam; - if (mCurFocusedWindow == windowToken) { + final boolean sameWindowFocused = mCurFocusedWindow == windowToken; + final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0; + if (sameWindowFocused && isTextEditor) { if (DEBUG) { Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client + " attribute=" + attribute + ", token = " + windowToken @@ -3473,6 +3478,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY, null, null, null, -1, null); } + mCurFocusedWindow = windowToken; mCurFocusedWindowSoftInputMode = softInputMode; mCurFocusedWindowClient = cs; @@ -3490,7 +3496,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub == LayoutParams.SOFT_INPUT_ADJUST_RESIZE || mRes.getConfiguration().isLayoutSizeAtLeast( Configuration.SCREENLAYOUT_SIZE_LARGE); - final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0; // We want to start input before showing the IME, but after closing // it. We want to do this after closing it to help the IME disappear @@ -3550,9 +3555,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } break; case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: - if (DEBUG) Slog.v(TAG, "Window asks to hide input"); - hideCurrentInputLocked(mCurFocusedWindow, 0, null, - SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE); + if (isImeVisible()) { + if (DEBUG) Slog.v(TAG, "Window asks to hide input"); + hideCurrentInputLocked(mCurFocusedWindow, 0, null, + SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE); + } break; case LayoutParams.SOFT_INPUT_STATE_VISIBLE: if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { @@ -3577,13 +3584,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Window asks to always show input"); if (InputMethodUtils.isSoftInputModeStateVisibleAllowed( unverifiedTargetSdkVersion, startInputFlags)) { - if (attribute != null) { - res = startInputUncheckedLocked(cs, inputContext, missingMethods, - attribute, startInputFlags, startInputReason); - didStart = true; + if (!isImeVisible()) { + if (attribute != null) { + res = startInputUncheckedLocked(cs, inputContext, missingMethods, + attribute, startInputFlags, startInputReason); + didStart = true; + } + showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE); } - showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, - SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE); } else { Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because" + " there is no focused view that also returns true from" @@ -3601,6 +3610,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else { res = InputBindResult.NO_EDITOR; } + } else if (sameWindowFocused) { + return new InputBindResult( + InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY, + null, null, null, -1, null); } else { res = InputBindResult.NULL_EDITOR_INFO; } @@ -3608,6 +3621,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return res; } + private boolean isImeVisible() { + return (mImeWindowVis & InputMethodService.IME_VISIBLE) != 0; + } + private boolean canShowInputMethodPickerLocked(IInputMethodClient client) { // TODO(yukawa): multi-display support. final int uid = Binder.getCallingUid();