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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: adding missing ImeTestUtils.java Created 4 years, 10 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 unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser.input; 5 package org.chromium.content.browser.input;
6 6
7 import android.content.res.Configuration; 7 import android.content.res.Configuration;
8 import android.os.ResultReceiver; 8 import android.os.ResultReceiver;
9 import android.os.SystemClock; 9 import android.os.SystemClock;
10 import android.text.Editable;
11 import android.text.Selection;
12 import android.text.SpannableString; 10 import android.text.SpannableString;
13 import android.text.TextUtils; 11 import android.text.TextUtils;
14 import android.text.style.BackgroundColorSpan; 12 import android.text.style.BackgroundColorSpan;
15 import android.text.style.CharacterStyle; 13 import android.text.style.CharacterStyle;
16 import android.text.style.UnderlineSpan; 14 import android.text.style.UnderlineSpan;
17 import android.view.KeyCharacterMap; 15 import android.view.KeyCharacterMap;
18 import android.view.KeyEvent; 16 import android.view.KeyEvent;
19 import android.view.View; 17 import android.view.View;
20 import android.view.inputmethod.BaseInputConnection; 18 import android.view.inputmethod.BaseInputConnection;
21 import android.view.inputmethod.EditorInfo; 19 import android.view.inputmethod.EditorInfo;
22 20
21 import org.chromium.base.CommandLine;
23 import org.chromium.base.Log; 22 import org.chromium.base.Log;
24 import org.chromium.base.VisibleForTesting; 23 import org.chromium.base.VisibleForTesting;
25 import org.chromium.base.annotations.CalledByNative; 24 import org.chromium.base.annotations.CalledByNative;
26 import org.chromium.base.annotations.JNINamespace; 25 import org.chromium.base.annotations.JNINamespace;
27 import org.chromium.blink_public.web.WebInputEventModifier; 26 import org.chromium.blink_public.web.WebInputEventModifier;
28 import org.chromium.blink_public.web.WebInputEventType; 27 import org.chromium.blink_public.web.WebInputEventType;
28 import org.chromium.content.common.ContentSwitches;
29 import org.chromium.ui.base.ime.TextInputType; 29 import org.chromium.ui.base.ime.TextInputType;
30 import org.chromium.ui.picker.InputDialogContainer; 30 import org.chromium.ui.picker.InputDialogContainer;
31 31
32 /** 32 /**
33 * Adapts and plumbs android IME service onto the chrome text input API. 33 * Adapts and plumbs android IME service onto the chrome text input API.
34 * ImeAdapter provides an interface in both ways native <-> java: 34 * ImeAdapter provides an interface in both ways native <-> java:
35 * 1. InputConnectionAdapter notifies native code of text composition state and 35 * 1. InputConnectionAdapter notifies native code of text composition state and
36 * dispatch key events from java -> WebKit. 36 * dispatch key events from java -> WebKit.
37 * 2. Native ImeAdapter notifies java side to clear composition text. 37 * 2. Native ImeAdapter notifies java side to clear composition text.
38 * 38 *
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 * @return Object that should be called for all keyboard show and hide r equests. 85 * @return Object that should be called for all keyboard show and hide r equests.
86 */ 86 */
87 ResultReceiver getNewShowKeyboardReceiver(); 87 ResultReceiver getNewShowKeyboardReceiver();
88 } 88 }
89 89
90 static char[] sSingleCharArray = new char[1]; 90 static char[] sSingleCharArray = new char[1];
91 static KeyCharacterMap sKeyCharacterMap; 91 static KeyCharacterMap sKeyCharacterMap;
92 92
93 private long mNativeImeAdapterAndroid; 93 private long mNativeImeAdapterAndroid;
94 private InputMethodManagerWrapper mInputMethodManagerWrapper; 94 private InputMethodManagerWrapper mInputMethodManagerWrapper;
95 private AdapterInputConnection mInputConnection; 95 private ChromiumBaseInputConnection mInputConnection;
96 private AdapterInputConnectionFactory mInputConnectionFactory; 96 private ChromiumBaseInputConnection.Factory mInputConnectionFactory;
97
97 private final ImeAdapterDelegate mViewEmbedder; 98 private final ImeAdapterDelegate mViewEmbedder;
98 99
99 // This holds the state of editable text (e.g. contents of <input>, contente ditable) of
100 // a focused element.
101 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
102 // state must be reflected to this to keep consistency.
103 private final Editable mEditable;
104
105 private int mTextInputType = TextInputType.NONE; 100 private int mTextInputType = TextInputType.NONE;
106 private int mTextInputFlags; 101 private int mTextInputFlags;
107 102
108 // Keep the current configuration to detect the change when onConfigurationC hanged() is called. 103 // Keep the current configuration to detect the change when onConfigurationC hanged() is called.
109 private Configuration mCurrentConfig; 104 private Configuration mCurrentConfig;
110 105
111 /** 106 /**
112 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to 107 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to
113 * InputMethodManager. 108 * InputMethodManager.
114 * @param embedder The view that is used for callbacks from ImeAdapter. 109 * @param embedder The view that is used for callbacks from ImeAdapter.
115 */ 110 */
116 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { 111 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) {
117 mInputMethodManagerWrapper = wrapper; 112 mInputMethodManagerWrapper = wrapper;
118 mViewEmbedder = embedder; 113 mViewEmbedder = embedder;
119 mInputConnectionFactory = new AdapterInputConnectionFactory(); 114 if (CommandLine.getInstance().hasSwitch(ContentSwitches.USE_IME_THREAD)) {
120 mEditable = Editable.Factory.getInstance().newEditable(""); 115 mInputConnectionFactory =
121 Selection.setSelection(mEditable, 0); 116 new ThreadedInputConnectionFactory(mInputMethodManagerWrappe r);
117 } else {
118 mInputConnectionFactory = new ReplicaInputConnection.Factory();
119 }
122 // Deep copy newConfig so that we can notice the difference. 120 // Deep copy newConfig so that we can notice the difference.
123 mCurrentConfig = new Configuration( 121 mCurrentConfig = new Configuration(
124 mViewEmbedder.getAttachedView().getResources().getConfiguration( )); 122 mViewEmbedder.getAttachedView().getResources().getConfiguration( ));
125 } 123 }
126 124
127 /** 125 /**
128 * Default factory for AdapterInputConnection classes.
129 */
130 static class AdapterInputConnectionFactory {
131 AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initial SelStart,
132 int initialSelEnd, EditorInfo outAttrs) {
133 return new AdapterInputConnection(
134 view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
135 }
136 }
137
138 /**
139 * @see View#onCreateInputConnection(EditorInfo) 126 * @see View#onCreateInputConnection(EditorInfo)
140 */ 127 */
141 public AdapterInputConnection onCreateInputConnection(EditorInfo outAttrs) { 128 public ChromiumBaseInputConnection onCreateInputConnection(EditorInfo outAtt rs) {
129 // InputMethodService evaluates fullscreen mode even when the new input connection is
130 // null. This makes sure IME doesn't enter fullscreen mode or open custo m UI.
131 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME _FLAG_NO_EXTRACT_UI;
142 // Without this line, some third-party IMEs will try to compose text eve n when 132 // Without this line, some third-party IMEs will try to compose text eve n when
143 // not on an editable node. Even when we return null here, key events ca n still go through 133 // not on an editable node. Even when we return null here, key events ca n still go
144 // ImeAdapter#dispatchKeyEvent(). 134 // through ImeAdapter#dispatchKeyEvent().
145 if (mTextInputType == TextInputType.NONE) { 135 if (mTextInputType == TextInputType.NONE) {
136 if (mInputConnection != null) mInputConnection.unblockOnUiThread();
146 mInputConnection = null; 137 mInputConnection = null;
147 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection returns null."); 138 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection returns null.");
148 // InputMethodService evaluates fullscreen mode even when the new in put connection is
149 // null. This makes sure IME doesn't enter fullscreen mode or open c ustom UI.
150 outAttrs.imeOptions =
151 EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_E XTRACT_UI;
152 return null; 139 return null;
153 } 140 }
154 141 mInputConnection = mInputConnectionFactory.initializeAndGet(
155 if (!isTextInputType(mTextInputType)) { 142 mViewEmbedder.getAttachedView(), this, mTextInputType, mTextInpu tFlags, outAttrs);
156 // Although onCheckIsTextEditor will return false in this case, the EditorInfo 143 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection: " + mInputConnectio n);
157 // is still used by the InputMethodService. Need to make sure the IM E doesn't
158 // enter fullscreen mode.
159 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
160 }
161 int initialSelStart = Selection.getSelectionStart(mEditable);
162 int initialSelEnd = outAttrs.initialSelEnd = Selection.getSelectionEnd(m Editable);
163 mInputConnection = mInputConnectionFactory.get(
164 mViewEmbedder.getAttachedView(), this, initialSelStart, initialS elEnd, outAttrs);
165 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection");
166 return mInputConnection; 144 return mInputConnection;
167 } 145 }
168 146
169 /** 147 /**
170 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to 148 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to
171 * InputMethodManager. 149 * InputMethodManager.
172 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager. 150 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager.
173 */ 151 */
174 @VisibleForTesting 152 @VisibleForTesting
175 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper im mw) { 153 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper im mw) {
176 mInputMethodManagerWrapper = immw; 154 mInputMethodManagerWrapper = immw;
177 } 155 }
178 156
179 @VisibleForTesting 157 @VisibleForTesting
180 void setInputConnectionFactory(AdapterInputConnectionFactory factory) { 158 void setInputConnectionFactory(ChromiumBaseInputConnection.Factory factory) {
181 mInputConnectionFactory = factory; 159 mInputConnectionFactory = factory;
182 } 160 }
183 161
184 /** 162 @VisibleForTesting
185 * Set the current active InputConnection when a new InputConnection is cons tructed. 163 ChromiumBaseInputConnection.Factory getInputConnectionFactoryForTest() {
186 * @param inputConnection The input connection that is currently used with I ME. 164 return mInputConnectionFactory;
187 */
188 void setInputConnection(AdapterInputConnection inputConnection) {
189 mInputConnection = inputConnection;
190 } 165 }
191 166
192 /** 167 /**
193 * Get the current input connection for testing purposes. 168 * Get the current input connection for testing purposes.
194 */ 169 */
195 @VisibleForTesting 170 @VisibleForTesting
196 public AdapterInputConnection getInputConnectionForTest() { 171 public ChromiumBaseInputConnection getInputConnectionForTest() {
197 return mInputConnection; 172 return mInputConnection;
198 } 173 }
199 174
200 /**
201 * @return The Editable instance that will be shared across AdapterInputConn ection instances.
202 */
203 Editable getEditable() {
204 return mEditable;
205 }
206
207 /**
208 * Should be used only by AdapterInputConnection.
209 * @return The input type of currently focused element.
210 */
211 int getTextInputType() {
212 return mTextInputType;
213 }
214
215 /**
216 * Should be used only by AdapterInputConnection.
217 * @return The input flags of the currently focused element.
218 */
219 int getTextInputFlags() {
220 return mTextInputFlags;
221 }
222
223 private static int getModifiers(int metaState) { 175 private static int getModifiers(int metaState) {
224 int modifiers = 0; 176 int modifiers = 0;
225 if ((metaState & KeyEvent.META_SHIFT_ON) != 0) { 177 if ((metaState & KeyEvent.META_SHIFT_ON) != 0) {
226 modifiers |= WebInputEventModifier.ShiftKey; 178 modifiers |= WebInputEventModifier.ShiftKey;
227 } 179 }
228 if ((metaState & KeyEvent.META_ALT_ON) != 0) { 180 if ((metaState & KeyEvent.META_ALT_ON) != 0) {
229 modifiers |= WebInputEventModifier.AltKey; 181 modifiers |= WebInputEventModifier.AltKey;
230 } 182 }
231 if ((metaState & KeyEvent.META_CTRL_ON) != 0) { 183 if ((metaState & KeyEvent.META_CTRL_ON) != 0) {
232 modifiers |= WebInputEventModifier.ControlKey; 184 modifiers |= WebInputEventModifier.ControlKey;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 * is no selection. 231 * is no selection.
280 * @param compositionStart The character offset of the composition start, or -1 if there is no 232 * @param compositionStart The character offset of the composition start, or -1 if there is no
281 * composition. 233 * composition.
282 * @param compositionEnd The character offset of the composition end, or -1 if there is no 234 * @param compositionEnd The character offset of the composition end, or -1 if there is no
283 * selection. 235 * selection.
284 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript). 236 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript).
285 */ 237 */
286 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart, 238 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart,
287 int compositionEnd, boolean isNonImeChange) { 239 int compositionEnd, boolean isNonImeChange) {
288 if (mInputConnection == null) return; 240 if (mInputConnection == null) return;
289 mInputConnection.updateState(text, selectionStart, selectionEnd, composi tionStart, 241 boolean singleLine = mTextInputType != TextInputType.TEXT_AREA
290 compositionEnd, isNonImeChange); 242 && mTextInputType != TextInputType.CONTENT_EDITABLE;
243 mInputConnection.updateStateOnUiThread(text, selectionStart, selectionEn d, compositionStart,
244 compositionEnd, singleLine, isNonImeChange);
291 } 245 }
292 246
293 /** 247 /**
294 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding 248 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding
295 * keyboard events to WebKit. 249 * keyboard events to WebKit.
296 * @param nativeImeAdapter The pointer to the native ImeAdapter object. 250 * @param nativeImeAdapter The pointer to the native ImeAdapter object.
297 */ 251 */
298 public void attach(long nativeImeAdapter) { 252 public void attach(long nativeImeAdapter) {
299 if (mNativeImeAdapterAndroid == nativeImeAdapter) return; 253 if (mNativeImeAdapterAndroid == nativeImeAdapter) return;
300 if (mNativeImeAdapterAndroid != 0) { 254 if (mNativeImeAdapterAndroid != 0) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 if (DEBUG_LOGS) Log.w(TAG, "onViewFocusChanged: gainFocus [%b]", gainFoc us); 323 if (DEBUG_LOGS) Log.w(TAG, "onViewFocusChanged: gainFocus [%b]", gainFoc us);
370 if (!gainFocus) hideKeyboard(); 324 if (!gainFocus) hideKeyboard();
371 } 325 }
372 326
373 /** 327 /**
374 * Move cursor to the end of the current selection. 328 * Move cursor to the end of the current selection.
375 */ 329 */
376 public void moveCursorToSelectionEnd() { 330 public void moveCursorToSelectionEnd() {
377 if (DEBUG_LOGS) Log.w(TAG, "movecursorToEnd"); 331 if (DEBUG_LOGS) Log.w(TAG, "movecursorToEnd");
378 if (mInputConnection != null) { 332 if (mInputConnection != null) {
379 int selectionEnd = Selection.getSelectionEnd(mEditable); 333 mInputConnection.moveCursorToSelectionEndOnUiThread();
380 mInputConnection.setSelection(selectionEnd, selectionEnd);
381 } 334 }
382 } 335 }
383 336
384 @VisibleForTesting 337 @VisibleForTesting
385 void setInputTypeForTest(int textInputType) { 338 void setInputTypeForTest(int textInputType) {
386 mTextInputType = textInputType; 339 mTextInputType = textInputType;
387 } 340 }
388 341
389 private static boolean isTextInputType(int type) { 342 private static boolean isTextInputType(int type) {
390 return type != TextInputType.NONE && !InputDialogContainer.isDialogInput Type(type); 343 return type != TextInputType.NONE && !InputDialogContainer.isDialogInput Type(type);
391 } 344 }
392 345
393 public boolean hasTextInputType() { 346 public boolean hasTextInputType() {
394 return isTextInputType(mTextInputType); 347 return isTextInputType(mTextInputType);
395 } 348 }
396 349
350 /**
351 * See {@link View#dispatchKeyEvent(KeyEvent)}
352 */
397 public boolean dispatchKeyEvent(KeyEvent event) { 353 public boolean dispatchKeyEvent(KeyEvent event) {
398 if (DEBUG_LOGS) Log.w(TAG, "dispatchKeyEvent: action [%d], keycode [%d]" , event.getAction(), 354 if (DEBUG_LOGS) Log.w(TAG, "dispatchKeyEvent: action [%d], keycode [%d]" , event.getAction(),
399 event.getKeyCode()); 355 event.getKeyCode());
400 if (mInputConnection != null) { 356 if (mInputConnection != null) return mInputConnection.sendKeyEventOnUiTh read(event);
401 return mInputConnection.sendKeyEvent(event);
402 }
403 return sendKeyEvent(event); 357 return sendKeyEvent(event);
404 } 358 }
405 359
406 /** 360 /**
361 * Resets IME adapter and hides keyboard. Note that this will also unblock i nput connection.
362 */
363 public void reset() {
364 if (DEBUG_LOGS) Log.w(TAG, "reset");
365 mTextInputType = TextInputType.NONE;
366 mTextInputFlags = 0;
367 // This will trigger unblocking if necessary.
368 hideKeyboard();
369 }
370
371 /**
407 * Update selection to input method manager. 372 * Update selection to input method manager.
408 * 373 *
409 * @param selectionStart The selection start. 374 * @param selectionStart The selection start.
410 * @param selectionEnd The selection end. 375 * @param selectionEnd The selection end.
411 * @param compositionStart The composition start. 376 * @param compositionStart The composition start.
412 * @param compositionEnd The composition end. 377 * @param compositionEnd The composition end.
413 */ 378 */
414 void updateSelection( 379 void updateSelection(
415 int selectionStart, int selectionEnd, int compositionStart, int comp ositionEnd) { 380 int selectionStart, int selectionEnd, int compositionStart, int comp ositionEnd) {
416 mInputMethodManagerWrapper.updateSelection(mViewEmbedder.getAttachedView (), selectionStart, 381 if (mInputConnection != null) {
417 selectionEnd, compositionStart, compositionEnd); 382 mInputMethodManagerWrapper.updateSelection(mViewEmbedder.getAttached View(),
383 selectionStart, selectionEnd, compositionStart, compositionE nd);
384 }
418 } 385 }
419 386
420 /** 387 /**
421 * Restart input (finish composition and change EditorInfo, such as input ty pe). 388 * Restart input (finish composition and change EditorInfo, such as input ty pe).
422 */ 389 */
423 void restartInput() { 390 void restartInput() {
391 // This will eventually cause input method manager to call View#onCreate InputConnection().
424 mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView()) ; 392 mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView()) ;
425 if (mInputConnection != null) mInputConnection.onRestartInput(); 393 if (mInputConnection != null) mInputConnection.onRestartInputOnUiThread( );
426 } 394 }
427 395
428 /** 396 /**
429 * @see BaseInputConnection#performContextMenuAction(int) 397 * @see BaseInputConnection#performContextMenuAction(int)
430 */ 398 */
431 boolean performContextMenuAction(int id) { 399 boolean performContextMenuAction(int id) {
432 if (DEBUG_LOGS) Log.w(TAG, "performContextMenuAction: id [%d]", id); 400 if (DEBUG_LOGS) Log.w(TAG, "performContextMenuAction: id [%d]", id);
433 return mViewEmbedder.performContextMenuAction(id); 401 return mViewEmbedder.performContextMenuAction(id);
434 } 402 }
435 403
436 boolean performEditorAction(int actionCode) { 404 boolean performEditorAction(int actionCode) {
437 if (mNativeImeAdapterAndroid == 0) return false; 405 if (mNativeImeAdapterAndroid == 0) return false;
438 if (actionCode == EditorInfo.IME_ACTION_NEXT) { 406 if (actionCode == EditorInfo.IME_ACTION_NEXT) {
439 sendSyntheticKeyPress(KeyEvent.KEYCODE_TAB, 407 sendSyntheticKeyPress(KeyEvent.KEYCODE_TAB,
440 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE 408 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
441 | KeyEvent.FLAG_EDITOR_ACTION); 409 | KeyEvent.FLAG_EDITOR_ACTION);
442 } else { 410 } else {
443 sendSyntheticKeyPress(KeyEvent.KEYCODE_ENTER, 411 sendSyntheticKeyPress(KeyEvent.KEYCODE_ENTER,
444 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE 412 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
445 | KeyEvent.FLAG_EDITOR_ACTION); 413 | KeyEvent.FLAG_EDITOR_ACTION);
446 } 414 }
447 return true; 415 return true;
448 } 416 }
449 417
418 void notifyUserAction() {
419 mInputMethodManagerWrapper.notifyUserAction();
420 }
421
450 @VisibleForTesting 422 @VisibleForTesting
451 protected void sendSyntheticKeyPress(int keyCode, int flags) { 423 protected void sendSyntheticKeyPress(int keyCode, int flags) {
452 long eventTime = SystemClock.uptimeMillis(); 424 long eventTime = SystemClock.uptimeMillis();
453 sendKeyEvent(new KeyEvent(eventTime, eventTime, 425 sendKeyEvent(new KeyEvent(eventTime, eventTime,
454 KeyEvent.ACTION_DOWN, keyCode, 0, 0, 426 KeyEvent.ACTION_DOWN, keyCode, 0, 0,
455 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 427 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
456 flags)); 428 flags));
457 sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, 429 sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
458 KeyEvent.ACTION_UP, keyCode, 0, 0, 430 KeyEvent.ACTION_UP, keyCode, 0, 0,
459 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 431 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
(...skipping 21 matching lines...) Expand all
481 nativeSetComposingText( 453 nativeSetComposingText(
482 mNativeImeAdapterAndroid, text, text.toString(), newCursorPo sition); 454 mNativeImeAdapterAndroid, text, text.toString(), newCursorPo sition);
483 } 455 }
484 456
485 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType. KeyUp, 457 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType. KeyUp,
486 timestampMs, COMPOSITION_KEY_CODE, 0, 0); 458 timestampMs, COMPOSITION_KEY_CODE, 0, 0);
487 return true; 459 return true;
488 } 460 }
489 461
490 @VisibleForTesting 462 @VisibleForTesting
491 void finishComposingText() { 463 boolean finishComposingText() {
492 if (mNativeImeAdapterAndroid == 0) return; 464 if (mNativeImeAdapterAndroid == 0) return false;
493 nativeFinishComposingText(mNativeImeAdapterAndroid); 465 nativeFinishComposingText(mNativeImeAdapterAndroid);
466 return true;
494 } 467 }
495 468
496 boolean sendKeyEvent(KeyEvent event) { 469 boolean sendKeyEvent(KeyEvent event) {
497 if (mNativeImeAdapterAndroid == 0) return false; 470 if (mNativeImeAdapterAndroid == 0) return false;
498 471
499 int action = event.getAction(); 472 int action = event.getAction();
500 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) { 473 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) {
501 // action == KeyEvent.ACTION_MULTIPLE 474 // action == KeyEvent.ACTION_MULTIPLE
502 // TODO(bulach): confirm the actual behavior. Apparently: 475 // TODO(bulach): confirm the actual behavior. Apparently:
503 // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a 476 // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end); 519 nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end);
547 return true; 520 return true;
548 } 521 }
549 522
550 /** 523 /**
551 * Send a request to the native counterpart to set composing region to given indices. 524 * Send a request to the native counterpart to set composing region to given indices.
552 * @param start The start of the composition. 525 * @param start The start of the composition.
553 * @param end The end of the composition. 526 * @param end The end of the composition.
554 * @return Whether the native counterpart of ImeAdapter received the call. 527 * @return Whether the native counterpart of ImeAdapter received the call.
555 */ 528 */
556 boolean setComposingRegion(CharSequence text, int start, int end) { 529 boolean setComposingRegion(int start, int end) {
557 if (mNativeImeAdapterAndroid == 0) return false; 530 if (mNativeImeAdapterAndroid == 0) return false;
558 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end); 531 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end);
559 return true; 532 return true;
560 } 533 }
561 534
562 @CalledByNative 535 @CalledByNative
563 private void focusedNodeChanged(boolean isEditable) { 536 private void focusedNodeChanged(boolean isEditable) {
564 if (DEBUG_LOGS) Log.w(TAG, "focusedNodeChanged: isEditable [%b]", isEdit able); 537 if (DEBUG_LOGS) Log.w(TAG, "focusedNodeChanged: isEditable [%b]", isEdit able);
565 if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) { 538 if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) {
566 restartInput(); 539 restartInput();
567 } 540 }
568 } 541 }
569 542
543 /**
544 * Send a request to the native counterpart to give the latest text input st ate update.
545 */
546 boolean requestTextInputStateUpdate() {
547 if (mNativeImeAdapterAndroid == 0) return false;
548 // You won't get state update anyways.
549 if (mInputConnection == null) return false;
550 return nativeRequestTextInputStateUpdate(mNativeImeAdapterAndroid);
551 }
552
570 @CalledByNative 553 @CalledByNative
571 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { 554 private void populateUnderlinesFromSpans(CharSequence text, long underlines) {
572 if (DEBUG_LOGS) { 555 if (DEBUG_LOGS) {
573 Log.w(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines); 556 Log.w(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines);
574 } 557 }
575 if (!(text instanceof SpannableString)) return; 558 if (!(text instanceof SpannableString)) return;
576 559
577 SpannableString spannableString = ((SpannableString) text); 560 SpannableString spannableString = ((SpannableString) text);
578 CharacterStyle spans[] = 561 CharacterStyle spans[] =
579 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; 562 spannableString.getSpans(0, text.length(), CharacterStyle.class) ;
(...skipping 16 matching lines...) Expand all
596 } 579 }
597 580
598 @CalledByNative 581 @CalledByNative
599 private void detach() { 582 private void detach() {
600 if (DEBUG_LOGS) Log.w(TAG, "detach"); 583 if (DEBUG_LOGS) Log.w(TAG, "detach");
601 mNativeImeAdapterAndroid = 0; 584 mNativeImeAdapterAndroid = 0;
602 } 585 }
603 586
604 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, 587 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid,
605 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar); 588 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar);
606
607 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, 589 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event,
608 int action, int modifiers, long timestampMs, int keyCode, int scanCo de, 590 int action, int modifiers, long timestampMs, int keyCode, int scanCo de,
609 boolean isSystemKey, int unicodeChar); 591 boolean isSystemKey, int unicodeChar);
610
611 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); 592 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end);
612
613 private static native void nativeAppendBackgroundColorSpan(long underlinePtr , int start, 593 private static native void nativeAppendBackgroundColorSpan(long underlinePtr , int start,
614 int end, int backgroundColor); 594 int end, int backgroundColor);
615
616 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Cha rSequence text, 595 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Cha rSequence text,
617 String textStr, int newCursorPosition); 596 String textStr, int newCursorPosition);
618
619 private native void nativeCommitText(long nativeImeAdapterAndroid, String te xtStr); 597 private native void nativeCommitText(long nativeImeAdapterAndroid, String te xtStr);
620
621 private native void nativeFinishComposingText(long nativeImeAdapterAndroid); 598 private native void nativeFinishComposingText(long nativeImeAdapterAndroid);
622
623 private native void nativeAttachImeAdapter(long nativeImeAdapterAndroid); 599 private native void nativeAttachImeAdapter(long nativeImeAdapterAndroid);
624
625 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid, 600 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid,
626 int start, int end); 601 int start, int end);
627
628 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end); 602 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end);
629
630 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , 603 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid ,
631 int before, int after); 604 int before, int after);
632
633 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); 605 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid);
606 private native boolean nativeRequestTextInputStateUpdate(long nativeImeAdapt erAndroid);
634 } 607 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698