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.os.Handler; | 7 import android.os.Handler; |
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; | 10 import android.text.Editable; |
11 import android.text.SpannableString; | |
12 import android.text.style.BackgroundColorSpan; | |
13 import android.text.style.CharacterStyle; | |
14 import android.text.style.UnderlineSpan; | |
11 import android.view.KeyCharacterMap; | 15 import android.view.KeyCharacterMap; |
12 import android.view.KeyEvent; | 16 import android.view.KeyEvent; |
13 import android.view.View; | 17 import android.view.View; |
14 import android.view.inputmethod.EditorInfo; | 18 import android.view.inputmethod.EditorInfo; |
15 | 19 |
16 import com.google.common.annotations.VisibleForTesting; | 20 import com.google.common.annotations.VisibleForTesting; |
17 | 21 |
22 import java.lang.CharSequence; | |
23 | |
18 import org.chromium.base.CalledByNative; | 24 import org.chromium.base.CalledByNative; |
19 import org.chromium.base.JNINamespace; | 25 import org.chromium.base.JNINamespace; |
20 | 26 |
21 /** | 27 /** |
22 * Adapts and plumbs android IME service onto the chrome text input API. | 28 * Adapts and plumbs android IME service onto the chrome text input API. |
23 * ImeAdapter provides an interface in both ways native <-> java: | 29 * ImeAdapter provides an interface in both ways native <-> java: |
24 * 1. InputConnectionAdapter notifies native code of text composition state and | 30 * 1. InputConnectionAdapter notifies native code of text composition state and |
25 * dispatch key events from java -> WebKit. | 31 * dispatch key events from java -> WebKit. |
26 * 2. Native ImeAdapter notifies java side to clear composition text. | 32 * 2. Native ImeAdapter notifies java side to clear composition text. |
27 * | 33 * |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
321 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 327 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
322 flags)); | 328 flags)); |
323 translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), ev entTime, | 329 translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), ev entTime, |
324 KeyEvent.ACTION_UP, keyCode, 0, 0, | 330 KeyEvent.ACTION_UP, keyCode, 0, 0, |
325 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 331 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
326 flags)); | 332 flags)); |
327 } | 333 } |
328 | 334 |
329 // Calls from Java to C++ | 335 // Calls from Java to C++ |
330 | 336 |
331 boolean checkCompositionQueueAndCallNative(String text, int newCursorPositio n, | 337 boolean checkCompositionQueueAndCallNative(CharSequence text, int newCursorP osition, |
332 boolean isCommit) { | 338 boolean isCommit) { |
333 if (mNativeImeAdapterAndroid == 0) return false; | 339 if (mNativeImeAdapterAndroid == 0) return false; |
340 String textStr = text.toString(); | |
334 | 341 |
335 // Committing an empty string finishes the current composition. | 342 // Committing an empty string finishes the current composition. |
336 boolean isFinish = text.isEmpty(); | 343 boolean isFinish = textStr.isEmpty(); |
337 mViewEmbedder.onImeEvent(isFinish); | 344 mViewEmbedder.onImeEvent(isFinish); |
338 int keyCode = shouldSendKeyEventWithKeyCode(text); | 345 int keyCode = shouldSendKeyEventWithKeyCode(textStr); |
339 long timeStampMs = SystemClock.uptimeMillis(); | 346 long timeStampMs = SystemClock.uptimeMillis(); |
340 | 347 |
341 if (keyCode != COMPOSITION_KEY_CODE) { | 348 if (keyCode != COMPOSITION_KEY_CODE) { |
342 sendKeyEventWithKeyCode(keyCode, | 349 sendKeyEventWithKeyCode(keyCode, |
343 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE) ; | 350 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE) ; |
344 } else { | 351 } else { |
345 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawK eyDown, | 352 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawK eyDown, |
346 timeStampMs, keyCode, 0); | 353 timeStampMs, keyCode, 0); |
347 if (isCommit) { | 354 if (isCommit) { |
348 nativeCommitText(mNativeImeAdapterAndroid, text); | 355 nativeCommitText(mNativeImeAdapterAndroid, textStr); |
349 } else { | 356 } else { |
350 nativeSetComposingText(mNativeImeAdapterAndroid, text, newCursor Position); | 357 nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr, newCursorPosition); |
351 } | 358 } |
352 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyU p, | 359 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyU p, |
353 timeStampMs, keyCode, 0); | 360 timeStampMs, keyCode, 0); |
354 } | 361 } |
355 | 362 |
356 return true; | 363 return true; |
357 } | 364 } |
358 | 365 |
359 void finishComposingText() { | 366 void finishComposingText() { |
360 if (mNativeImeAdapterAndroid == 0) return; | 367 if (mNativeImeAdapterAndroid == 0) return; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 sTextInputTypeNumber = textInputTypeNumber; | 520 sTextInputTypeNumber = textInputTypeNumber; |
514 sTextInputTypeContentEditable = textInputTypeContentEditable; | 521 sTextInputTypeContentEditable = textInputTypeContentEditable; |
515 } | 522 } |
516 | 523 |
517 @CalledByNative | 524 @CalledByNative |
518 private void focusedNodeChanged(boolean isEditable) { | 525 private void focusedNodeChanged(boolean isEditable) { |
519 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t(); | 526 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t(); |
520 } | 527 } |
521 | 528 |
522 @CalledByNative | 529 @CalledByNative |
530 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { | |
531 String textStr = text.toString(); | |
532 if (!(text instanceof SpannableString)) | |
aurimas (slooooooooow)
2014/06/10 20:06:35
Can we add assert : text instanceof SpannableStrin
huangs
2014/06/10 20:23:56
I think here we should be robust rather than fragi
| |
533 return; | |
534 | |
535 SpannableString spannableString = ((SpannableString) text); | |
536 CharacterStyle spans[] = | |
537 spannableString.getSpans(0, textStr.length(), CharacterStyle.cla ss); | |
538 for (CharacterStyle span : spans) { | |
539 if (span instanceof BackgroundColorSpan) { | |
540 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), | |
541 spannableString.getSpanEnd(span), | |
542 ((BackgroundColorSpan) span).getBackgroundColor()); | |
543 } else if (span instanceof UnderlineSpan) { | |
544 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), | |
545 spannableString.getSpanEnd(span)); | |
546 } | |
547 } | |
548 } | |
549 | |
550 @CalledByNative | |
523 private void cancelComposition() { | 551 private void cancelComposition() { |
524 if (mInputConnection != null) mInputConnection.restartInput(); | 552 if (mInputConnection != null) mInputConnection.restartInput(); |
525 } | 553 } |
526 | 554 |
527 @CalledByNative | 555 @CalledByNative |
528 void detach() { | 556 void detach() { |
529 if (mDismissInput != null) mHandler.removeCallbacks(mDismissInput); | 557 if (mDismissInput != null) mHandler.removeCallbacks(mDismissInput); |
530 mNativeImeAdapterAndroid = 0; | 558 mNativeImeAdapterAndroid = 0; |
531 mTextInputType = 0; | 559 mTextInputType = 0; |
532 } | 560 } |
533 | 561 |
534 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, | 562 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, |
535 int eventType, long timestampMs, int keyCode, int unicodeChar); | 563 int eventType, long timestampMs, int keyCode, int unicodeChar); |
536 | 564 |
537 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, | 565 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, |
538 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey, | 566 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey, |
539 int unicodeChar); | 567 int unicodeChar); |
540 | 568 |
541 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Str ing text, | 569 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); |
542 int newCursorPosition); | |
543 | 570 |
544 private native void nativeCommitText(long nativeImeAdapterAndroid, String te xt); | 571 private static native void nativeAppendBackgroundColorSpan(long underlinePtr , int start, |
572 int end, int backgroundColor); | |
573 | |
574 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Cha rSequence text, | |
575 String textStr, int newCursorPosition); | |
576 | |
577 private native void nativeCommitText(long nativeImeAdapterAndroid, String te xtStr); | |
545 | 578 |
546 private native void nativeFinishComposingText(long nativeImeAdapterAndroid); | 579 private native void nativeFinishComposingText(long nativeImeAdapterAndroid); |
547 | 580 |
548 private native void nativeAttachImeAdapter(long nativeImeAdapterAndroid); | 581 private native void nativeAttachImeAdapter(long nativeImeAdapterAndroid); |
549 | 582 |
550 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid, | 583 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid, |
551 int start, int end); | 584 int start, int end); |
552 | 585 |
553 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end); | 586 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end); |
554 | 587 |
555 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , | 588 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , |
556 int before, int after); | 589 int before, int after); |
557 | 590 |
558 private native void nativeUnselect(long nativeImeAdapterAndroid); | 591 private native void nativeUnselect(long nativeImeAdapterAndroid); |
559 private native void nativeSelectAll(long nativeImeAdapterAndroid); | 592 private native void nativeSelectAll(long nativeImeAdapterAndroid); |
560 private native void nativeCut(long nativeImeAdapterAndroid); | 593 private native void nativeCut(long nativeImeAdapterAndroid); |
561 private native void nativeCopy(long nativeImeAdapterAndroid); | 594 private native void nativeCopy(long nativeImeAdapterAndroid); |
562 private native void nativePaste(long nativeImeAdapterAndroid); | 595 private native void nativePaste(long nativeImeAdapterAndroid); |
563 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); | 596 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); |
564 } | 597 } |
OLD | NEW |