summaryrefslogtreecommitdiff
path: root/android/inputmethodservice/IInputMethodWrapper.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/inputmethodservice/IInputMethodWrapper.java')
-rw-r--r--android/inputmethodservice/IInputMethodWrapper.java93
1 files changed, 66 insertions, 27 deletions
diff --git a/android/inputmethodservice/IInputMethodWrapper.java b/android/inputmethodservice/IInputMethodWrapper.java
index 765aff96..2c7e51a1 100644
--- a/android/inputmethodservice/IInputMethodWrapper.java
+++ b/android/inputmethodservice/IInputMethodWrapper.java
@@ -16,14 +16,8 @@
package android.inputmethodservice;
-import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputMethodSession;
-import com.android.internal.view.IInputSessionCallback;
-import com.android.internal.view.InputConnectionWrapper;
-
+import android.annotation.BinderThread;
+import android.annotation.MainThread;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -41,11 +35,20 @@ import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethod;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
+import com.android.internal.view.InputConnectionWrapper;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Implements the internal IInputMethod interface to convert incoming calls
@@ -67,17 +70,27 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final int DO_SHOW_SOFT_INPUT = 60;
private static final int DO_HIDE_SOFT_INPUT = 70;
private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
-
+
final WeakReference<AbstractInputMethodService> mTarget;
final Context mContext;
final HandlerCaller mCaller;
final WeakReference<InputMethod> mInputMethod;
final int mTargetSdkVersion;
-
- static class Notifier {
- boolean notified;
- }
-
+
+ /**
+ * This is not {@null} only between {@link #bindInput(InputBinding)} and {@link #unbindInput()}
+ * so that {@link InputConnectionWrapper} can query if {@link #unbindInput()} has already been
+ * called or not, mainly to avoid unnecessary blocking operations.
+ *
+ * <p>This field must be set and cleared only from the binder thread(s), where the system
+ * guarantees that {@link #bindInput(InputBinding)},
+ * {@link #startInput(IBinder, IInputContext, int, EditorInfo, boolean)}, and
+ * {@link #unbindInput()} are called with the same order as the original calls
+ * in {@link com.android.server.InputMethodManagerService}. See {@link IBinder#FLAG_ONEWAY}
+ * for detailed semantics.</p>
+ */
+ AtomicBoolean mIsUnbindIssued = null;
+
// NOTE: we should have a cache of these.
static final class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
final Context mContext;
@@ -108,20 +121,16 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
}
-
- public IInputMethodWrapper(AbstractInputMethodService context,
- InputMethod inputMethod) {
- mTarget = new WeakReference<AbstractInputMethodService>(context);
+
+ public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) {
+ mTarget = new WeakReference<>(context);
mContext = context.getApplicationContext();
mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/);
- mInputMethod = new WeakReference<InputMethod>(inputMethod);
+ mInputMethod = new WeakReference<>(inputMethod);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
}
- public InputMethod getInternalInputMethod() {
- return mInputMethod.get();
- }
-
+ @MainThread
@Override
public void executeMessage(Message msg) {
InputMethod inputMethod = mInputMethod.get();
@@ -169,8 +178,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
final IBinder startInputToken = (IBinder) args.arg1;
final IInputContext inputContext = (IInputContext) args.arg2;
final EditorInfo info = (EditorInfo) args.arg3;
+ final AtomicBoolean isUnbindIssued = (AtomicBoolean) args.arg4;
final InputConnection ic = inputContext != null
- ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
+ ? new InputConnectionWrapper(
+ mTarget, inputContext, missingMethods, isUnbindIssued) : null;
info.makeCompatible(mTargetSdkVersion);
inputMethod.dispatchStartInputWithToken(ic, info, restarting /* restarting */,
startInputToken);
@@ -205,6 +216,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
Log.w(TAG, "Unhandled message code: " + msg.what);
}
+ @BinderThread
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
AbstractInputMethodService target = mTarget.get();
@@ -232,40 +244,63 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
+ @BinderThread
@Override
public void attachToken(IBinder token) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
}
+ @BinderThread
@Override
public void bindInput(InputBinding binding) {
+ if (mIsUnbindIssued != null) {
+ Log.e(TAG, "bindInput must be paired with unbindInput.");
+ }
+ mIsUnbindIssued = new AtomicBoolean();
// This IInputContext is guaranteed to implement all the methods.
final int missingMethodFlags = 0;
InputConnection ic = new InputConnectionWrapper(mTarget,
- IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags);
+ IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags,
+ mIsUnbindIssued);
InputBinding nu = new InputBinding(ic, binding);
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
}
+ @BinderThread
@Override
public void unbindInput() {
+ if (mIsUnbindIssued != null) {
+ // Signal the flag then forget it.
+ mIsUnbindIssued.set(true);
+ mIsUnbindIssued = null;
+ } else {
+ Log.e(TAG, "unbindInput must be paired with bindInput.");
+ }
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
}
+ @BinderThread
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
@InputConnectionInspector.MissingMethodFlags final int missingMethods,
EditorInfo attribute, boolean restarting) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOO(DO_START_INPUT,
- missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute));
+ if (mIsUnbindIssued == null) {
+ Log.e(TAG, "startInput must be called after bindInput.");
+ mIsUnbindIssued = new AtomicBoolean();
+ }
+ mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOOO(DO_START_INPUT,
+ missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute,
+ mIsUnbindIssued));
}
+ @BinderThread
@Override
public void createSession(InputChannel channel, IInputSessionCallback callback) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_SESSION,
channel, callback));
}
+ @BinderThread
@Override
public void setSessionEnabled(IInputMethodSession session, boolean enabled) {
try {
@@ -282,6 +317,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
+ @BinderThread
@Override
public void revokeSession(IInputMethodSession session) {
try {
@@ -297,18 +333,21 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
+ @BinderThread
@Override
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
flags, resultReceiver));
}
+ @BinderThread
@Override
public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
flags, resultReceiver));
}
+ @BinderThread
@Override
public void changeInputMethodSubtype(InputMethodSubtype subtype) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,