Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1840)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java

Issue 2355483006: Allow some InputConnection methods to be called on UI thread (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
index 563dd0e1844000eec0d31dc084cdf07f0af22c68..5e54699a3a15df6fd1ea78913c73b5f68fff0225 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
@@ -42,7 +42,7 @@ public class ThreadedInputConnection extends BaseInputConnection
private static final boolean DEBUG_LOGS = false;
private static final TextInputState UNBLOCKER = new TextInputState(
- "", new Range(0, 0), new Range(-1, -1), false, false /* notFromIme */) {
+ "", new Range(0, 0), new Range(-1, -1), false, false /* notFromIme */, false) {
@Override
public boolean shouldUnblock() {
@@ -75,6 +75,22 @@ public class ThreadedInputConnection extends BaseInputConnection
}
};
+ private final Runnable mBeginBatchEdit = new Runnable() {
+ @Override
+ public void run() {
+ boolean result = mImeAdapter.beginBatchEdit();
+ if (!result) unblockOnUiThread();
+ }
+ };
+
+ private final Runnable mEndBatchEdit = new Runnable() {
+ @Override
+ public void run() {
+ boolean result = mImeAdapter.endBatchEdit();
+ if (!result) unblockOnUiThread();
+ }
+ };
+
private final Runnable mNotifyUserActionRunnable = new Runnable() {
@Override
public void run() {
@@ -85,7 +101,7 @@ public class ThreadedInputConnection extends BaseInputConnection
private final Runnable mFinishComposingTextRunnable = new Runnable() {
@Override
public void run() {
- mImeAdapter.finishComposingText();
+ finishComposingTextOnUiThread();
}
};
@@ -97,6 +113,8 @@ public class ThreadedInputConnection extends BaseInputConnection
// a bunch of new objects for each key stroke.
private final BlockingQueue<TextInputState> mQueue = new LinkedBlockingQueue<>();
private int mPendingAccent;
+ private TextInputState mCachedTextInputState;
+ private boolean mLastInBatchEditMode;
ThreadedInputConnection(View view, ImeAdapter imeAdapter, Handler handler) {
super(view, true);
@@ -104,28 +122,34 @@ public class ThreadedInputConnection extends BaseInputConnection
ImeUtils.checkOnUiThread();
mImeAdapter = imeAdapter;
mHandler = handler;
+ mImeAdapter.endBatchEdit();
}
void resetOnUiThread() {
ImeUtils.checkOnUiThread();
mNumNestedBatchEdits = 0;
mPendingAccent = 0;
+ mImeAdapter.endBatchEdit();
}
@Override
- public void updateStateOnUiThread(final String text, final int selectionStart,
- final int selectionEnd, final int compositionStart, final int compositionEnd,
- boolean singleLine, final boolean isNonImeChange) {
+ public void updateStateOnUiThread(String text, int selectionStart,
+ int selectionEnd, int compositionStart, int compositionEnd,
+ boolean singleLine, boolean isNonImeChange, boolean inBatchEditMode) {
ImeUtils.checkOnUiThread();
- final TextInputState newState =
+ mCachedTextInputState =
new TextInputState(text, new Range(selectionStart, selectionEnd),
- new Range(compositionStart, compositionEnd), singleLine, !isNonImeChange);
- if (DEBUG_LOGS) Log.w(TAG, "updateState: %s", newState);
-
- addToQueueOnUiThread(newState);
- if (isNonImeChange) {
+ new Range(compositionStart, compositionEnd), singleLine, !isNonImeChange,
+ inBatchEditMode);
+ if (DEBUG_LOGS) Log.w(TAG, "updateState: %s", mCachedTextInputState);
+
+ addToQueueOnUiThread(mCachedTextInputState);
+ // If state update is caused by explicitly requesting the state update,
+ // or batch edit just finished, then we may need to update state to IMM.
+ if (isNonImeChange || (mLastInBatchEditMode && !inBatchEditMode)) {
mHandler.post(mProcessPendingInputStatesRunnable);
+ mLastInBatchEditMode = inBatchEditMode;
}
}
@@ -198,7 +222,7 @@ public class ThreadedInputConnection extends BaseInputConnection
private void updateSelection(TextInputState textInputState) {
if (textInputState == null) return;
assertOnImeThread();
- if (mNumNestedBatchEdits != 0) return;
+ if (textInputState.inBatchEditMode()) return;
Range selection = textInputState.selection();
Range composition = textInputState.composition();
mImeAdapter.updateSelection(
@@ -207,6 +231,12 @@ public class ThreadedInputConnection extends BaseInputConnection
private TextInputState requestAndWaitForTextInputState() {
if (DEBUG_LOGS) Log.w(TAG, "requestAndWaitForTextInputState");
+ if (runningOnUiThread()) {
+ Log.w(TAG, "InputConnection API is not called on IME thread. Returning cached result.");
+ // Returning cached result is a workaround for existing webview apps. (crbug.com/643477)
+ return mCachedTextInputState;
+ }
+ assertOnImeThread();
ThreadUtils.postOnUiThread(mRequestTextInputStateUpdate);
return blockAndGetStateUpdate();
}
@@ -228,6 +258,11 @@ public class ThreadedInputConnection extends BaseInputConnection
return mQueue;
}
+ @VisibleForTesting
+ protected boolean runningOnUiThread() {
+ return ThreadUtils.runningOnUiThread();
+ }
+
private void assertOnImeThread() {
ImeUtils.checkCondition(mHandler.getLooper() == Looper.myLooper());
}
@@ -284,31 +319,35 @@ public class ThreadedInputConnection extends BaseInputConnection
@VisibleForTesting
public boolean updateComposingText(
final CharSequence text, final int newCursorPosition, final boolean isPendingAccent) {
- final int accentToSend =
- isPendingAccent ? (mPendingAccent | KeyCharacterMap.COMBINING_ACCENT) : 0;
- assertOnImeThread();
- cancelCombiningAccent();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
- mImeAdapter.sendCompositionToNative(text, newCursorPosition, false, accentToSend);
+ updateComposingTextOnUiThread(text, newCursorPosition, isPendingAccent);
}
});
notifyUserAction();
return true;
}
+ private void updateComposingTextOnUiThread(
+ CharSequence text, int newCursorPosition, boolean isPendingAccent) {
+ int accentToSend =
+ isPendingAccent ? (mPendingAccent | KeyCharacterMap.COMBINING_ACCENT) : 0;
+ cancelCombiningAccentOnUiThread();
+ mImeAdapter.sendCompositionToNative(text, newCursorPosition, false, accentToSend);
+ }
+
/**
* @see InputConnection#commitText(java.lang.CharSequence, int)
*/
@Override
public boolean commitText(final CharSequence text, final int newCursorPosition) {
if (DEBUG_LOGS) Log.w(TAG, "commitText [%s] [%d]", text, newCursorPosition);
- assertOnImeThread();
- cancelCombiningAccent();
+ if (text == null) return false;
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
+ cancelCombiningAccentOnUiThread();
mImeAdapter.sendCompositionToNative(text, newCursorPosition, text.length() > 0, 0);
}
});
@@ -322,7 +361,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean performEditorAction(final int actionCode) {
if (DEBUG_LOGS) Log.w(TAG, "performEditorAction [%d]", actionCode);
- assertOnImeThread();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -338,7 +376,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean performContextMenuAction(final int id) {
if (DEBUG_LOGS) Log.w(TAG, "performContextMenuAction [%d]", id);
- assertOnImeThread();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -354,7 +391,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (DEBUG_LOGS) Log.w(TAG, "getExtractedText");
- assertOnImeThread();
TextInputState textInputState = requestAndWaitForTextInputState();
if (textInputState == null) return null;
ExtractedText extractedText = new ExtractedText();
@@ -372,8 +408,10 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean beginBatchEdit() {
if (DEBUG_LOGS) Log.w(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0));
- assertOnImeThread();
mNumNestedBatchEdits++;
+ if (mNumNestedBatchEdits == 1) {
+ ThreadUtils.postOnUiThread(mBeginBatchEdit);
+ }
return true;
}
@@ -382,12 +420,11 @@ public class ThreadedInputConnection extends BaseInputConnection
*/
@Override
public boolean endBatchEdit() {
- assertOnImeThread();
if (mNumNestedBatchEdits == 0) return false;
--mNumNestedBatchEdits;
if (DEBUG_LOGS) Log.w(TAG, "endBatchEdit [%b]", (mNumNestedBatchEdits == 0));
if (mNumNestedBatchEdits == 0) {
- updateSelection(requestAndWaitForTextInputState());
+ ThreadUtils.postOnUiThread(mEndBatchEdit);
}
return mNumNestedBatchEdits != 0;
}
@@ -398,13 +435,12 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
if (DEBUG_LOGS) Log.w(TAG, "deleteSurroundingText [%d %d]", beforeLength, afterLength);
- assertOnImeThread();
- if (mPendingAccent != 0) {
- finishComposingText();
- }
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
+ if (mPendingAccent != 0) {
+ finishComposingTextOnUiThread();
+ }
mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
}
});
@@ -425,13 +461,10 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean sendKeyEvent(final KeyEvent event) {
if (DEBUG_LOGS) Log.w(TAG, "sendKeyEvent [%d %d]", event.getAction(), event.getKeyCode());
- assertOnImeThread();
-
- if (handleCombiningAccent(event)) return true;
-
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
+ if (handleCombiningAccentOnUiThread(event)) return;
mImeAdapter.sendKeyEvent(event);
}
});
@@ -439,7 +472,7 @@ public class ThreadedInputConnection extends BaseInputConnection
return true;
}
- private boolean handleCombiningAccent(final KeyEvent event) {
+ private boolean handleCombiningAccentOnUiThread(final KeyEvent event) {
// TODO(changwan): this will break the current composition. check if we can
// implement it in the renderer instead.
int action = event.getAction();
@@ -450,30 +483,31 @@ public class ThreadedInputConnection extends BaseInputConnection
int pendingAccent = unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK;
StringBuilder builder = new StringBuilder();
builder.appendCodePoint(pendingAccent);
- updateComposingText(builder.toString(), 1, true);
- setCombiningAccent(pendingAccent);
+ updateComposingTextOnUiThread(builder.toString(), 1, true);
+ setCombiningAccentOnUiThread(pendingAccent);
return true;
} else if (mPendingAccent != 0 && unicodeChar != 0) {
int combined = KeyEvent.getDeadChar(mPendingAccent, unicodeChar);
if (combined != 0) {
StringBuilder builder = new StringBuilder();
builder.appendCodePoint(combined);
- commitText(builder.toString(), 1);
+ String text = builder.toString();
+ mImeAdapter.sendCompositionToNative(text, 1, text.length() > 0, 0);
return true;
}
// Noncombinable character; commit the accent character and fall through to sending
// the key event for the character afterwards.
- finishComposingText();
+ finishComposingTextOnUiThread();
}
return false;
}
@VisibleForTesting
- public void setCombiningAccent(int pendingAccent) {
+ public void setCombiningAccentOnUiThread(int pendingAccent) {
mPendingAccent = pendingAccent;
}
- private void cancelCombiningAccent() {
+ private void cancelCombiningAccentOnUiThread() {
mPendingAccent = 0;
}
@@ -483,20 +517,23 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean finishComposingText() {
if (DEBUG_LOGS) Log.w(TAG, "finishComposingText");
- cancelCombiningAccent();
// This is the only function that may be called on UI thread because
// of direct calls from InputMethodManager.
ThreadUtils.postOnUiThread(mFinishComposingTextRunnable);
return true;
}
+ private void finishComposingTextOnUiThread() {
+ cancelCombiningAccentOnUiThread();
+ mImeAdapter.finishComposingText();
+ }
+
/**
* @see InputConnection#setSelection(int, int)
*/
@Override
public boolean setSelection(final int start, final int end) {
if (DEBUG_LOGS) Log.w(TAG, "setSelection [%d %d]", start, end);
- assertOnImeThread();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -512,7 +549,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean setComposingRegion(final int start, final int end) {
if (DEBUG_LOGS) Log.w(TAG, "setComposingRegion [%d %d]", start, end);
- assertOnImeThread();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -528,7 +564,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public CharSequence getTextBeforeCursor(int maxChars, int flags) {
if (DEBUG_LOGS) Log.w(TAG, "getTextBeforeCursor [%d %x]", maxChars, flags);
- assertOnImeThread();
TextInputState textInputState = requestAndWaitForTextInputState();
if (textInputState == null) return null;
return textInputState.getTextBeforeSelection(maxChars);
@@ -540,7 +575,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public CharSequence getTextAfterCursor(int maxChars, int flags) {
if (DEBUG_LOGS) Log.w(TAG, "getTextAfterCursor [%d %x]", maxChars, flags);
- assertOnImeThread();
TextInputState textInputState = requestAndWaitForTextInputState();
if (textInputState == null) return null;
return textInputState.getTextAfterSelection(maxChars);
@@ -552,7 +586,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public CharSequence getSelectedText(int flags) {
if (DEBUG_LOGS) Log.w(TAG, "getSelectedText [%x]", flags);
- assertOnImeThread();
TextInputState textInputState = requestAndWaitForTextInputState();
if (textInputState == null) return null;
return textInputState.getSelectedText();
@@ -579,7 +612,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG_LOGS) Log.w(TAG, "commitCompletion [%s]", text);
- assertOnImeThread();
return false;
}
@@ -592,7 +624,6 @@ public class ThreadedInputConnection extends BaseInputConnection
Log.w(TAG, "commitCorrection [%s]",
ImeUtils.getCorrectionInfoDebugString(correctionInfo));
}
- assertOnImeThread();
return false;
}
@@ -602,7 +633,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean clearMetaKeyStates(int states) {
if (DEBUG_LOGS) Log.w(TAG, "clearMetaKeyStates [%x]", states);
- assertOnImeThread();
return false;
}
@@ -624,7 +654,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean performPrivateCommand(String action, Bundle data) {
if (DEBUG_LOGS) Log.w(TAG, "performPrivateCommand [%s]", action);
- assertOnImeThread();
return false;
}
@@ -634,7 +663,6 @@ public class ThreadedInputConnection extends BaseInputConnection
@Override
public boolean requestCursorUpdates(final int cursorUpdateMode) {
if (DEBUG_LOGS) Log.w(TAG, "requestCursorUpdates [%x]", cursorUpdateMode);
- assertOnImeThread();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -648,6 +676,7 @@ public class ThreadedInputConnection extends BaseInputConnection
* @see InputConnection#closeConnection()
*/
public void closeConnection() {
+ if (DEBUG_LOGS) Log.w(TAG, "closeConnection");
// TODO(changwan): Implement this. http://crbug.com/595525
}
}

Powered by Google App Engine
This is Rietveld 408576698