From 94506d40f217e00cdd2000bc8e1cefab0fe317b6 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 8 Oct 2021 09:01:54 +0000 Subject: [PATCH] Enable preventing IME startup for non-edit views This CL introduces the config_preventImeStartupUnlessTextEditor configuration option, which is disabled by default. When enabled, this prevents the IMMS from triggering an onStartInput unless the window receiving focus contains a text editor element or IME startup was explicitly requested by the client app. Bug: 199887357 Bug: 37617707 Test: set the config option to true in an overlay Test: manually on adt3 and another android tv device Test: atest CtsInputMethodTestCases Change-Id: Iacb29cfdb3825248ee8c40e610652f697aa2d6da --- core/api/test-current.txt | 1 + core/res/res/values/config.xml | 4 ++ core/res/res/values/public.xml | 2 + core/res/res/values/symbols.xml | 1 + .../InputMethodBindingController.java | 11 +++++- .../InputMethodManagerService.java | 38 +++++++++++++++---- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 89dc678360f15..8184f8f51ac13 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -59,6 +59,7 @@ package android { public static final class R.bool { field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005 field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004 + field public static final int config_preventImeStartupUnlessTextEditor; field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006 } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index be32c42eb30d9..baee71b14c835 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2897,6 +2897,10 @@ false + + false + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 527865f77257d..bcd8d6650a884 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2250,6 +2250,7 @@ + diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index c5dc23e30822c..375f1c76487f8 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -496,8 +496,17 @@ final class InputMethodBindingController { return; } + // No IME is currently connected. Reestablish the main connection. + if (!mHasConnection) { + if (DEBUG) { + Slog.d(TAG, "Cannot show input: no IME bound. Rebinding."); + } + bindCurrentMethodLocked(); + return; + } + long bindingDuration = SystemClock.uptimeMillis() - mLastBindTime; - if (mHasConnection && bindingDuration >= TIME_TO_RECONNECT) { + if (bindingDuration >= TIME_TO_RECONNECT) { // The client has asked to have the input method shown, but // we have been sitting here too long with a connection to the // service and no interface received, so let's disconnect/connect diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index da3729d7498f5..4bf9b560deff2 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -261,6 +261,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final String ACTION_SHOW_INPUT_METHOD_PICKER = "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"; + /** + * When set, {@link #startInputUncheckedLocked} will return + * {@link InputBindResult#NO_EDITOR} instead of starting an IME connection + * unless {@link StartInputFlags#IS_TEXT_EDITOR} is set. This behavior overrides + * {@link LayoutParams#SOFT_INPUT_STATE_VISIBLE SOFT_INPUT_STATE_VISIBLE} and + * {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE SOFT_INPUT_STATE_ALWAYS_VISIBLE} + * starting from {@link android.os.Build.VERSION_CODES#P}. + */ + private final boolean mPreventImeStartupUnlessTextEditor; + @UserIdInt private int mLastSwitchUserId; @@ -1648,6 +1658,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSettings, context); mMenuController = new InputMethodMenuController(this); mBindingController = new InputMethodBindingController(this); + mPreventImeStartupUnlessTextEditor = mRes.getBoolean( + com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); } @GuardedBy("mMethodMap") @@ -2311,7 +2323,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext, @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags, - @StartInputReason int startInputReason) { + @StartInputReason int startInputReason, int unverifiedTargetSdkVersion) { // If no method is currently selected, do nothing. String selectedMethodId = getSelectedMethodId(); if (selectedMethodId == null) { @@ -2360,6 +2372,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurInputContext = inputContext; mCurAttribute = attribute; + // If configured, we want to avoid starting up the IME if it is not supposed to be showing + if (mPreventImeStartupUnlessTextEditor + && !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, + startInputFlags) + && !mShowRequested) { + if (DEBUG) { + Slog.d(TAG, "Avoiding IME startup and unbinding current input method."); + } + mBindingController.unbindCurrentMethodLocked(); + return InputBindResult.NO_EDITOR; + } + // Check if the input method is changing. // We expect the caller has already verified that the client is allowed to access this // display ID. @@ -3302,7 +3326,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (attribute != null) { return startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags, - startInputReason); + startInputReason, unverifiedTargetSdkVersion); } return new InputBindResult( InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY, @@ -3343,7 +3367,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (isTextEditor && attribute != null && shouldRestoreImeVisibility(windowToken, softInputMode)) { res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags, - startInputReason); + startInputReason, unverifiedTargetSdkVersion); showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY); return res; @@ -3382,7 +3406,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Unspecified window will show input"); if (attribute != null) { res = startInputUncheckedLocked(cs, inputContext, attribute, - startInputFlags, startInputReason); + startInputFlags, startInputReason, unverifiedTargetSdkVersion); didStart = true; } showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, @@ -3413,7 +3437,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub unverifiedTargetSdkVersion, startInputFlags)) { if (attribute != null) { res = startInputUncheckedLocked(cs, inputContext, attribute, - startInputFlags, startInputReason); + startInputFlags, startInputReason, unverifiedTargetSdkVersion); didStart = true; } showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, @@ -3432,7 +3456,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!sameWindowFocused) { if (attribute != null) { res = startInputUncheckedLocked(cs, inputContext, attribute, - startInputFlags, startInputReason); + startInputFlags, startInputReason, unverifiedTargetSdkVersion); didStart = true; } showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, @@ -3461,7 +3485,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags, - startInputReason); + startInputReason, unverifiedTargetSdkVersion); } else { res = InputBindResult.NULL_EDITOR_INFO; }