| 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; |
| 11 import android.text.Editable; | 11 import android.text.Editable; |
| 12 import android.text.SpannableString; | 12 import android.text.SpannableString; |
| 13 import android.text.style.BackgroundColorSpan; | 13 import android.text.style.BackgroundColorSpan; |
| 14 import android.text.style.CharacterStyle; | 14 import android.text.style.CharacterStyle; |
| 15 import android.text.style.UnderlineSpan; | 15 import android.text.style.UnderlineSpan; |
| 16 import android.view.KeyCharacterMap; | 16 import android.view.KeyCharacterMap; |
| 17 import android.view.KeyEvent; | 17 import android.view.KeyEvent; |
| 18 import android.view.View; | 18 import android.view.View; |
| 19 import android.view.inputmethod.CursorAnchorInfo; |
| 19 import android.view.inputmethod.EditorInfo; | 20 import android.view.inputmethod.EditorInfo; |
| 21 import android.view.inputmethod.InputMethodManager; |
| 20 | 22 |
| 21 import org.chromium.base.CalledByNative; | 23 import org.chromium.base.CalledByNative; |
| 22 import org.chromium.base.JNINamespace; | 24 import org.chromium.base.JNINamespace; |
| 23 import org.chromium.base.VisibleForTesting; | 25 import org.chromium.base.VisibleForTesting; |
| 24 import org.chromium.blink_public.web.WebInputEventModifier; | 26 import org.chromium.blink_public.web.WebInputEventModifier; |
| 25 import org.chromium.blink_public.web.WebInputEventType; | 27 import org.chromium.blink_public.web.WebInputEventType; |
| 26 import org.chromium.blink_public.web.WebTextInputFlags; | 28 import org.chromium.blink_public.web.WebTextInputFlags; |
| 29 import org.chromium.content.browser.RenderCoordinates; |
| 27 import org.chromium.ui.base.ime.TextInputType; | 30 import org.chromium.ui.base.ime.TextInputType; |
| 28 import org.chromium.ui.picker.InputDialogContainer; | 31 import org.chromium.ui.picker.InputDialogContainer; |
| 29 | 32 |
| 30 import java.lang.CharSequence; | 33 import java.lang.CharSequence; |
| 31 | 34 |
| 32 /** | 35 /** |
| 33 * Adapts and plumbs android IME service onto the chrome text input API. | 36 * Adapts and plumbs android IME service onto the chrome text input API. |
| 34 * ImeAdapter provides an interface in both ways native <-> java: | 37 * ImeAdapter provides an interface in both ways native <-> java: |
| 35 * 1. InputConnectionAdapter notifies native code of text composition state and | 38 * 1. InputConnectionAdapter notifies native code of text composition state and |
| 36 * dispatch key events from java -> WebKit. | 39 * dispatch key events from java -> WebKit. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 | 106 |
| 104 private long mNativeImeAdapterAndroid; | 107 private long mNativeImeAdapterAndroid; |
| 105 private InputMethodManagerWrapper mInputMethodManagerWrapper; | 108 private InputMethodManagerWrapper mInputMethodManagerWrapper; |
| 106 private AdapterInputConnection mInputConnection; | 109 private AdapterInputConnection mInputConnection; |
| 107 private final ImeAdapterDelegate mViewEmbedder; | 110 private final ImeAdapterDelegate mViewEmbedder; |
| 108 private final Handler mHandler; | 111 private final Handler mHandler; |
| 109 private int mTextInputType; | 112 private int mTextInputType; |
| 110 private int mTextInputFlags; | 113 private int mTextInputFlags; |
| 111 private String mLastComposeText; | 114 private String mLastComposeText; |
| 112 | 115 |
| 116 private final CursorAnchorInfoController mCursorAnchorInfoController; |
| 117 |
| 113 @VisibleForTesting | 118 @VisibleForTesting |
| 114 int mLastSyntheticKeyCode; | 119 int mLastSyntheticKeyCode; |
| 115 | 120 |
| 116 @VisibleForTesting | 121 @VisibleForTesting |
| 117 boolean mIsShowWithoutHideOutstanding = false; | 122 boolean mIsShowWithoutHideOutstanding = false; |
| 118 | 123 |
| 119 /** | 124 /** |
| 120 * @param wrapper InputMethodManagerWrapper that should receive all the call
directed to | 125 * @param wrapper InputMethodManagerWrapper that should receive all the call
directed to |
| 121 * InputMethodManager. | 126 * InputMethodManager. |
| 122 * @param embedder The view that is used for callbacks from ImeAdapter. | 127 * @param embedder The view that is used for callbacks from ImeAdapter. |
| 123 */ | 128 */ |
| 124 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe
dder) { | 129 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe
dder) { |
| 125 mInputMethodManagerWrapper = wrapper; | 130 mInputMethodManagerWrapper = wrapper; |
| 126 mViewEmbedder = embedder; | 131 mViewEmbedder = embedder; |
| 127 mHandler = new Handler(); | 132 mHandler = new Handler(); |
| 133 mCursorAnchorInfoController = CursorAnchorInfoController.create(wrapper)
; |
| 128 } | 134 } |
| 129 | 135 |
| 130 /** | 136 /** |
| 131 * Default factory for AdapterInputConnection classes. | 137 * Default factory for AdapterInputConnection classes. |
| 132 */ | 138 */ |
| 133 public static class AdapterInputConnectionFactory { | 139 public static class AdapterInputConnectionFactory { |
| 134 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, | 140 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, |
| 135 Editable editable, EditorInfo outAttrs) { | 141 Editable editable, EditorInfo outAttrs) { |
| 136 return new AdapterInputConnection(view, imeAdapter, editable, outAtt
rs); | 142 return new AdapterInputConnection(view, imeAdapter, editable, outAtt
rs); |
| 137 } | 143 } |
| 138 } | 144 } |
| 139 | 145 |
| 140 /** | 146 /** |
| 141 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call
s to | 147 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call
s to |
| 142 * InputMethodManager. | 148 * InputMethodManager. |
| 143 * @param immw InputMethodManagerWrapper that should be used to call InputMe
thodManager. | 149 * @param immw InputMethodManagerWrapper that should be used to call InputMe
thodManager. |
| 144 */ | 150 */ |
| 145 @VisibleForTesting | 151 @VisibleForTesting |
| 146 public void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) { | 152 public void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) { |
| 147 mInputMethodManagerWrapper = immw; | 153 mInputMethodManagerWrapper = immw; |
| 154 if (mCursorAnchorInfoController != null) { |
| 155 mCursorAnchorInfoController.setInputMethodManagerWrapper(immw); |
| 156 } |
| 148 } | 157 } |
| 149 | 158 |
| 150 /** | 159 /** |
| 151 * Should be only used by AdapterInputConnection. | 160 * Should be only used by AdapterInputConnection. |
| 152 * @return InputMethodManagerWrapper that should receive all the calls direc
ted to | 161 * @return InputMethodManagerWrapper that should receive all the calls direc
ted to |
| 153 * InputMethodManager. | 162 * InputMethodManager. |
| 154 */ | 163 */ |
| 155 InputMethodManagerWrapper getInputMethodManagerWrapper() { | 164 InputMethodManagerWrapper getInputMethodManagerWrapper() { |
| 156 return mInputMethodManagerWrapper; | 165 return mInputMethodManagerWrapper; |
| 157 } | 166 } |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 /** | 611 /** |
| 603 * Send a request to the native counterpart of ImeAdapter to paste the text
from the clipboard. | 612 * Send a request to the native counterpart of ImeAdapter to paste the text
from the clipboard. |
| 604 * @return Whether the native counterpart of ImeAdapter received the call. | 613 * @return Whether the native counterpart of ImeAdapter received the call. |
| 605 */ | 614 */ |
| 606 public boolean paste() { | 615 public boolean paste() { |
| 607 if (mNativeImeAdapterAndroid == 0) return false; | 616 if (mNativeImeAdapterAndroid == 0) return false; |
| 608 nativePaste(mNativeImeAdapterAndroid); | 617 nativePaste(mNativeImeAdapterAndroid); |
| 609 return true; | 618 return true; |
| 610 } | 619 } |
| 611 | 620 |
| 621 public boolean onRequestCursorUpdates(int cursorUpdateMode) { |
| 622 if (mCursorAnchorInfoController == null) return false; |
| 623 return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMo
de, |
| 624 mViewEmbedder.getAttachedView()); |
| 625 } |
| 626 |
| 627 /** |
| 628 * Update the parameters that are to be passed to the IME through |
| 629 * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)}
. |
| 630 * @param text Text in the focused text field. |
| 631 * @param selectionStart Index where the text selection starts. {@code -1} i
f there is no |
| 632 * selection. |
| 633 * @param selectionEnd Index where the text selection ends. {@code -1} if th
ere is no |
| 634 * selection. |
| 635 * @param compositionStart Index where the text composition starts. {@code -
1} if there is no |
| 636 * selection. |
| 637 * @param compositionEnd Index where the text composition ends. {@code -1} i
f there is no |
| 638 * selection. |
| 639 */ |
| 640 public void updateTextAndSelection(String text, int selectionStart, int sele
ctionEnd, |
| 641 int compositionStart, int compositionEnd) { |
| 642 if (mCursorAnchorInfoController == null) return; |
| 643 mCursorAnchorInfoController.updateTextAndSelection(text, compositionStar
t, compositionEnd, |
| 644 selectionStart, selectionEnd); |
| 645 } |
| 646 |
| 647 /** |
| 648 * Notify the location of composing characters to the IME if it explicitly r
equested them. |
| 649 * @param renderCoordinates coordinate information to convert CSS (document)
coordinates to |
| 650 * View-local Physical (screen) coordinates |
| 651 * @param hasInsertionMarker Whether the insertion marker is visible or not. |
| 652 * @param insertionMarkerHorizontal X coordinates of the insertion marker if
it exists. |
| 653 * Will be ignored otherwise. |
| 654 * @param insertionMarkerTop Y coordinates of the top of the insertion marke
r if it exists. |
| 655 * Will be ignored otherwise. |
| 656 * @param insertionMarkerBottom Y coordinates of the bottom of the insertion
marker if it |
| 657 * exists. Will be ignored otherwise. |
| 658 */ |
| 659 public void onUpdateFrameInfo(RenderCoordinates renderCoordinates, boolean h
asInsertionMarker, |
| 660 boolean isInsertionMarkerVisible, float insertionMarkerHorizontal, |
| 661 float insertionMarkerTop, float insertionMarkerBottom) { |
| 662 if (mCursorAnchorInfoController == null) return; |
| 663 mCursorAnchorInfoController.onUpdateFrameInfo(renderCoordinates, hasInse
rtionMarker, |
| 664 isInsertionMarkerVisible, insertionMarkerHorizontal, insertionMa
rkerTop, |
| 665 insertionMarkerBottom, mViewEmbedder.getAttachedView()); |
| 666 } |
| 667 |
| 612 // Calls from C++ to Java | 668 // Calls from C++ to Java |
| 613 | 669 |
| 614 @CalledByNative | 670 @CalledByNative |
| 615 private void focusedNodeChanged(boolean isEditable) { | 671 private void focusedNodeChanged(boolean isEditable) { |
| 672 // Update controller before the connection is restarted. |
| 673 if (mCursorAnchorInfoController != null) { |
| 674 mCursorAnchorInfoController.focusedNodeChanged(isEditable); |
| 675 } |
| 616 if (mInputConnection != null && isEditable) mInputConnection.restartInpu
t(); | 676 if (mInputConnection != null && isEditable) mInputConnection.restartInpu
t(); |
| 617 } | 677 } |
| 618 | 678 |
| 619 @CalledByNative | 679 @CalledByNative |
| 620 private void populateUnderlinesFromSpans(CharSequence text, long underlines)
{ | 680 private void populateUnderlinesFromSpans(CharSequence text, long underlines)
{ |
| 621 if (!(text instanceof SpannableString)) return; | 681 if (!(text instanceof SpannableString)) return; |
| 622 | 682 |
| 623 SpannableString spannableString = ((SpannableString) text); | 683 SpannableString spannableString = ((SpannableString) text); |
| 624 CharacterStyle spans[] = | 684 CharacterStyle spans[] = |
| 625 spannableString.getSpans(0, text.length(), CharacterStyle.class)
; | 685 spannableString.getSpans(0, text.length(), CharacterStyle.class)
; |
| 626 for (CharacterStyle span : spans) { | 686 for (CharacterStyle span : spans) { |
| 627 if (span instanceof BackgroundColorSpan) { | 687 if (span instanceof BackgroundColorSpan) { |
| 628 nativeAppendBackgroundColorSpan(underlines, spannableString.getS
panStart(span), | 688 nativeAppendBackgroundColorSpan(underlines, spannableString.getS
panStart(span), |
| 629 spannableString.getSpanEnd(span), | 689 spannableString.getSpanEnd(span), |
| 630 ((BackgroundColorSpan) span).getBackgroundColor()); | 690 ((BackgroundColorSpan) span).getBackgroundColor()); |
| 631 } else if (span instanceof UnderlineSpan) { | 691 } else if (span instanceof UnderlineSpan) { |
| 632 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta
rt(span), | 692 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta
rt(span), |
| 633 spannableString.getSpanEnd(span)); | 693 spannableString.getSpanEnd(span)); |
| 634 } | 694 } |
| 635 } | 695 } |
| 636 } | 696 } |
| 637 | 697 |
| 638 @CalledByNative | 698 @CalledByNative |
| 639 private void cancelComposition() { | 699 private void cancelComposition() { |
| 640 if (mInputConnection != null) mInputConnection.restartInput(); | 700 if (mInputConnection != null) mInputConnection.restartInput(); |
| 641 mLastComposeText = null; | 701 mLastComposeText = null; |
| 642 } | 702 } |
| 643 | 703 |
| 644 @CalledByNative | 704 @CalledByNative |
| 705 private void setCharacterBounds(float[] characterBounds) { |
| 706 if (mCursorAnchorInfoController == null) return; |
| 707 mCursorAnchorInfoController.setCompositionCharacterBounds(characterBound
s); |
| 708 } |
| 709 |
| 710 @CalledByNative |
| 645 void detach() { | 711 void detach() { |
| 646 mHandler.removeCallbacks(mDismissInputRunnable); | 712 mHandler.removeCallbacks(mDismissInputRunnable); |
| 647 mNativeImeAdapterAndroid = 0; | 713 mNativeImeAdapterAndroid = 0; |
| 648 mTextInputType = 0; | 714 mTextInputType = 0; |
| 715 if (mCursorAnchorInfoController != null) { |
| 716 mCursorAnchorInfoController.focusedNodeChanged(false); |
| 717 } |
| 649 } | 718 } |
| 650 | 719 |
| 651 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr
oid, | 720 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr
oid, |
| 652 int eventType, long timestampMs, int keyCode, int modifiers, int uni
codeChar); | 721 int eventType, long timestampMs, int keyCode, int modifiers, int uni
codeChar); |
| 653 | 722 |
| 654 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE
vent event, | 723 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE
vent event, |
| 655 int action, int modifiers, long timestampMs, int keyCode, boolean is
SystemKey, | 724 int action, int modifiers, long timestampMs, int keyCode, boolean is
SystemKey, |
| 656 int unicodeChar); | 725 int unicodeChar); |
| 657 | 726 |
| 658 private static native void nativeAppendUnderlineSpan(long underlinePtr, int
start, int end); | 727 private static native void nativeAppendUnderlineSpan(long underlinePtr, int
start, int end); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 677 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid
, | 746 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid
, |
| 678 int before, int after); | 747 int before, int after); |
| 679 | 748 |
| 680 private native void nativeUnselect(long nativeImeAdapterAndroid); | 749 private native void nativeUnselect(long nativeImeAdapterAndroid); |
| 681 private native void nativeSelectAll(long nativeImeAdapterAndroid); | 750 private native void nativeSelectAll(long nativeImeAdapterAndroid); |
| 682 private native void nativeCut(long nativeImeAdapterAndroid); | 751 private native void nativeCut(long nativeImeAdapterAndroid); |
| 683 private native void nativeCopy(long nativeImeAdapterAndroid); | 752 private native void nativeCopy(long nativeImeAdapterAndroid); |
| 684 private native void nativePaste(long nativeImeAdapterAndroid); | 753 private native void nativePaste(long nativeImeAdapterAndroid); |
| 685 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); | 754 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); |
| 686 } | 755 } |
| OLD | NEW |