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 2bcd30a2d52d7eeb529e397bd0adee5237b9e1c0..12b3906a2dc62f7e41fb9fe28dc649619779124c 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 |
@@ -84,7 +84,7 @@ public class ThreadedInputConnection extends BaseInputConnection |
private final Runnable mFinishComposingTextRunnable = new Runnable() { |
@Override |
public void run() { |
- mImeAdapter.finishComposingText(); |
+ finishComposingTextOnUiThread(); |
} |
}; |
@@ -96,6 +96,7 @@ 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; |
ThreadedInputConnection(View view, ImeAdapter imeAdapter, Handler handler) { |
super(view, true); |
@@ -117,12 +118,12 @@ public class ThreadedInputConnection extends BaseInputConnection |
boolean singleLine, final boolean isNonImeChange) { |
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); |
+ if (DEBUG_LOGS) Log.w(TAG, "updateState: %s", mCachedTextInputState); |
- addToQueueOnUiThread(newState); |
+ addToQueueOnUiThread(mCachedTextInputState); |
if (isNonImeChange) { |
mHandler.post(mProcessPendingInputStatesRunnable); |
} |
@@ -206,6 +207,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(); |
} |
@@ -227,6 +234,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,20 +296,24 @@ 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) |
*/ |
@@ -305,11 +321,10 @@ public class ThreadedInputConnection extends BaseInputConnection |
public boolean commitText(final CharSequence text, final int newCursorPosition) { |
if (DEBUG_LOGS) Log.w(TAG, "commitText [%s] [%d]", text, newCursorPosition); |
if (text == null) return false; |
- assertOnImeThread(); |
- cancelCombiningAccent(); |
ThreadUtils.postOnUiThread(new Runnable() { |
@Override |
public void run() { |
+ cancelCombiningAccentOnUiThread(); |
mImeAdapter.sendCompositionToNative(text, newCursorPosition, text.length() > 0, 0); |
} |
}); |
@@ -323,7 +338,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() { |
@@ -339,7 +353,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() { |
@@ -355,7 +368,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(); |
@@ -399,13 +411,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); |
} |
}); |
@@ -426,13 +437,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); |
} |
}); |
@@ -440,7 +448,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(); |
@@ -451,30 +459,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; |
} |
@@ -484,20 +493,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() { |
@@ -513,7 +525,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() { |
@@ -529,7 +540,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); |
@@ -541,7 +551,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); |
@@ -553,7 +562,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(); |
@@ -565,7 +573,6 @@ public class ThreadedInputConnection extends BaseInputConnection |
@Override |
public int getCursorCapsMode(int reqModes) { |
if (DEBUG_LOGS) Log.w(TAG, "getCursorCapsMode [%x]", reqModes); |
- assertOnImeThread(); |
// TODO(changwan): implement this. |
return 0; |
} |
@@ -576,7 +583,6 @@ public class ThreadedInputConnection extends BaseInputConnection |
@Override |
public boolean commitCompletion(CompletionInfo text) { |
if (DEBUG_LOGS) Log.w(TAG, "commitCompletion [%s]", text); |
- assertOnImeThread(); |
return false; |
} |
@@ -589,7 +595,6 @@ public class ThreadedInputConnection extends BaseInputConnection |
Log.w(TAG, "commitCorrection [%s]", |
ImeUtils.getCorrectionInfoDebugString(correctionInfo)); |
} |
- assertOnImeThread(); |
return false; |
} |
@@ -599,7 +604,6 @@ public class ThreadedInputConnection extends BaseInputConnection |
@Override |
public boolean clearMetaKeyStates(int states) { |
if (DEBUG_LOGS) Log.w(TAG, "clearMetaKeyStates [%x]", states); |
- assertOnImeThread(); |
return false; |
} |
@@ -621,7 +625,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; |
} |
@@ -631,7 +634,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() { |
@@ -645,6 +647,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 |
} |
} |