diff options
Diffstat (limited to 'com/android/internal/view/InputConnectionWrapper.java')
-rw-r--r-- | com/android/internal/view/InputConnectionWrapper.java | 95 |
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=#" |