Allow exempting IMEs from being unbound by IMMS

This CL introduces a denylist so that IMEs which cannot handle being
frequently unbound can be exempt from the preventable startup
behavior, such as the virtual remote IME.

Bug: 216618758
Test: atest CtsInputMethodTestCases
Test: also manually
Change-Id: Id0aaa496ee46532d0e97c236df7e073947ababcd
This commit is contained in:
Nikolas Havrikov
2022-02-01 10:58:50 +01:00
parent 535a34fac5
commit 76a3c8c9b3
3 changed files with 53 additions and 7 deletions

View File

@@ -2963,6 +2963,11 @@
the currently focused view is a text editor. --> the currently focused view is a text editor. -->
<bool name="config_preventImeStartupUnlessTextEditor">false</bool> <bool name="config_preventImeStartupUnlessTextEditor">false</bool>
<!-- These IMEs are known not to behave well when evicted from memory and thus are exempt
from the IME startup prevention behavior that is enabled by
config_preventImeStartupUnlessTextEditor. -->
<string-array name="config_nonPreemptibleInputMethods" translatable="false" />
<!-- The list of classes that should be added to the notification ranking pipeline. <!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor} See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update If you add a new extractor to this list make sure to update

View File

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

View File

@@ -49,6 +49,7 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT; import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -187,6 +188,8 @@ import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.utils.PriorityDump; import com.android.server.utils.PriorityDump;
import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowManagerInternal;
import com.google.android.collect.Sets;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -201,6 +204,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -267,6 +271,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
*/ */
private final boolean mPreventImeStartupUnlessTextEditor; private final boolean mPreventImeStartupUnlessTextEditor;
/**
* These IMEs are known not to behave well when evicted from memory and thus are exempt
* from the IME startup avoidance behavior that is enabled by
* {@link #mPreventImeStartupUnlessTextEditor}.
*/
@NonNull
private final Set<String> mNonPreemptibleInputMethods;
@UserIdInt @UserIdInt
private int mLastSwitchUserId; private int mLastSwitchUserId;
@@ -1692,6 +1704,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mBindingController = new InputMethodBindingController(this); mBindingController = new InputMethodBindingController(this);
mPreventImeStartupUnlessTextEditor = mRes.getBoolean( mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray(
com.android.internal.R.array.config_nonPreemptibleInputMethods));
mHwController = new HandwritingModeController(thread.getLooper(), mHwController = new HandwritingModeController(thread.getLooper(),
new InkWindowInitializer()); new InkWindowInitializer());
} }
@@ -2548,7 +2562,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputFlags int startInputFlags, @StartInputReason int startInputReason, @StartInputFlags int startInputFlags, @StartInputReason int startInputReason,
int unverifiedTargetSdkVersion) { int unverifiedTargetSdkVersion) {
// If no method is currently selected, do nothing. // If no method is currently selected, do nothing.
String selectedMethodId = getSelectedMethodIdLocked(); final String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) { if (selectedMethodId == null) {
return InputBindResult.NO_IME; return InputBindResult.NO_IME;
} }
@@ -2592,10 +2606,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurAttribute = attribute; mCurAttribute = attribute;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing // If configured, we want to avoid starting up the IME if it is not supposed to be showing
if (mPreventImeStartupUnlessTextEditor if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
&& !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, unverifiedTargetSdkVersion)) {
startInputFlags)
&& !mShowRequested) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method."); Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
} }
@@ -2636,6 +2648,34 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return mBindingController.bindCurrentMethod(); return mBindingController.bindCurrentMethod();
} }
@GuardedBy("ImfLock.class")
private boolean shouldPreventImeStartupLocked(
@NonNull String selectedMethodId,
@StartInputFlags int startInputFlags,
int unverifiedTargetSdkVersion) {
// Fast-path for the majority of cases
if (!mPreventImeStartupUnlessTextEditor) {
return false;
}
final boolean imeVisibleAllowed =
isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags);
return !(imeVisibleAllowed
|| mShowRequested
|| isNonPreemptibleImeLocked(selectedMethodId));
}
/** Return {@code true} if the given IME is non-preemptible like the tv remote service. */
@GuardedBy("ImfLock.class")
private boolean isNonPreemptibleImeLocked(@NonNull String selectedMethodId) {
final InputMethodInfo imi = mMethodMap.get(selectedMethodId);
if (imi != null) {
return mNonPreemptibleInputMethods.contains(imi.getPackageName());
}
return false;
}
@GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class")
private boolean isSelectedMethodBoundLocked() { private boolean isSelectedMethodBoundLocked() {
String curId = getCurIdLocked(); String curId = getCurIdLocked();
@@ -3826,7 +3866,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case LayoutParams.SOFT_INPUT_STATE_VISIBLE: case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward"); if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed( if (isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) { unverifiedTargetSdkVersion, startInputFlags)) {
if (attribute != null) { if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute, res = startInputUncheckedLocked(cs, inputContext, attribute,
@@ -3844,7 +3884,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
break; break;
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
if (DEBUG) Slog.v(TAG, "Window asks to always show input"); if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed( if (isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) { unverifiedTargetSdkVersion, startInputFlags)) {
if (!sameWindowFocused) { if (!sameWindowFocused) {
if (attribute != null) { if (attribute != null) {