From e8424ef6004ac39c5ba6af458b863d2e110ce8f9 Mon Sep 17 00:00:00 2001
From: Yohei Yukawa
Date: Wed, 15 Sep 2021 10:03:20 -0700
Subject: [PATCH] Deprecate MissingMethodFlags to preserve invocation order
This CL effectively replaces my previous CL [1], which made
unimplemented methods in InputConnection not fatal errors, with a
simplified implementation that still gracefully take care of
unimplemented methods without causing app crashes.
Instead of propagating missing method information from the IME client
to the IME process, this CL will simply catch AbstractMethodError in
the IME client process. Doing so enables us to
1. preserve the strict invocation order of InputConnection APIs, and
2. achieve the same goal with fewer lines of code.
The additional cost of throwing (and catching) AbstractMethodError
every time the IME calls an unimplemented InputConnection API can be
justified as it is really an exceptional scenario, and avoiding it
would require extra maintenance cost as seen in
InputConnectionInspector.
The above overhead (and complexity) due to AbstractMethodError can be
avoided by adding default implementations to those InputConnection
APIs, but doing so requires API signature update hence API council
approval to go ahead, which is to be discussed in Bug 199934664.
[1]: I3c58fadd924fad72cb984f0c23d3099fd0295c64
19a80a1e807acd00bec999eaac7812da6ffce954
Bug: 27407234
Bug: 27642734
Bug: 27650039
Bug: 194110780
Test: atest CtsInputMethodTestCases
Change-Id: I9e801e92496a6e16cee37664870c97ed096f1413
---
.../IInputMethodWrapper.java | 13 +-
.../RemoteInputConnection.java | 48 +--
.../view/inputmethod/InputConnection.java | 33 +-
.../inputmethod/InputConnectionInspector.java | 293 ------------------
.../inputmethod/InputConnectionWrapper.java | 12 -
.../view/inputmethod/InputMethodManager.java | 18 +-
.../RemoteInputConnectionImpl.java | 47 ++-
.../android/internal/view/IInputMethod.aidl | 2 +-
.../internal/view/IInputMethodManager.aidl | 1 -
.../InputMethodManagerService.java | 60 ++--
10 files changed, 88 insertions(+), 439 deletions(-)
delete mode 100644 core/java/android/view/inputmethod/InputConnectionInspector.java
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 8db6d9e1cd184..e30594fb9da7b 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -32,7 +32,6 @@ import android.view.InputChannel;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
@@ -190,10 +189,8 @@ class IInputMethodWrapper extends IInputMethod.Stub
final EditorInfo info = (EditorInfo) args.arg3;
final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
final boolean restarting = args.argi5 == 1;
- final int missingMethod = args.argi6;
final InputConnection ic = inputContext != null
- ? new RemoteInputConnection(
- mTarget, inputContext, missingMethod, cancellationGroup)
+ ? new RemoteInputConnection(mTarget, inputContext, cancellationGroup)
: null;
info.makeCompatible(mTargetSdkVersion);
inputMethod.dispatchStartInputWithToken(ic, info, restarting, startInputToken);
@@ -295,11 +292,8 @@ class IInputMethodWrapper extends IInputMethod.Stub
Log.e(TAG, "bindInput must be paired with unbindInput.");
}
mCancellationGroup = new CancellationGroup();
- // This IInputContext is guaranteed to implement all the methods.
- final int missingMethodFlags = 0;
InputConnection ic = new RemoteInputConnection(mTarget,
- IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags,
- mCancellationGroup);
+ IInputContext.Stub.asInterface(binding.getConnectionToken()), mCancellationGroup);
InputBinding nu = new InputBinding(ic, binding);
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
}
@@ -320,14 +314,13 @@ class IInputMethodWrapper extends IInputMethod.Stub
@BinderThread
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
- @InputConnectionInspector.MissingMethodFlags final int missingMethods,
EditorInfo attribute, boolean restarting) {
if (mCancellationGroup == null) {
Log.e(TAG, "startInput must be called after bindInput.");
mCancellationGroup = new CancellationGroup();
}
mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
- inputContext, attribute, mCancellationGroup, restarting ? 1 : 0, missingMethods));
+ inputContext, attribute, mCancellationGroup, restarting ? 1 : 0, 0 /* unused */));
}
@BinderThread
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 589dd7255a62d..657f8428179f0 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -29,8 +29,6 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionInspector;
-import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.SurroundingText;
@@ -87,9 +85,6 @@ final class RemoteInputConnection implements InputConnection {
@NonNull
private final InputMethodServiceInternalHolder mImsInternal;
- @MissingMethodFlags
- private final int mMissingMethods;
-
/**
* Signaled when the system decided to take away IME focus from the target app.
*
@@ -101,11 +96,9 @@ final class RemoteInputConnection implements InputConnection {
RemoteInputConnection(
@NonNull WeakReference inputMethodService,
- IInputContext inputContext, @MissingMethodFlags int missingMethods,
- @NonNull CancellationGroup cancellationGroup) {
+ IInputContext inputContext, @NonNull CancellationGroup cancellationGroup) {
mImsInternal = new InputMethodServiceInternalHolder(inputMethodService);
mInvoker = IInputContextInvoker.create(inputContext);
- mMissingMethods = missingMethods;
mCancellationGroup = cancellationGroup;
}
@@ -163,10 +156,6 @@ final class RemoteInputConnection implements InputConnection {
return null;
}
- if (isMethodMissing(MissingMethodFlags.GET_SELECTED_TEXT)) {
- // This method is not implemented.
- return null;
- }
final CompletableFuture value = mInvoker.getSelectedText(flags);
final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
@@ -200,10 +189,6 @@ final class RemoteInputConnection implements InputConnection {
return null;
}
- if (isMethodMissing(MissingMethodFlags.GET_SURROUNDING_TEXT)) {
- // This method is not implemented.
- return null;
- }
final CompletableFuture value = mInvoker.getSurroundingText(beforeLength,
afterLength, flags);
final SurroundingText result = CompletableFutureUtil.getResultOrNull(
@@ -284,10 +269,6 @@ final class RemoteInputConnection implements InputConnection {
@AnyThread
public boolean commitCorrection(CorrectionInfo correctionInfo) {
- if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
- // This method is not implemented.
- return false;
- }
return mInvoker.commitCorrection(correctionInfo);
}
@@ -308,10 +289,6 @@ final class RemoteInputConnection implements InputConnection {
@AnyThread
public boolean setComposingRegion(int start, int end) {
- if (isMethodMissing(MissingMethodFlags.SET_COMPOSING_REGION)) {
- // This method is not implemented.
- return false;
- }
return mInvoker.setComposingRegion(start, end);
}
@@ -360,10 +337,6 @@ final class RemoteInputConnection implements InputConnection {
@AnyThread
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
- if (isMethodMissing(MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS)) {
- // This method is not implemented.
- return false;
- }
return mInvoker.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
}
@@ -389,11 +362,6 @@ final class RemoteInputConnection implements InputConnection {
return false;
}
- if (isMethodMissing(MissingMethodFlags.REQUEST_CURSOR_UPDATES)) {
- // This method is not implemented.
- return false;
- }
-
final InputMethodServiceInternal ims = mImsInternal.getAndWarnIfNull();
if (ims == null) {
return false;
@@ -423,11 +391,6 @@ final class RemoteInputConnection implements InputConnection {
return false;
}
- if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
- // This method is not implemented.
- return false;
- }
-
if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal == null) {
@@ -450,17 +413,10 @@ final class RemoteInputConnection implements InputConnection {
return mInvoker.setImeConsumesInput(imeConsumesInput);
}
- @AnyThread
- private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
- return (mMissingMethods & methodFlag) == methodFlag;
- }
-
@AnyThread
@Override
public String toString() {
return "RemoteInputConnection{idHash=#"
- + Integer.toHexString(System.identityHashCode(this))
- + " mMissingMethods="
- + InputConnectionInspector.getMissingMethodFlagsAsString(mMissingMethods) + "}";
+ + Integer.toHexString(System.identityHashCode(this)) + "}";
}
}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 5185dc2543c78..aa28a9203b5e9 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -274,10 +274,7 @@ public interface InputConnection {
*
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or {@link #GET_TEXT_WITH_STYLES}.
- * @return the text that is currently selected, if any, or null if
- * no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
- * later, returns false when the target application does not implement
- * this method.
+ * @return the text that is currently selected, if any, or {@code null} if no text is selected.
*/
CharSequence getSelectedText(int flags);
@@ -483,8 +480,9 @@ public interface InputConnection {
* If this is greater than the number of existing characters between the cursor and
* the end of the text, then this method does not fail but deletes all the characters in
* that range.
- * @return true on success, false if the input connection is no longer valid. Returns
- * {@code false} when the target application does not implement this method.
+ * @return {@code true} on success, {@code false} if the input connection is no longer valid.
+ * Before Android {@link android.os.Build.VERSION_CODES#TIRAMISU}, this API returned
+ * {@code false} when the target application does not implement this method.
*/
boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
@@ -573,9 +571,10 @@ public interface InputConnection {
*
* @param start the position in the text at which the composing region begins
* @param end the position in the text at which the composing region ends
- * @return true on success, false if the input connection is no longer
- * valid. In {@link android.os.Build.VERSION_CODES#N} and later, false is returned when the
- * target application does not implement this method.
+ * @return {@code true} on success, {@code false} if the input connection is no longer valid.
+ * Since Android {@link android.os.Build.VERSION_CODES#N} until
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, this API returned {@code false} when
+ * the target application does not implement this method.
*/
boolean setComposingRegion(int start, int end);
@@ -686,9 +685,10 @@ public interface InputConnection {
* in progress.
*
* @param correctionInfo Detailed information about the correction.
- * @return true on success, false if the input connection is no longer valid.
- * In {@link android.os.Build.VERSION_CODES#N} and later, returns false
- * when the target application does not implement this method.
+ * @return {@code true} on success, {@code false} if the input connection is no longer valid.
+ * Since Android {@link android.os.Build.VERSION_CODES#N} until
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, this API returned {@code false} when
+ * the target application does not implement this method.
*/
boolean commitCorrection(CorrectionInfo correctionInfo);
@@ -924,10 +924,11 @@ public interface InputConnection {
* {@link #CURSOR_UPDATE_MONITOR}. Pass {@code 0} to disable the effect of
* {@link #CURSOR_UPDATE_MONITOR}.
* @return {@code true} if the request is scheduled. {@code false} to indicate that when the
- * application will not call
- * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
- * In {@link android.os.Build.VERSION_CODES#N} and later, returns {@code false} also when the
- * target application does not implement this method.
+ * application will not call {@link InputMethodManager#updateCursorAnchorInfo(
+ * android.view.View, CursorAnchorInfo)}.
+ * Since Android {@link android.os.Build.VERSION_CODES#N} until
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, this API returned {@code false} when
+ * the target application does not implement this method.
*/
boolean requestCursorUpdates(int cursorUpdateMode);
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
deleted file mode 100644
index 7621da7cef1bc..0000000000000
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.inputmethod;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-
-import java.lang.annotation.Retention;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * @hide
- */
-public final class InputConnectionInspector {
-
- @Retention(SOURCE)
- @IntDef({MissingMethodFlags.GET_SELECTED_TEXT,
- MissingMethodFlags.SET_COMPOSING_REGION,
- MissingMethodFlags.COMMIT_CORRECTION,
- MissingMethodFlags.REQUEST_CURSOR_UPDATES,
- MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
- MissingMethodFlags.GET_HANDLER,
- MissingMethodFlags.CLOSE_CONNECTION,
- MissingMethodFlags.COMMIT_CONTENT,
- MissingMethodFlags.GET_SURROUNDING_TEXT
- })
- public @interface MissingMethodFlags {
- /**
- * {@link InputConnection#getSelectedText(int)} is available in
- * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
- */
- int GET_SELECTED_TEXT = 1 << 0;
- /**
- * {@link InputConnection#setComposingRegion(int, int)} is available in
- * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
- */
- int SET_COMPOSING_REGION = 1 << 1;
- /**
- * {@link InputConnection#commitCorrection(CorrectionInfo)} is available in
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and later.
- */
- int COMMIT_CORRECTION = 1 << 2;
- /**
- * {@link InputConnection#requestCursorUpdates(int)} is available in
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
- */
- int REQUEST_CURSOR_UPDATES = 1 << 3;
- /**
- * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
- * {@link android.os.Build.VERSION_CODES#N} and later.
- */
- int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 1 << 4;
- /**
- * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
- * {@link android.os.Build.VERSION_CODES#N} and later.
- */
- int GET_HANDLER = 1 << 5;
- /**
- * {@link InputConnection#closeConnection()}} is available in
- * {@link android.os.Build.VERSION_CODES#N} and later.
- */
- int CLOSE_CONNECTION = 1 << 6;
- /**
- * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} is available in
- * {@link android.os.Build.VERSION_CODES#N} MR-1 and later.
- */
- int COMMIT_CONTENT = 1 << 7;
- /**
- * {@link InputConnection#getSurroundingText(int, int, int)} is available in
- * {@link android.os.Build.VERSION_CODES#S} and later.
- */
- int GET_SURROUNDING_TEXT = 1 << 8;
- }
-
- private static final Map sMissingMethodsMap = Collections.synchronizedMap(
- new WeakHashMap<>());
-
- @MissingMethodFlags
- public static int getMissingMethodFlags(@Nullable final InputConnection ic) {
- if (ic == null) {
- return 0;
- }
- // Optimization for a known class.
- if (ic instanceof BaseInputConnection) {
- return 0;
- }
- // Optimization for a known class.
- if (ic instanceof InputConnectionWrapper) {
- return ((InputConnectionWrapper) ic).getMissingMethodFlags();
- }
- return getMissingMethodFlagsInternal(ic.getClass());
- }
-
- @MissingMethodFlags
- public static int getMissingMethodFlagsInternal(@NonNull final Class clazz) {
- final Integer cachedFlags = sMissingMethodsMap.get(clazz);
- if (cachedFlags != null) {
- return cachedFlags;
- }
- int flags = 0;
- if (!hasGetSelectedText(clazz)) {
- flags |= MissingMethodFlags.GET_SELECTED_TEXT;
- }
- if (!hasSetComposingRegion(clazz)) {
- flags |= MissingMethodFlags.SET_COMPOSING_REGION;
- }
- if (!hasCommitCorrection(clazz)) {
- flags |= MissingMethodFlags.COMMIT_CORRECTION;
- }
- if (!hasRequestCursorUpdate(clazz)) {
- flags |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
- }
- if (!hasDeleteSurroundingTextInCodePoints(clazz)) {
- flags |= MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS;
- }
- if (!hasGetHandler(clazz)) {
- flags |= MissingMethodFlags.GET_HANDLER;
- }
- if (!hasCloseConnection(clazz)) {
- flags |= MissingMethodFlags.CLOSE_CONNECTION;
- }
- if (!hasCommitContent(clazz)) {
- flags |= MissingMethodFlags.COMMIT_CONTENT;
- }
- if (!hasGetSurroundingText(clazz)) {
- flags |= MissingMethodFlags.GET_SURROUNDING_TEXT;
- }
- sMissingMethodsMap.put(clazz, flags);
- return flags;
- }
-
- private static boolean hasGetSelectedText(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("getSelectedText", int.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasSetComposingRegion(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("setComposingRegion", int.class, int.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasCommitCorrection(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("commitCorrection", CorrectionInfo.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasRequestCursorUpdate(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("requestCursorUpdates", int.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasDeleteSurroundingTextInCodePoints(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("deleteSurroundingTextInCodePoints", int.class,
- int.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasGetHandler(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("getHandler");
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasCloseConnection(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("closeConnection");
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasCommitContent(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("commitContent", InputContentInfo.class,
- int.class, Bundle.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- private static boolean hasGetSurroundingText(@NonNull final Class clazz) {
- try {
- final Method method = clazz.getMethod("getSurroundingText", int.class, int.class,
- int.class);
- return !Modifier.isAbstract(method.getModifiers());
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
- final StringBuilder sb = new StringBuilder();
- boolean isEmpty = true;
- if ((flags & MissingMethodFlags.GET_SELECTED_TEXT) != 0) {
- sb.append("getSelectedText(int)");
- isEmpty = false;
- }
- if ((flags & MissingMethodFlags.SET_COMPOSING_REGION) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("setComposingRegion(int, int)");
- isEmpty = false;
- }
- if ((flags & MissingMethodFlags.COMMIT_CORRECTION) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("commitCorrection(CorrectionInfo)");
- isEmpty = false;
- }
- if ((flags & MissingMethodFlags.REQUEST_CURSOR_UPDATES) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("requestCursorUpdate(int)");
- isEmpty = false;
- }
- if ((flags & MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("deleteSurroundingTextInCodePoints(int, int)");
- isEmpty = false;
- }
- if ((flags & MissingMethodFlags.GET_HANDLER) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("getHandler()");
- }
- if ((flags & MissingMethodFlags.CLOSE_CONNECTION) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("closeConnection()");
- }
- if ((flags & MissingMethodFlags.COMMIT_CONTENT) != 0) {
- if (!isEmpty) {
- sb.append(",");
- }
- sb.append("commitContent(InputContentInfo, Bundle)");
- }
- return sb.toString();
- }
-}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index b1501a4c035c5..a99e9b8aab077 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -30,8 +30,6 @@ import com.android.internal.util.Preconditions;
public class InputConnectionWrapper implements InputConnection {
private InputConnection mTarget;
final boolean mMutable;
- @InputConnectionInspector.MissingMethodFlags
- private int mMissingMethodFlags;
/**
* Initializes a wrapper.
@@ -46,7 +44,6 @@ public class InputConnectionWrapper implements InputConnection {
public InputConnectionWrapper(InputConnection target, boolean mutable) {
mMutable = mutable;
mTarget = target;
- mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
}
/**
@@ -63,15 +60,6 @@ public class InputConnectionWrapper implements InputConnection {
throw new SecurityException("not mutable");
}
mTarget = target;
- mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
- }
-
- /**
- * @hide
- */
- @InputConnectionInspector.MissingMethodFlags
- public int getMissingMethodFlags() {
- return mMissingMethodFlags;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 139b69c218f5e..009afceebf2c6 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -683,7 +683,6 @@ public final class InputMethodManager {
windowFlags,
null,
null,
- 0 /* missingMethodFlags */,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1938,7 +1937,6 @@ public final class InputMethodManager {
mServedInputConnection = null;
}
RemoteInputConnectionImpl servedInputConnection;
- final int missingMethodFlags;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
mCursorSelEnd = tba.initialSelEnd;
@@ -1946,19 +1944,17 @@ public final class InputMethodManager {
mCursorCandEnd = -1;
mCursorRect.setEmpty();
mCursorAnchorInfo = null;
- missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
- if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
- != 0) {
- // InputConnection#getHandler() is not implemented.
- icHandler = null;
- } else {
- icHandler = ic.getHandler();
+ Handler handler = null;
+ try {
+ handler = ic.getHandler();
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
}
+ icHandler = handler;
servedInputConnection = new RemoteInputConnectionImpl(
icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
} else {
servedInputConnection = null;
- missingMethodFlags = 0;
icHandler = null;
}
mServedInputConnection = servedInputConnection;
@@ -1971,7 +1967,7 @@ public final class InputMethodManager {
try {
res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
- softInputMode, windowFlags, tba, servedInputConnection, missingMethodFlags,
+ softInputMode, windowFlags, tba, servedInputConnection,
view.getContext().getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index 45eef93e86e73..29c1b1b2b604e 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -38,8 +38,6 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionInspector;
-import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethodManager;
@@ -145,10 +143,10 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
if (ic == null) {
return;
}
- @MissingMethodFlags
- final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
- if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+ try {
ic.closeConnection();
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
}
} finally {
synchronized (mLock) {
@@ -260,7 +258,12 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "getSelectedText on inactive InputConnection");
return null;
}
- return ic.getSelectedText(flags);
+ try {
+ return ic.getSelectedText(flags);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ return null;
+ }
}, useImeTracing() ? result -> buildGetSelectedTextProto(flags, result) : null);
}
@@ -335,7 +338,11 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "commitCorrection on inactive InputConnection");
return;
}
- ic.commitCorrection(info);
+ try {
+ ic.commitCorrection(info);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ }
});
}
@@ -383,7 +390,11 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "setComposingRegion on inactive InputConnection");
return;
}
- ic.setComposingRegion(start, end);
+ try {
+ ic.setComposingRegion(start, end);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ }
});
}
@@ -467,7 +478,11 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
return;
}
- ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+ try {
+ ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ }
});
}
@@ -532,7 +547,12 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
// requestCursorUpdates() is not currently supported across displays.
return false;
}
- return ic.requestCursorUpdates(cursorUpdateMode);
+ try {
+ return ic.requestCursorUpdates(cursorUpdateMode);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ return false;
+ }
});
}
@@ -549,7 +569,12 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "commitContent with invalid inputContentInfo=" + inputContentInfo);
return false;
}
- return ic.commitContent(inputContentInfo, flags, opts);
+ try {
+ return ic.commitContent(inputContentInfo, flags, opts);
+ } catch (AbstractMethodError ignored) {
+ // TODO(b/199934664): See if we can remove this by providing a default impl.
+ return false;
+ }
});
}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 5354afbd667b9..139660a29ede4 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -45,7 +45,7 @@ oneway interface IInputMethod {
void unbindInput();
- void startInput(in IBinder startInputToken, in IInputContext inputContext, int missingMethods,
+ void startInput(in IBinder startInputToken, in IInputContext inputContext,
in EditorInfo attribute, boolean restarting);
void createSession(in InputChannel channel, IInputSessionCallback callback);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 4b72355e2593b..350ec33326bd7 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -54,7 +54,6 @@ interface IInputMethodManager {
/* @StartInputFlags */ int startInputFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, in EditorInfo attribute, IInputContext inputContext,
- /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
int unverifiedTargetSdkVersion);
void showInputMethodPickerFromClient(in IInputMethodClient client,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index df612fa3ca1bb..075b74d5bbdca 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -136,8 +136,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionInspector;
-import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto;
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto;
@@ -511,14 +509,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
IInputContext mCurInputContext;
- /**
- * The missing method flags for the input context last provided by the current client.
- *
- * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
- */
- @MissingMethodFlags
- int mCurInputContextMissingMethods;
-
/**
* The attributes last provided by the current client.
*/
@@ -2313,7 +2303,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final SessionState session = mCurClient.curSession;
executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
- MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
+ MSG_START_INPUT, 0 /* unused */, initial ? 0 : 1 /* restarting */,
startInputToken, session, mCurInputContext, mCurAttribute));
if (mShowRequested) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
@@ -2331,8 +2321,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("mMethodMap")
@NonNull
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
- @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
- @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
+ @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
+ @StartInputReason int startInputReason) {
// If no method is currently selected, do nothing.
if (mCurMethodId == null) {
return InputBindResult.NO_IME;
@@ -2389,7 +2379,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurSeq <= 0) mCurSeq = 1;
mCurClient = cs;
mCurInputContext = inputContext;
- mCurInputContextMissingMethods = missingMethods;
mCurAttribute = attribute;
// Check if the input method is changing.
@@ -3274,10 +3263,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
- @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
+ int unverifiedTargetSdkVersion) {
return startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, attribute, inputContext,
- missingMethods, unverifiedTargetSdkVersion);
+ unverifiedTargetSdkVersion);
}
@NonNull
@@ -3285,7 +3274,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext,
- @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
+ int unverifiedTargetSdkVersion) {
if (windowToken == null) {
Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
@@ -3321,8 +3310,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
- attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
- userId);
+ attribute, inputContext, unverifiedTargetSdkVersion, userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3348,15 +3336,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputReason int startInputReason, IInputMethodClient client,
@NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
- IInputContext inputContext, @MissingMethodFlags int missingMethods,
- int unverifiedTargetSdkVersion, @UserIdInt int userId) {
+ IInputContext inputContext, int unverifiedTargetSdkVersion, @UserIdInt int userId) {
if (DEBUG) {
Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
+ InputMethodDebug.startInputReasonToString(startInputReason)
+ " client=" + client.asBinder()
+ " inputContext=" + inputContext
- + " missingMethods="
- + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
+ " attribute=" + attribute
+ " startInputFlags="
+ InputMethodDebug.startInputFlagsToString(startInputFlags)
@@ -3437,8 +3422,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ InputMethodDebug.startInputReasonToString(startInputReason));
}
if (attribute != null) {
- return startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
+ return startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
+ startInputReason);
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
@@ -3478,8 +3463,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// UI for input.
if (isTextEditor && attribute != null
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- startInputFlags, startInputReason);
+ res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
+ startInputReason);
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
return res;
@@ -3517,8 +3502,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// is more room for the target window + IME.
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
+ res = startInputUncheckedLocked(cs, inputContext, attribute,
+ startInputFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3548,8 +3533,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
+ res = startInputUncheckedLocked(cs, inputContext, attribute,
+ startInputFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3567,8 +3552,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
unverifiedTargetSdkVersion, startInputFlags)) {
if (!sameWindowFocused) {
if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
+ res = startInputUncheckedLocked(cs, inputContext, attribute,
+ startInputFlags, startInputReason);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3596,8 +3581,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
}
}
- res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- startInputFlags, startInputReason);
+ res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
+ startInputReason);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -4363,7 +4348,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ---------------------------------------------------------
case MSG_START_INPUT: {
- final int missingMethods = msg.arg1;
final boolean restarting = msg.arg2 != 0;
args = (SomeArgs) msg.obj;
final IBinder startInputToken = (IBinder) args.arg1;
@@ -4372,8 +4356,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final EditorInfo editorInfo = (EditorInfo) args.arg4;
try {
setEnabledSessionInHandlerThread(session);
- session.method.startInput(startInputToken, inputContext, missingMethods,
- editorInfo, restarting);
+ session.method.startInput(startInputToken, inputContext, editorInfo,
+ restarting);
} catch (RemoteException e) {
}
args.recycle();