summaryrefslogtreecommitdiff
path: root/com/android/internal/view/InputConnectionWrapper.java
diff options
context:
space:
mode:
Diffstat (limited to 'com/android/internal/view/InputConnectionWrapper.java')
-rw-r--r--com/android/internal/view/InputConnectionWrapper.java95
1 files changed, 87 insertions, 8 deletions
diff --git a/com/android/internal/view/InputConnectionWrapper.java b/com/android/internal/view/InputConnectionWrapper.java
index cc0ef756..5b65bbe1 100644
--- a/com/android/internal/view/InputConnectionWrapper.java
+++ b/com/android/internal/view/InputConnectionWrapper.java
@@ -16,6 +16,8 @@
package com.android.internal.view;
+import android.annotation.AnyThread;
+import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
@@ -34,6 +36,7 @@ import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicBoolean;
public class InputConnectionWrapper implements InputConnection {
private static final int MAX_WAIT_TIME_MILLIS = 2000;
@@ -44,6 +47,14 @@ public class InputConnectionWrapper implements InputConnection {
@MissingMethodFlags
private final int mMissingMethods;
+ /**
+ * {@code true} if the system already decided to take away IME focus from the target app. This
+ * can be signaled even when the corresponding signal is in the task queue and
+ * {@link InputMethodService#onUnbindInput()} is not yet called back on the UI thread.
+ */
+ @NonNull
+ private final AtomicBoolean mIsUnbindIssued;
+
static class InputContextCallback extends IInputContextCallback.Stub {
private static final String TAG = "InputConnectionWrapper.ICC";
public int mSeq;
@@ -67,6 +78,7 @@ public class InputConnectionWrapper implements InputConnection {
* sequence number is set to a new integer. We use a sequence number so that replies that
* occur after a timeout has expired are not interpreted as replies to a later request.
*/
+ @AnyThread
private static InputContextCallback getInstance() {
synchronized (InputContextCallback.class) {
// Return sInstance if it's non-null, otherwise construct a new callback
@@ -90,6 +102,7 @@ public class InputConnectionWrapper implements InputConnection {
/**
* Makes the given InputContextCallback available for use in the future.
*/
+ @AnyThread
private void dispose() {
synchronized (InputContextCallback.class) {
// If sInstance is non-null, just let this object be garbage-collected
@@ -102,7 +115,8 @@ public class InputConnectionWrapper implements InputConnection {
}
}
}
-
+
+ @BinderThread
public void setTextBeforeCursor(CharSequence textBeforeCursor, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -116,6 +130,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setTextAfterCursor(CharSequence textAfterCursor, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -129,6 +144,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setSelectedText(CharSequence selectedText, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -142,6 +158,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setCursorCapsMode(int capsMode, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -155,6 +172,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setExtractedText(ExtractedText extractedText, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -168,6 +186,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -181,6 +200,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @BinderThread
public void setCommitContentResult(boolean result, int seq) {
synchronized (this) {
if (seq == mSeq) {
@@ -199,6 +219,7 @@ public class InputConnectionWrapper implements InputConnection {
*
* <p>The caller must be synchronized on this callback object.
*/
+ @AnyThread
void waitForResultLocked() {
long startTime = SystemClock.uptimeMillis();
long endTime = startTime + MAX_WAIT_TIME_MILLIS;
@@ -219,13 +240,20 @@ public class InputConnectionWrapper implements InputConnection {
public InputConnectionWrapper(
@NonNull WeakReference<AbstractInputMethodService> inputMethodService,
- IInputContext inputContext, @MissingMethodFlags final int missingMethods) {
+ IInputContext inputContext, @MissingMethodFlags final int missingMethods,
+ @NonNull AtomicBoolean isUnbindIssued) {
mInputMethodService = inputMethodService;
mIInputContext = inputContext;
mMissingMethods = missingMethods;
+ mIsUnbindIssued = isUnbindIssued;
}
+ @AnyThread
public CharSequence getTextAfterCursor(int length, int flags) {
+ if (mIsUnbindIssued.get()) {
+ return null;
+ }
+
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -242,8 +270,13 @@ public class InputConnectionWrapper implements InputConnection {
}
return value;
}
-
+
+ @AnyThread
public CharSequence getTextBeforeCursor(int length, int flags) {
+ if (mIsUnbindIssued.get()) {
+ return null;
+ }
+
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -261,7 +294,12 @@ public class InputConnectionWrapper implements InputConnection {
return value;
}
+ @AnyThread
public CharSequence getSelectedText(int flags) {
+ if (mIsUnbindIssued.get()) {
+ return null;
+ }
+
if (isMethodMissing(MissingMethodFlags.GET_SELECTED_TEXT)) {
// This method is not implemented.
return null;
@@ -283,7 +321,12 @@ public class InputConnectionWrapper implements InputConnection {
return value;
}
+ @AnyThread
public int getCursorCapsMode(int reqModes) {
+ if (mIsUnbindIssued.get()) {
+ return 0;
+ }
+
int value = 0;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -301,7 +344,12 @@ public class InputConnectionWrapper implements InputConnection {
return value;
}
+ @AnyThread
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+ if (mIsUnbindIssued.get()) {
+ return null;
+ }
+
ExtractedText value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -318,7 +366,8 @@ public class InputConnectionWrapper implements InputConnection {
}
return value;
}
-
+
+ @AnyThread
public boolean commitText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.commitText(text, newCursorPosition);
@@ -328,6 +377,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean commitCompletion(CompletionInfo text) {
if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
// This method is not implemented.
@@ -341,6 +391,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean commitCorrection(CorrectionInfo correctionInfo) {
try {
mIInputContext.commitCorrection(correctionInfo);
@@ -350,6 +401,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean setSelection(int start, int end) {
try {
mIInputContext.setSelection(start, end);
@@ -358,7 +410,8 @@ public class InputConnectionWrapper implements InputConnection {
return false;
}
}
-
+
+ @AnyThread
public boolean performEditorAction(int actionCode) {
try {
mIInputContext.performEditorAction(actionCode);
@@ -367,7 +420,8 @@ public class InputConnectionWrapper implements InputConnection {
return false;
}
}
-
+
+ @AnyThread
public boolean performContextMenuAction(int id) {
try {
mIInputContext.performContextMenuAction(id);
@@ -377,6 +431,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean setComposingRegion(int start, int end) {
if (isMethodMissing(MissingMethodFlags.SET_COMPOSING_REGION)) {
// This method is not implemented.
@@ -390,6 +445,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean setComposingText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.setComposingText(text, newCursorPosition);
@@ -399,6 +455,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean finishComposingText() {
try {
mIInputContext.finishComposingText();
@@ -408,6 +465,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean beginBatchEdit() {
try {
mIInputContext.beginBatchEdit();
@@ -416,7 +474,8 @@ public class InputConnectionWrapper implements InputConnection {
return false;
}
}
-
+
+ @AnyThread
public boolean endBatchEdit() {
try {
mIInputContext.endBatchEdit();
@@ -425,7 +484,8 @@ public class InputConnectionWrapper implements InputConnection {
return false;
}
}
-
+
+ @AnyThread
public boolean sendKeyEvent(KeyEvent event) {
try {
mIInputContext.sendKeyEvent(event);
@@ -435,6 +495,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean clearMetaKeyStates(int states) {
try {
mIInputContext.clearMetaKeyStates(states);
@@ -444,6 +505,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
try {
mIInputContext.deleteSurroundingText(beforeLength, afterLength);
@@ -453,6 +515,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
if (isMethodMissing(MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS)) {
// This method is not implemented.
@@ -466,11 +529,13 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean reportFullscreenMode(boolean enabled) {
// Nothing should happen when called from input method.
return false;
}
+ @AnyThread
public boolean performPrivateCommand(String action, Bundle data) {
try {
mIInputContext.performPrivateCommand(action, data);
@@ -480,7 +545,12 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ @AnyThread
public boolean requestCursorUpdates(int cursorUpdateMode) {
+ if (mIsUnbindIssued.get()) {
+ return false;
+ }
+
boolean result = false;
if (isMethodMissing(MissingMethodFlags.REQUEST_CURSOR_UPDATES)) {
// This method is not implemented.
@@ -502,16 +572,23 @@ public class InputConnectionWrapper implements InputConnection {
return result;
}
+ @AnyThread
public Handler getHandler() {
// Nothing should happen when called from input method.
return null;
}
+ @AnyThread
public void closeConnection() {
// Nothing should happen when called from input method.
}
+ @AnyThread
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ if (mIsUnbindIssued.get()) {
+ return false;
+ }
+
boolean result = false;
if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
// This method is not implemented.
@@ -542,10 +619,12 @@ public class InputConnectionWrapper implements InputConnection {
return result;
}
+ @AnyThread
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
}
+ @AnyThread
@Override
public String toString() {
return "InputConnectionWrapper{idHash=#"