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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
119 private long mNativeImeAdapterAndroid; | 122 private long mNativeImeAdapterAndroid; |
120 private InputMethodManagerWrapper mInputMethodManagerWrapper; | 123 private InputMethodManagerWrapper mInputMethodManagerWrapper; |
121 private AdapterInputConnection mInputConnection; | 124 private AdapterInputConnection mInputConnection; |
122 private final ImeAdapterDelegate mViewEmbedder; | 125 private final ImeAdapterDelegate mViewEmbedder; |
123 private final Handler mHandler; | 126 private final Handler mHandler; |
124 private DelayedDismissInput mDismissInput = null; | 127 private DelayedDismissInput mDismissInput = null; |
125 private int mTextInputType; | 128 private int mTextInputType; |
126 private int mTextInputFlags; | 129 private int mTextInputFlags; |
127 private String mLastComposeText; | 130 private String mLastComposeText; |
128 | 131 |
132 private final CursorAnchorInfoController mCursorAnchorInfoController; | |
133 | |
129 @VisibleForTesting | 134 @VisibleForTesting |
130 int mLastSyntheticKeyCode; | 135 int mLastSyntheticKeyCode; |
131 | 136 |
132 @VisibleForTesting | 137 @VisibleForTesting |
133 boolean mIsShowWithoutHideOutstanding = false; | 138 boolean mIsShowWithoutHideOutstanding = false; |
134 | 139 |
135 /** | 140 /** |
136 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to | 141 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to |
137 * InputMethodManager. | 142 * InputMethodManager. |
138 * @param embedder The view that is used for callbacks from ImeAdapter. | 143 * @param embedder The view that is used for callbacks from ImeAdapter. |
139 */ | 144 */ |
140 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { | 145 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { |
141 mInputMethodManagerWrapper = wrapper; | 146 mInputMethodManagerWrapper = wrapper; |
142 mViewEmbedder = embedder; | 147 mViewEmbedder = embedder; |
143 mHandler = new Handler(); | 148 mHandler = new Handler(); |
149 mCursorAnchorInfoController = CursorAnchorInfoController.create(wrapper) ; | |
144 } | 150 } |
145 | 151 |
146 /** | 152 /** |
147 * Default factory for AdapterInputConnection classes. | 153 * Default factory for AdapterInputConnection classes. |
148 */ | 154 */ |
149 public static class AdapterInputConnectionFactory { | 155 public static class AdapterInputConnectionFactory { |
150 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, | 156 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, |
151 Editable editable, EditorInfo outAttrs) { | 157 Editable editable, EditorInfo outAttrs) { |
152 return new AdapterInputConnection(view, imeAdapter, editable, outAtt rs); | 158 return new AdapterInputConnection(view, imeAdapter, editable, outAtt rs); |
153 } | 159 } |
154 } | 160 } |
155 | 161 |
156 /** | 162 /** |
157 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to | 163 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to |
158 * InputMethodManager. | 164 * InputMethodManager. |
159 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager. | 165 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager. |
160 */ | 166 */ |
161 @VisibleForTesting | 167 @VisibleForTesting |
162 public void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) { | 168 public void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) { |
163 mInputMethodManagerWrapper = immw; | 169 mInputMethodManagerWrapper = immw; |
170 if (mCursorAnchorInfoController != null) { | |
171 mCursorAnchorInfoController.setInputMethodManagerWrapper(immw); | |
172 } | |
164 } | 173 } |
165 | 174 |
166 /** | 175 /** |
167 * Should be only used by AdapterInputConnection. | 176 * Should be only used by AdapterInputConnection. |
168 * @return InputMethodManagerWrapper that should receive all the calls direc ted to | 177 * @return InputMethodManagerWrapper that should receive all the calls direc ted to |
169 * InputMethodManager. | 178 * InputMethodManager. |
170 */ | 179 */ |
171 InputMethodManagerWrapper getInputMethodManagerWrapper() { | 180 InputMethodManagerWrapper getInputMethodManagerWrapper() { |
172 return mInputMethodManagerWrapper; | 181 return mInputMethodManagerWrapper; |
173 } | 182 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding | 282 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding |
274 * keyboard events to WebKit. | 283 * keyboard events to WebKit. |
275 * @param nativeImeAdapter The pointer to the native ImeAdapter object. | 284 * @param nativeImeAdapter The pointer to the native ImeAdapter object. |
276 */ | 285 */ |
277 public void attach(long nativeImeAdapter) { | 286 public void attach(long nativeImeAdapter) { |
278 attach(nativeImeAdapter, TextInputType.NONE, WebTextInputFlags.None); | 287 attach(nativeImeAdapter, TextInputType.NONE, WebTextInputFlags.None); |
279 } | 288 } |
280 | 289 |
281 private void showKeyboard() { | 290 private void showKeyboard() { |
282 mIsShowWithoutHideOutstanding = true; | 291 mIsShowWithoutHideOutstanding = true; |
283 mInputMethodManagerWrapper.showSoftInput( | 292 mInputMethodManagerWrapper.showSoftInput(mViewEmbedder.getAttachedView() , 0, |
284 mViewEmbedder.getAttachedView(), 0, mViewEmbedder.getNewShowKeyb oardReceiver()); | 293 mViewEmbedder.getNewShowKeyboardReceiver()); |
jdduke (slow)
2015/04/15 19:38:24
Was this change intentional?
| |
285 if (mViewEmbedder.getAttachedView().getResources().getConfiguration().ke yboard | 294 if (mViewEmbedder.getAttachedView().getResources().getConfiguration().ke yboard |
286 != Configuration.KEYBOARD_NOKEYS) { | 295 != Configuration.KEYBOARD_NOKEYS) { |
287 mViewEmbedder.onKeyboardBoundsUnchanged(); | 296 mViewEmbedder.onKeyboardBoundsUnchanged(); |
288 } | 297 } |
289 } | 298 } |
290 | 299 |
291 private void dismissInput(boolean unzoomIfNeeded) { | 300 private void dismissInput(boolean unzoomIfNeeded) { |
292 mIsShowWithoutHideOutstanding = false; | 301 mIsShowWithoutHideOutstanding = false; |
293 View view = mViewEmbedder.getAttachedView(); | 302 View view = mViewEmbedder.getAttachedView(); |
294 if (mInputMethodManagerWrapper.isActive(view)) { | 303 if (mInputMethodManagerWrapper.isActive(view)) { |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
608 /** | 617 /** |
609 * Send a request to the native counterpart of ImeAdapter to paste the text from the clipboard. | 618 * Send a request to the native counterpart of ImeAdapter to paste the text from the clipboard. |
610 * @return Whether the native counterpart of ImeAdapter received the call. | 619 * @return Whether the native counterpart of ImeAdapter received the call. |
611 */ | 620 */ |
612 public boolean paste() { | 621 public boolean paste() { |
613 if (mNativeImeAdapterAndroid == 0) return false; | 622 if (mNativeImeAdapterAndroid == 0) return false; |
614 nativePaste(mNativeImeAdapterAndroid); | 623 nativePaste(mNativeImeAdapterAndroid); |
615 return true; | 624 return true; |
616 } | 625 } |
617 | 626 |
627 public boolean onRequestCursorUpdates(int cursorUpdateMode) { | |
628 if (mCursorAnchorInfoController == null) return false; | |
629 return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMo de, | |
630 mViewEmbedder.getAttachedView()); | |
631 } | |
632 | |
633 /** | |
634 * Update the parameters that are to be passed to the IME through | |
635 * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} . | |
636 * @param text Text in the focused text field. | |
637 * @param selectionStart Index where the text selection starts. {@code -1} i f there is no | |
638 * selection. | |
639 * @param selectionEnd Index where the text selection ends. {@code -1} if th ere is no | |
640 * selection. | |
641 * @param compositionStart Index where the text composition starts. {@code - 1} if there is no | |
642 * selection. | |
643 * @param compositionEnd Index where the text composition ends. {@code -1} i f there is no | |
644 * selection. | |
645 */ | |
646 public void updateTextAndSelection(String text, int selectionStart, int sele ctionEnd, | |
647 int compositionStart, int compositionEnd) { | |
648 if (mCursorAnchorInfoController == null) return; | |
649 mCursorAnchorInfoController.updateTextAndSelection(text, compositionStar t, compositionEnd, | |
650 selectionStart, selectionEnd); | |
651 } | |
652 | |
653 /** | |
654 * Notify the location of composing characters to the IME if it explicitly r equested them. | |
655 * @param renderCoordinates coordinate information to convert CSS (document) coordinates to | |
656 * View-local Physical (screen) coordinates | |
657 * @param hasInsertionMarker Whether the insertion marker is visible or not. | |
658 * @param insertionMarkerHorizontal X coordinates of the insertion marker if it exists. | |
659 * Will be ignored otherwise. | |
660 * @param insertionMarkerTop Y coordinates of the top of the insertion marke r if it exists. | |
661 * Will be ignored otherwise. | |
662 * @param insertionMarkerBottom Y coordinates of the bottom of the insertion marker if it | |
663 * exists. Will be ignored otherwise. | |
664 */ | |
665 public void onUpdateFrameInfo(RenderCoordinates renderCoordinates, boolean h asInsertionMarker, | |
666 boolean isInsertionMarkerVisible, float insertionMarkerHorizontal, | |
667 float insertionMarkerTop, float insertionMarkerBottom) { | |
668 if (mCursorAnchorInfoController == null) return; | |
669 mCursorAnchorInfoController.onUpdateFrameInfo(renderCoordinates, hasInse rtionMarker, | |
670 isInsertionMarkerVisible, insertionMarkerHorizontal, insertionMa rkerTop, | |
671 insertionMarkerBottom, mViewEmbedder.getAttachedView()); | |
672 } | |
673 | |
618 // Calls from C++ to Java | 674 // Calls from C++ to Java |
619 | 675 |
620 @CalledByNative | 676 @CalledByNative |
621 private void focusedNodeChanged(boolean isEditable) { | 677 private void focusedNodeChanged(boolean isEditable) { |
678 // Update controller before the connection is restarted. | |
679 if (mCursorAnchorInfoController != null) { | |
680 mCursorAnchorInfoController.focusedNodeChanged(isEditable); | |
681 } | |
622 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t(); | 682 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t(); |
623 } | 683 } |
624 | 684 |
625 @CalledByNative | 685 @CalledByNative |
626 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { | 686 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { |
627 if (!(text instanceof SpannableString)) return; | 687 if (!(text instanceof SpannableString)) return; |
628 | 688 |
629 SpannableString spannableString = ((SpannableString) text); | 689 SpannableString spannableString = ((SpannableString) text); |
630 CharacterStyle spans[] = | 690 CharacterStyle spans[] = |
631 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; | 691 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; |
632 for (CharacterStyle span : spans) { | 692 for (CharacterStyle span : spans) { |
633 if (span instanceof BackgroundColorSpan) { | 693 if (span instanceof BackgroundColorSpan) { |
634 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), | 694 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), |
635 spannableString.getSpanEnd(span), | 695 spannableString.getSpanEnd(span), |
636 ((BackgroundColorSpan) span).getBackgroundColor()); | 696 ((BackgroundColorSpan) span).getBackgroundColor()); |
637 } else if (span instanceof UnderlineSpan) { | 697 } else if (span instanceof UnderlineSpan) { |
638 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), | 698 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), |
639 spannableString.getSpanEnd(span)); | 699 spannableString.getSpanEnd(span)); |
640 } | 700 } |
641 } | 701 } |
642 } | 702 } |
643 | 703 |
644 @CalledByNative | 704 @CalledByNative |
645 private void cancelComposition() { | 705 private void cancelComposition() { |
646 if (mInputConnection != null) mInputConnection.restartInput(); | 706 if (mInputConnection != null) mInputConnection.restartInput(); |
647 mLastComposeText = null; | 707 mLastComposeText = null; |
648 } | 708 } |
649 | 709 |
650 @CalledByNative | 710 @CalledByNative |
711 private void setCharacterBounds(float[] characterBounds) { | |
712 if (mCursorAnchorInfoController == null) return; | |
713 mCursorAnchorInfoController.setCompositionCharacterBounds(characterBound s); | |
714 } | |
715 | |
716 @CalledByNative | |
651 void detach() { | 717 void detach() { |
652 if (mDismissInput != null) { | 718 if (mDismissInput != null) { |
653 mHandler.removeCallbacks(mDismissInput); | 719 mHandler.removeCallbacks(mDismissInput); |
654 mDismissInput.detach(); | 720 mDismissInput.detach(); |
655 } | 721 } |
656 mNativeImeAdapterAndroid = 0; | 722 mNativeImeAdapterAndroid = 0; |
657 mTextInputType = 0; | 723 mTextInputType = 0; |
724 if (mCursorAnchorInfoController != null) { | |
725 mCursorAnchorInfoController.focusedNodeChanged(false); | |
726 } | |
658 } | 727 } |
659 | 728 |
660 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, | 729 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, |
661 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar); | 730 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar); |
662 | 731 |
663 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, | 732 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, |
664 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey, | 733 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey, |
665 int unicodeChar); | 734 int unicodeChar); |
666 | 735 |
667 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); | 736 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); |
(...skipping 18 matching lines...) Expand all Loading... | |
686 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , | 755 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , |
687 int before, int after); | 756 int before, int after); |
688 | 757 |
689 private native void nativeUnselect(long nativeImeAdapterAndroid); | 758 private native void nativeUnselect(long nativeImeAdapterAndroid); |
690 private native void nativeSelectAll(long nativeImeAdapterAndroid); | 759 private native void nativeSelectAll(long nativeImeAdapterAndroid); |
691 private native void nativeCut(long nativeImeAdapterAndroid); | 760 private native void nativeCut(long nativeImeAdapterAndroid); |
692 private native void nativeCopy(long nativeImeAdapterAndroid); | 761 private native void nativeCopy(long nativeImeAdapterAndroid); |
693 private native void nativePaste(long nativeImeAdapterAndroid); | 762 private native void nativePaste(long nativeImeAdapterAndroid); |
694 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); | 763 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); |
695 } | 764 } |
OLD | NEW |