OLD | NEW |
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.Handler; | 8 import android.os.Handler; |
9 import android.os.ResultReceiver; | 9 import android.os.ResultReceiver; |
10 import android.os.SystemClock; | 10 import android.os.SystemClock; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 static char[] sSingleCharArray = new char[1]; | 102 static char[] sSingleCharArray = new char[1]; |
103 static KeyCharacterMap sKeyCharacterMap; | 103 static KeyCharacterMap sKeyCharacterMap; |
104 | 104 |
105 private long mNativeImeAdapterAndroid; | 105 private long mNativeImeAdapterAndroid; |
106 private InputMethodManagerWrapper mInputMethodManagerWrapper; | 106 private InputMethodManagerWrapper mInputMethodManagerWrapper; |
107 private AdapterInputConnection mInputConnection; | 107 private AdapterInputConnection mInputConnection; |
108 private final ImeAdapterDelegate mViewEmbedder; | 108 private final ImeAdapterDelegate mViewEmbedder; |
109 private final Handler mHandler; | 109 private final Handler mHandler; |
110 private int mTextInputType; | 110 private int mTextInputType; |
111 private int mTextInputFlags; | 111 private int mTextInputFlags; |
112 private String mLastComposeText; | |
113 | |
114 @VisibleForTesting | |
115 int mLastSyntheticKeyCode; | |
116 | 112 |
117 @VisibleForTesting | 113 @VisibleForTesting |
118 boolean mIsShowWithoutHideOutstanding = false; | 114 boolean mIsShowWithoutHideOutstanding = false; |
119 | 115 |
120 /** | 116 /** |
121 * @param wrapper InputMethodManagerWrapper that should receive all the call
directed to | 117 * @param wrapper InputMethodManagerWrapper that should receive all the call
directed to |
122 * InputMethodManager. | 118 * InputMethodManager. |
123 * @param embedder The view that is used for callbacks from ImeAdapter. | 119 * @param embedder The view that is used for callbacks from ImeAdapter. |
124 */ | 120 */ |
125 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe
dder) { | 121 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe
dder) { |
(...skipping 30 matching lines...) Expand all Loading... |
156 InputMethodManagerWrapper getInputMethodManagerWrapper() { | 152 InputMethodManagerWrapper getInputMethodManagerWrapper() { |
157 return mInputMethodManagerWrapper; | 153 return mInputMethodManagerWrapper; |
158 } | 154 } |
159 | 155 |
160 /** | 156 /** |
161 * Set the current active InputConnection when a new InputConnection is cons
tructed. | 157 * Set the current active InputConnection when a new InputConnection is cons
tructed. |
162 * @param inputConnection The input connection that is currently used with I
ME. | 158 * @param inputConnection The input connection that is currently used with I
ME. |
163 */ | 159 */ |
164 void setInputConnection(AdapterInputConnection inputConnection) { | 160 void setInputConnection(AdapterInputConnection inputConnection) { |
165 mInputConnection = inputConnection; | 161 mInputConnection = inputConnection; |
166 mLastComposeText = null; | |
167 } | 162 } |
168 | 163 |
169 /** | 164 /** |
170 * Should be used only by AdapterInputConnection. | 165 * Should be used only by AdapterInputConnection. |
171 * @return The input type of currently focused element. | 166 * @return The input type of currently focused element. |
172 */ | 167 */ |
173 int getTextInputType() { | 168 int getTextInputType() { |
174 return mTextInputType; | 169 return mTextInputType; |
175 } | 170 } |
176 | 171 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 private void attach(long nativeImeAdapter, int textInputType, int textInputF
lags, | 234 private void attach(long nativeImeAdapter, int textInputType, int textInputF
lags, |
240 boolean delayDismissInput) { | 235 boolean delayDismissInput) { |
241 Log.d(TAG, "attach"); | 236 Log.d(TAG, "attach"); |
242 if (mNativeImeAdapterAndroid != 0) { | 237 if (mNativeImeAdapterAndroid != 0) { |
243 nativeResetImeAdapter(mNativeImeAdapterAndroid); | 238 nativeResetImeAdapter(mNativeImeAdapterAndroid); |
244 } | 239 } |
245 if (nativeImeAdapter != 0) { | 240 if (nativeImeAdapter != 0) { |
246 nativeAttachImeAdapter(nativeImeAdapter); | 241 nativeAttachImeAdapter(nativeImeAdapter); |
247 } | 242 } |
248 mNativeImeAdapterAndroid = nativeImeAdapter; | 243 mNativeImeAdapterAndroid = nativeImeAdapter; |
249 mLastComposeText = null; | |
250 mTextInputFlags = textInputFlags; | 244 mTextInputFlags = textInputFlags; |
251 if (textInputType == mTextInputType) return; | 245 if (textInputType == mTextInputType) return; |
252 mTextInputType = textInputType; | 246 mTextInputType = textInputType; |
253 mHandler.removeCallbacks(mDismissInputRunnable); // okay if not found | 247 mHandler.removeCallbacks(mDismissInputRunnable); // okay if not found |
254 if (mTextInputType == TextInputType.NONE) { | 248 if (mTextInputType == TextInputType.NONE) { |
255 if (delayDismissInput) { | 249 if (delayDismissInput) { |
256 // Set a delayed task to do unfocus. This avoids hiding the keyb
oard when tabbing | 250 // Set a delayed task to do unfocus. This avoids hiding the keyb
oard when tabbing |
257 // through text inputs or when JS rapidly changes focus to anoth
er text element. | 251 // through text inputs or when JS rapidly changes focus to anoth
er text element. |
258 mHandler.postDelayed(mDismissInputRunnable, INPUT_DISMISS_DELAY)
; | 252 mHandler.postDelayed(mDismissInputRunnable, INPUT_DISMISS_DELAY)
; |
259 mIsShowWithoutHideOutstanding = false; | 253 mIsShowWithoutHideOutstanding = false; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 public boolean hasTextInputType() { | 302 public boolean hasTextInputType() { |
309 return isTextInputType(mTextInputType); | 303 return isTextInputType(mTextInputType); |
310 } | 304 } |
311 | 305 |
312 public boolean dispatchKeyEvent(KeyEvent event) { | 306 public boolean dispatchKeyEvent(KeyEvent event) { |
313 Log.d(TAG, "dispatchKeyEvent: action [%d], keycode [%d]", event.getActio
n(), | 307 Log.d(TAG, "dispatchKeyEvent: action [%d], keycode [%d]", event.getActio
n(), |
314 event.getKeyCode()); | 308 event.getKeyCode()); |
315 if (mInputConnection != null) { | 309 if (mInputConnection != null) { |
316 return mInputConnection.sendKeyEvent(event); | 310 return mInputConnection.sendKeyEvent(event); |
317 } | 311 } |
318 return translateAndSendNativeEvents(event); | 312 return sendKeyEvent(event); |
319 } | |
320 | |
321 private int shouldSendKeyEventWithKeyCode(String text) { | |
322 if (text.length() != 1) return COMPOSITION_KEY_CODE; | |
323 | |
324 if (text.equals("\n")) { | |
325 return KeyEvent.KEYCODE_ENTER; | |
326 } else if (text.equals("\t")) { | |
327 return KeyEvent.KEYCODE_TAB; | |
328 } else { | |
329 return COMPOSITION_KEY_CODE; | |
330 } | |
331 } | |
332 | |
333 /** | |
334 * @return Android KeyEvent for a single unicode character. Only one KeyEve
nt is returned | |
335 * even if the system determined that various modifier keys (like Shift) wou
ld also have | |
336 * been pressed. | |
337 */ | |
338 private static KeyEvent androidKeyEventForCharacter(char chr) { | |
339 if (sKeyCharacterMap == null) { | |
340 sKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYB
OARD); | |
341 } | |
342 sSingleCharArray[0] = chr; | |
343 // TODO: Evaluate cost of this system call. | |
344 KeyEvent[] events = sKeyCharacterMap.getEvents(sSingleCharArray); | |
345 if (events == null) { // No known key sequence will create that charact
er. | |
346 return null; | |
347 } | |
348 | |
349 for (int i = 0; i < events.length; ++i) { | |
350 if (events[i].getAction() == KeyEvent.ACTION_DOWN | |
351 && !KeyEvent.isModifierKey(events[i].getKeyCode())) { | |
352 return events[i]; | |
353 } | |
354 } | |
355 | |
356 return null; // No printing characters were found. | |
357 } | 313 } |
358 | 314 |
359 /** | 315 /** |
360 * @see BaseInputConnection#performContextMenuAction(int) | 316 * @see BaseInputConnection#performContextMenuAction(int) |
361 */ | 317 */ |
362 public boolean performContextMenuAction(int id) { | 318 boolean performContextMenuAction(int id) { |
363 Log.d(TAG, "performContextMenuAction: id [%d]", id); | 319 Log.d(TAG, "performContextMenuAction: id [%d]", id); |
364 return mViewEmbedder.performContextMenuAction(id); | 320 return mViewEmbedder.performContextMenuAction(id); |
365 } | 321 } |
366 | 322 |
367 @VisibleForTesting | 323 boolean performEditorAction(int actionCode) { |
368 public static KeyEvent getTypedKeyEventGuess(String oldtext, String newtext)
{ | 324 if (mNativeImeAdapterAndroid == 0) return false; |
369 // Starting typing a new composition should add only a single character.
Any composition | 325 if (actionCode == EditorInfo.IME_ACTION_NEXT) { |
370 // beginning with text longer than that must come from something other t
han typing so | 326 sendSyntheticKeyPress(KeyEvent.KEYCODE_TAB, |
371 // return 0. | 327 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE |
372 if (oldtext == null) { | 328 | KeyEvent.FLAG_EDITOR_ACTION); |
373 if (newtext.length() == 1) { | 329 } else { |
374 return androidKeyEventForCharacter(newtext.charAt(0)); | 330 sendSyntheticKeyPress(KeyEvent.KEYCODE_ENTER, |
375 } else { | 331 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE |
376 return null; | 332 | KeyEvent.FLAG_EDITOR_ACTION); |
377 } | |
378 } | 333 } |
379 | 334 return true; |
380 // The content has grown in length: assume the last character is the key
that caused it. | |
381 if (newtext.length() > oldtext.length() && newtext.startsWith(oldtext))
{ | |
382 return androidKeyEventForCharacter(newtext.charAt(newtext.length() -
1)); | |
383 } | |
384 | |
385 // The content has shrunk in length: assume that backspace was pressed. | |
386 if (oldtext.length() > newtext.length() && oldtext.startsWith(newtext))
{ | |
387 return new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); | |
388 } | |
389 | |
390 // The content is unchanged or has undergone a complex change (i.e. not
a simple tail | |
391 // modification) so return an unknown key-code. | |
392 return null; | |
393 } | 335 } |
394 | 336 |
395 void sendKeyEventWithKeyCode(int keyCode, int flags) { | 337 @VisibleForTesting |
| 338 protected void sendSyntheticKeyPress(int keyCode, int flags) { |
396 long eventTime = SystemClock.uptimeMillis(); | 339 long eventTime = SystemClock.uptimeMillis(); |
397 mLastSyntheticKeyCode = keyCode; | 340 sendKeyEvent(new KeyEvent(eventTime, eventTime, |
398 translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime, | |
399 KeyEvent.ACTION_DOWN, keyCode, 0, 0, | 341 KeyEvent.ACTION_DOWN, keyCode, 0, 0, |
400 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 342 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
401 flags)); | 343 flags)); |
402 translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), ev
entTime, | 344 sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, |
403 KeyEvent.ACTION_UP, keyCode, 0, 0, | 345 KeyEvent.ACTION_UP, keyCode, 0, 0, |
404 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 346 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
405 flags)); | 347 flags)); |
406 } | 348 } |
407 | 349 |
408 // Calls from Java to C++ | 350 boolean sendCompositionToNative(CharSequence text, int newCursorPosition, bo
olean isCommit) { |
409 // TODO: Add performance tracing to more complicated functions. | |
410 boolean checkCompositionQueueAndCallNative(CharSequence text, int newCursorP
osition, | |
411 boolean isCommit) { | |
412 if (mNativeImeAdapterAndroid == 0) return false; | 351 if (mNativeImeAdapterAndroid == 0) return false; |
413 mViewEmbedder.onImeEvent(); | 352 mViewEmbedder.onImeEvent(); |
414 | 353 |
415 String textStr = text.toString(); | 354 long timestampMs = SystemClock.uptimeMillis(); |
416 int keyCode = shouldSendKeyEventWithKeyCode(textStr); | 355 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.
RawKeyDown, |
417 long timeStampMs = SystemClock.uptimeMillis(); | 356 timestampMs, COMPOSITION_KEY_CODE, 0, 0); |
418 | 357 |
419 if (keyCode != COMPOSITION_KEY_CODE) { | 358 if (isCommit) { |
420 sendKeyEventWithKeyCode(keyCode, | 359 nativeCommitText(mNativeImeAdapterAndroid, text.toString()); |
421 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)
; | |
422 } else { | 360 } else { |
423 KeyEvent keyEvent = getTypedKeyEventGuess(mLastComposeText, textStr)
; | 361 nativeSetComposingText( |
424 int modifiers = 0; | 362 mNativeImeAdapterAndroid, text, text.toString(), newCursorPo
sition); |
425 if (keyEvent != null) { | |
426 keyCode = keyEvent.getKeyCode(); | |
427 modifiers = getModifiers(keyEvent.getMetaState()); | |
428 } else if (!textStr.equals(mLastComposeText)) { | |
429 keyCode = KeyEvent.KEYCODE_UNKNOWN; | |
430 } else { | |
431 keyCode = -1; | |
432 } | |
433 | |
434 // If this is a single-character commit with no previous composition
, then treat it as | |
435 // a native KeyDown/KeyUp pair with no composition rather than a syn
thetic pair with | |
436 // composition below. | |
437 if (keyCode > 0 && isCommit && mLastComposeText == null && textStr.l
ength() == 1) { | |
438 mLastSyntheticKeyCode = keyCode; | |
439 return translateAndSendNativeEvents(keyEvent) | |
440 && translateAndSendNativeEvents( | |
441 KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_
UP)); | |
442 } | |
443 | |
444 // Always send compose events. This is a quick fix for http://crbug.
com/476497. | |
445 keyCode = COMPOSITION_KEY_CODE; | |
446 modifiers = 0; | |
447 | |
448 // When typing, there is no issue sending KeyDown and KeyUp events a
round the | |
449 // composition event because those key events do nothing (other than
call JS | |
450 // handlers). Typing does not cause changes outside of a KeyPress e
vent which | |
451 // we don't call here. However, if the key-code is a control key su
ch as | |
452 // KEYCODE_DEL then there never is an associated KeyPress event and
the KeyDown | |
453 // event itself causes the action. The net result below is that the
Renderer calls | |
454 // cancelComposition() and then Android starts anew with setComposin
gRegion(). | |
455 // This stopping and restarting of composition could be a source of
problems | |
456 // with 3rd party keyboards. | |
457 // | |
458 // An alternative is to *not* call nativeSetComposingText() in the n
on-commit case | |
459 // below. This avoids the restart of composition described above bu
t fails to send | |
460 // an update to the composition while in composition which, strictly
speaking, | |
461 // does not match the spec. | |
462 // | |
463 // For now, the solution is to endure the restarting of composition
and only dive | |
464 // into the alternate solution should there be problems in the field
. --bcwhite | |
465 | |
466 if (keyCode >= 0) { | |
467 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEv
entType.RawKeyDown, | |
468 timeStampMs, keyCode, modifiers, 0); | |
469 } | |
470 | |
471 if (isCommit) { | |
472 nativeCommitText(mNativeImeAdapterAndroid, textStr); | |
473 textStr = null; | |
474 } else { | |
475 nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr,
newCursorPosition); | |
476 } | |
477 | |
478 if (keyCode >= 0) { | |
479 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEv
entType.KeyUp, | |
480 timeStampMs, keyCode, modifiers, 0); | |
481 } | |
482 | |
483 mLastSyntheticKeyCode = keyCode; | |
484 } | 363 } |
485 | 364 |
486 mLastComposeText = textStr; | 365 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.
KeyUp, |
| 366 timestampMs, COMPOSITION_KEY_CODE, 0, 0); |
487 return true; | 367 return true; |
488 } | 368 } |
489 | 369 |
490 @VisibleForTesting | 370 @VisibleForTesting |
491 protected void finishComposingText() { | 371 protected void finishComposingText() { |
492 mLastComposeText = null; | |
493 if (mNativeImeAdapterAndroid == 0) return; | 372 if (mNativeImeAdapterAndroid == 0) return; |
494 nativeFinishComposingText(mNativeImeAdapterAndroid); | 373 nativeFinishComposingText(mNativeImeAdapterAndroid); |
495 } | 374 } |
496 | 375 |
497 boolean translateAndSendNativeEvents(KeyEvent event) { | 376 boolean sendKeyEvent(KeyEvent event) { |
498 if (mNativeImeAdapterAndroid == 0) return false; | 377 if (mNativeImeAdapterAndroid == 0) return false; |
499 | 378 |
500 int action = event.getAction(); | 379 int action = event.getAction(); |
501 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) { | 380 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) { |
502 // action == KeyEvent.ACTION_MULTIPLE | 381 // action == KeyEvent.ACTION_MULTIPLE |
503 // TODO(bulach): confirm the actual behavior. Apparently: | 382 // TODO(bulach): confirm the actual behavior. Apparently: |
504 // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a | 383 // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a |
505 // composition key down (229) followed by a commit text with the | 384 // composition key down (229) followed by a commit text with the |
506 // string from event.getUnicodeChars(). | 385 // string from event.getUnicodeChars(). |
507 // Otherwise, we'd need to send an event with a | 386 // Otherwise, we'd need to send an event with a |
508 // WebInputEvent::IsAutoRepeat modifier. We also need to verify when | 387 // WebInputEvent::IsAutoRepeat modifier. We also need to verify when |
509 // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOW
N, | 388 // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOW
N, |
510 // and if that's the case, we'll need to review when to send the Cha
r | 389 // and if that's the case, we'll need to review when to send the Cha
r |
511 // event. | 390 // event. |
512 return false; | 391 return false; |
513 } | 392 } |
514 mViewEmbedder.onImeEvent(); | 393 mViewEmbedder.onImeEvent(); |
515 return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, event.getActi
on(), | 394 return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, event.getActi
on(), |
516 getModifiers(event.getMetaState()), event.getEventTime(), event.
getKeyCode(), | 395 getModifiers(event.getMetaState()), event.getEventTime(), event.
getKeyCode(), |
517 event.getScanCode(), /*isSystemKey=*/false, event.g
etUnicodeChar()); | 396 event.getScanCode(), /*isSystemKey=*/false, event.g
etUnicodeChar()); |
518 } | 397 } |
519 | 398 |
520 boolean sendSyntheticKeyEvent(int eventType, long timestampMs, int keyCode,
int modifiers, | |
521 int unicodeChar) { | |
522 if (mNativeImeAdapterAndroid == 0) return false; | |
523 | |
524 nativeSendSyntheticKeyEvent( | |
525 mNativeImeAdapterAndroid, eventType, timestampMs, keyCode, modif
iers, unicodeChar); | |
526 return true; | |
527 } | |
528 | |
529 /** | 399 /** |
530 * Send a request to the native counterpart to delete a given range of chara
cters. | 400 * Send a request to the native counterpart to delete a given range of chara
cters. |
531 * @param beforeLength Number of characters to extend the selection by befor
e the existing | 401 * @param beforeLength Number of characters to extend the selection by befor
e the existing |
532 * selection. | 402 * selection. |
533 * @param afterLength Number of characters to extend the selection by after
the existing | 403 * @param afterLength Number of characters to extend the selection by after
the existing |
534 * selection. | 404 * selection. |
535 * @return Whether the native counterpart of ImeAdapter received the call. | 405 * @return Whether the native counterpart of ImeAdapter received the call. |
536 */ | 406 */ |
537 boolean deleteSurroundingText(int beforeLength, int afterLength) { | 407 boolean deleteSurroundingText(int beforeLength, int afterLength) { |
538 mViewEmbedder.onImeEvent(); | 408 mViewEmbedder.onImeEvent(); |
539 if (mNativeImeAdapterAndroid == 0) return false; | 409 if (mNativeImeAdapterAndroid == 0) return false; |
| 410 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.
RawKeyDown, |
| 411 SystemClock.uptimeMillis(), COMPOSITION_KEY_CODE, 0, 0); |
540 nativeDeleteSurroundingText(mNativeImeAdapterAndroid, beforeLength, afte
rLength); | 412 nativeDeleteSurroundingText(mNativeImeAdapterAndroid, beforeLength, afte
rLength); |
| 413 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, |
| 414 WebInputEventType.KeyUp, SystemClock.uptimeMillis(), COMPOSITION
_KEY_CODE, 0, 0); |
541 return true; | 415 return true; |
542 } | 416 } |
543 | 417 |
544 /** | 418 /** |
545 * Send a request to the native counterpart to set the selection to given ra
nge. | 419 * Send a request to the native counterpart to set the selection to given ra
nge. |
546 * @param start Selection start index. | 420 * @param start Selection start index. |
547 * @param end Selection end index. | 421 * @param end Selection end index. |
548 * @return Whether the native counterpart of ImeAdapter received the call. | 422 * @return Whether the native counterpart of ImeAdapter received the call. |
549 */ | 423 */ |
550 boolean setEditableSelectionOffsets(int start, int end) { | 424 boolean setEditableSelectionOffsets(int start, int end) { |
551 if (mNativeImeAdapterAndroid == 0) return false; | 425 if (mNativeImeAdapterAndroid == 0) return false; |
552 nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end); | 426 nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end); |
553 return true; | 427 return true; |
554 } | 428 } |
555 | 429 |
556 /** | 430 /** |
557 * Send a request to the native counterpart to set composing region to given
indices. | 431 * Send a request to the native counterpart to set composing region to given
indices. |
558 * @param start The start of the composition. | 432 * @param start The start of the composition. |
559 * @param end The end of the composition. | 433 * @param end The end of the composition. |
560 * @return Whether the native counterpart of ImeAdapter received the call. | 434 * @return Whether the native counterpart of ImeAdapter received the call. |
561 */ | 435 */ |
562 boolean setComposingRegion(CharSequence text, int start, int end) { | 436 boolean setComposingRegion(CharSequence text, int start, int end) { |
563 if (mNativeImeAdapterAndroid == 0) return false; | 437 if (mNativeImeAdapterAndroid == 0) return false; |
564 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end); | 438 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end); |
565 mLastComposeText = text != null ? text.toString() : null; | |
566 return true; | 439 return true; |
567 } | 440 } |
568 | 441 |
569 @CalledByNative | 442 @CalledByNative |
570 private void focusedNodeChanged(boolean isEditable) { | 443 private void focusedNodeChanged(boolean isEditable) { |
571 Log.d(TAG, "focusedNodeChanged"); | 444 Log.d(TAG, "focusedNodeChanged"); |
572 if (mInputConnection != null && isEditable) mInputConnection.restartInpu
t(); | 445 if (mInputConnection != null && isEditable) mInputConnection.restartInpu
t(); |
573 } | 446 } |
574 | 447 |
575 @CalledByNative | 448 @CalledByNative |
(...skipping 13 matching lines...) Expand all Loading... |
589 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta
rt(span), | 462 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta
rt(span), |
590 spannableString.getSpanEnd(span)); | 463 spannableString.getSpanEnd(span)); |
591 } | 464 } |
592 } | 465 } |
593 } | 466 } |
594 | 467 |
595 @CalledByNative | 468 @CalledByNative |
596 private void cancelComposition() { | 469 private void cancelComposition() { |
597 Log.d(TAG, "cancelComposition"); | 470 Log.d(TAG, "cancelComposition"); |
598 if (mInputConnection != null) mInputConnection.restartInput(); | 471 if (mInputConnection != null) mInputConnection.restartInput(); |
599 mLastComposeText = null; | |
600 } | 472 } |
601 | 473 |
602 @CalledByNative | 474 @CalledByNative |
603 void detach() { | 475 void detach() { |
604 Log.d(TAG, "detach"); | 476 Log.d(TAG, "detach"); |
605 mHandler.removeCallbacks(mDismissInputRunnable); | 477 mHandler.removeCallbacks(mDismissInputRunnable); |
606 mNativeImeAdapterAndroid = 0; | 478 mNativeImeAdapterAndroid = 0; |
607 mTextInputType = 0; | 479 mTextInputType = 0; |
608 } | 480 } |
609 | 481 |
(...skipping 21 matching lines...) Expand all Loading... |
631 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA
ndroid, | 503 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA
ndroid, |
632 int start, int end); | 504 int start, int end); |
633 | 505 |
634 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i
nt start, int end); | 506 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i
nt start, int end); |
635 | 507 |
636 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid
, | 508 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid
, |
637 int before, int after); | 509 int before, int after); |
638 | 510 |
639 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); | 511 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); |
640 } | 512 } |
OLD | NEW |