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
This commit is contained in:
Nikolas Havrikov
2021-10-08 09:01:54 +00:00
parent 6560e43b06
commit 94506d40f2
6 changed files with 49 additions and 8 deletions

View File

@@ -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
}

View File

@@ -2897,6 +2897,10 @@
<!-- Make the IME killable by the lowmemorykiller by raising its oom_score_adj. -->
<bool name="config_killableInputMethods">false</bool>
<!-- Prevent the InputMethodManagerService from starting up the IME unless
the currently focused view is a text editor. -->
<bool name="config_preventImeStartupUnlessTextEditor">false</bool>
<!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update

View File

@@ -3311,6 +3311,8 @@
<staging-public-group type="bool" first-id="0x01cf0000">
<!-- @hide @SystemApi -->
<public name="config_systemCaptionsServiceCallsEnabled" />
<!-- @hide @TestApi -->
<public name="config_preventImeStartupUnlessTextEditor" />
</staging-public-group>
<staging-public-group type="fraction" first-id="0x01ce0000">

View File

@@ -2250,6 +2250,7 @@
<java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
<java-symbol type="bool" name="config_killableInputMethods" />
<java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />

View File

@@ -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

View File

@@ -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;
}