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

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

Powered by Google App Engine
This is Rietveld 408576698