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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java

Issue 699333003: Support InputMethodManager#updateCursorAnchorInfo for Android 5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move the core logic into Java side Created 5 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.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
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
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());
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
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) {
629 return false;
630 }
631 return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMo de,
632 mViewEmbedder.getAttachedView());
633 }
634
635 /**
636 * Update the parameters that are to be passed to the IME through
637 * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} .
638 * @param text Text in the focused text field.
639 * @param selectionStart Index where the text selection starts. {@code -1} i f there is no
640 * selection.
641 * @param selectionEnd Index where the text selection ends. {@code -1} if th ere is no
642 * selection.
643 * @param compositionStart Index where the text composition starts. {@code - 1} if there is no
644 * selection.
645 * @param compositionEnd Index where the text composition ends. {@code -1} i f there is no
646 * selection.
647 */
648 public void updateTextAndSelection(String text, int selectionStart, int sele ctionEnd,
649 int compositionStart, int compositionEnd) {
650 if (mCursorAnchorInfoController == null) {
jdduke (slow) 2015/02/09 17:01:17 Nit: Early return on same line as if, without brac
yukawa 2015/02/10 17:24:54 Done.
651 return;
652 }
653 mCursorAnchorInfoController.updateTextAndSelection(text, compositionStar t, compositionEnd,
654 selectionStart, selectionEnd);
655 }
656
657 /**
658 * Notify the location of composing characters to the IME if it explicitly r equested them.
659 * @param renderCoordinates coordinate information to convert CSS (document) coordinates to
660 * View-local Physical (screen) coordinates
661 * @param hasInsertionMarker Whether the insertion marker is visible or not.
662 * @param insertionMarkerHorizontal X coordinates of the insertion marker if it exists.
663 * Will be ignored otherwise.
664 * @param insertionMarkerTop Y coordinates of the top of the insertion marke r if it exists.
665 * Will be ignored otherwise.
666 * @param insertionMarkerBottom Y coordinates of the bottom of the insertion marker if it
667 * exists. Will be ignored otherwise.
668 */
669 public void onUpdateFrameInfo(RenderCoordinates renderCoordinates, boolean h asInsertionMarker,
670 boolean isInsertionMarkerVisible, float insertionMarkerHorizontal,
671 float insertionMarkerTop, float insertionMarkerBottom) {
672 if (mCursorAnchorInfoController == null) {
673 return;
674 }
675 mCursorAnchorInfoController.onUpdateFrameInfo(renderCoordinates, hasInse rtionMarker,
676 isInsertionMarkerVisible, insertionMarkerHorizontal, insertionMa rkerTop,
677 insertionMarkerBottom, mViewEmbedder.getAttachedView());
678 }
679
618 // Calls from C++ to Java 680 // Calls from C++ to Java
619 681
620 @CalledByNative 682 @CalledByNative
621 private void focusedNodeChanged(boolean isEditable) { 683 private void focusedNodeChanged(boolean isEditable) {
684 // Update controller before the connection is restarted.
685 if (mCursorAnchorInfoController != null) {
686 mCursorAnchorInfoController.focusedNodeChanged(isEditable);
687 }
622 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t(); 688 if (mInputConnection != null && isEditable) mInputConnection.restartInpu t();
623 } 689 }
624 690
625 @CalledByNative 691 @CalledByNative
626 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { 692 private void populateUnderlinesFromSpans(CharSequence text, long underlines) {
627 if (!(text instanceof SpannableString)) return; 693 if (!(text instanceof SpannableString)) return;
628 694
629 SpannableString spannableString = ((SpannableString) text); 695 SpannableString spannableString = ((SpannableString) text);
630 CharacterStyle spans[] = 696 CharacterStyle spans[] =
631 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; 697 spannableString.getSpans(0, text.length(), CharacterStyle.class) ;
632 for (CharacterStyle span : spans) { 698 for (CharacterStyle span : spans) {
633 if (span instanceof BackgroundColorSpan) { 699 if (span instanceof BackgroundColorSpan) {
634 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), 700 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span),
635 spannableString.getSpanEnd(span), 701 spannableString.getSpanEnd(span),
636 ((BackgroundColorSpan) span).getBackgroundColor()); 702 ((BackgroundColorSpan) span).getBackgroundColor());
637 } else if (span instanceof UnderlineSpan) { 703 } else if (span instanceof UnderlineSpan) {
638 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), 704 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span),
639 spannableString.getSpanEnd(span)); 705 spannableString.getSpanEnd(span));
640 } 706 }
641 } 707 }
642 } 708 }
643 709
644 @CalledByNative 710 @CalledByNative
645 private void cancelComposition() { 711 private void cancelComposition() {
646 if (mInputConnection != null) mInputConnection.restartInput(); 712 if (mInputConnection != null) mInputConnection.restartInput();
647 mLastComposeText = null; 713 mLastComposeText = null;
648 } 714 }
649 715
650 @CalledByNative 716 @CalledByNative
717 private void setCharacterBounds(float[] characterBounds) {
jdduke (slow) 2015/02/09 17:01:17 Aren't the coordinates from the renderer in DIPs?
yukawa 2015/02/10 17:24:54 Yes I think it's DIP at least for Android and Wind
718 if (mCursorAnchorInfoController != null) {
719 mCursorAnchorInfoController.setCompositionCharacterBounds(characterB ounds);
720 }
721 }
722
723 @CalledByNative
651 void detach() { 724 void detach() {
652 if (mDismissInput != null) { 725 if (mDismissInput != null) {
653 mHandler.removeCallbacks(mDismissInput); 726 mHandler.removeCallbacks(mDismissInput);
654 mDismissInput.detach(); 727 mDismissInput.detach();
655 } 728 }
656 mNativeImeAdapterAndroid = 0; 729 mNativeImeAdapterAndroid = 0;
657 mTextInputType = 0; 730 mTextInputType = 0;
731 if (mCursorAnchorInfoController != null) {
732 mCursorAnchorInfoController.focusedNodeChanged(false);
jdduke (slow) 2015/02/09 17:01:17 Might as well null it out here as well I guess.
yukawa 2015/02/10 17:24:54 I think #attach can be called again after #detach,
733 }
658 } 734 }
659 735
660 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, 736 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid,
661 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar); 737 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar);
662 738
663 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, 739 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event,
664 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey, 740 int action, int modifiers, long timestampMs, int keyCode, boolean is SystemKey,
665 int unicodeChar); 741 int unicodeChar);
666 742
667 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); 743 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end);
(...skipping 18 matching lines...) Expand all
686 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , 762 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid ,
687 int before, int after); 763 int before, int after);
688 764
689 private native void nativeUnselect(long nativeImeAdapterAndroid); 765 private native void nativeUnselect(long nativeImeAdapterAndroid);
690 private native void nativeSelectAll(long nativeImeAdapterAndroid); 766 private native void nativeSelectAll(long nativeImeAdapterAndroid);
691 private native void nativeCut(long nativeImeAdapterAndroid); 767 private native void nativeCut(long nativeImeAdapterAndroid);
692 private native void nativeCopy(long nativeImeAdapterAndroid); 768 private native void nativeCopy(long nativeImeAdapterAndroid);
693 private native void nativePaste(long nativeImeAdapterAndroid); 769 private native void nativePaste(long nativeImeAdapterAndroid);
694 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); 770 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid);
695 } 771 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698