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

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

Issue 1589953005: Support InputMethodManager#updateCursorAnchorInfo for Android 5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment remove. Created 4 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.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.Selection; 11 import android.text.Selection;
12 import android.text.SpannableString; 12 import android.text.SpannableString;
13 import android.text.TextUtils; 13 import android.text.TextUtils;
14 import android.text.style.BackgroundColorSpan; 14 import android.text.style.BackgroundColorSpan;
15 import android.text.style.CharacterStyle; 15 import android.text.style.CharacterStyle;
16 import android.text.style.UnderlineSpan; 16 import android.text.style.UnderlineSpan;
17 import android.view.KeyCharacterMap; 17 import android.view.KeyCharacterMap;
18 import android.view.KeyEvent; 18 import android.view.KeyEvent;
19 import android.view.View; 19 import android.view.View;
20 import android.view.inputmethod.BaseInputConnection; 20 import android.view.inputmethod.BaseInputConnection;
21 import android.view.inputmethod.EditorInfo; 21 import android.view.inputmethod.EditorInfo;
22 22
23 import org.chromium.base.Log; 23 import org.chromium.base.Log;
24 import org.chromium.base.VisibleForTesting; 24 import org.chromium.base.VisibleForTesting;
25 import org.chromium.base.annotations.CalledByNative; 25 import org.chromium.base.annotations.CalledByNative;
26 import org.chromium.base.annotations.JNINamespace; 26 import org.chromium.base.annotations.JNINamespace;
27 import org.chromium.blink_public.web.WebInputEventModifier; 27 import org.chromium.blink_public.web.WebInputEventModifier;
28 import org.chromium.blink_public.web.WebInputEventType; 28 import org.chromium.blink_public.web.WebInputEventType;
29 import org.chromium.content.browser.RenderCoordinates;
29 import org.chromium.ui.base.ime.TextInputType; 30 import org.chromium.ui.base.ime.TextInputType;
30 import org.chromium.ui.picker.InputDialogContainer; 31 import org.chromium.ui.picker.InputDialogContainer;
31 32
32 /** 33 /**
33 * Adapts and plumbs android IME service onto the chrome text input API. 34 * Adapts and plumbs android IME service onto the chrome text input API.
34 * ImeAdapter provides an interface in both ways native <-> java: 35 * ImeAdapter provides an interface in both ways native <-> java:
35 * 1. InputConnectionAdapter notifies native code of text composition state and 36 * 1. InputConnectionAdapter notifies native code of text composition state and
36 * dispatch key events from java -> WebKit. 37 * dispatch key events from java -> WebKit.
37 * 2. Native ImeAdapter notifies java side to clear composition text. 38 * 2. Native ImeAdapter notifies java side to clear composition text.
38 * 39 *
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 private InputMethodManagerWrapper mInputMethodManagerWrapper; 95 private InputMethodManagerWrapper mInputMethodManagerWrapper;
95 private AdapterInputConnection mInputConnection; 96 private AdapterInputConnection mInputConnection;
96 private AdapterInputConnectionFactory mInputConnectionFactory; 97 private AdapterInputConnectionFactory mInputConnectionFactory;
97 private final ImeAdapterDelegate mViewEmbedder; 98 private final ImeAdapterDelegate mViewEmbedder;
98 99
99 // This holds the state of editable text (e.g. contents of <input>, contente ditable) of 100 // This holds the state of editable text (e.g. contents of <input>, contente ditable) of
100 // a focused element. 101 // a focused element.
101 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new 102 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
102 // state must be reflected to this to keep consistency. 103 // state must be reflected to this to keep consistency.
103 private final Editable mEditable; 104 private final Editable mEditable;
105 // This holds the information necessary for constructing CursorAnchorInfo, a nd notifies to
106 // InputMethodManager on appropriate timing, depending on how IME requested the information
107 // via InputConnection. The update request is per InputConnection, hence for each time it is
108 // re-created, the monitoring status will be reset.
109 private final CursorAnchorInfoController mCursorAnchorInfoController;
110
111 @VisibleForTesting
112 int mLastSyntheticKeyCode;
aelias_OOO_until_Jul13 2016/02/26 08:25:33 Looks like you accidentally reintroduced this dele
kinaba 2016/03/01 08:46:46 Ooops, removed.
104 113
105 private int mTextInputType = TextInputType.NONE; 114 private int mTextInputType = TextInputType.NONE;
106 private int mTextInputFlags; 115 private int mTextInputFlags;
107 116
108 // Keep the current configuration to detect the change when onConfigurationC hanged() is called. 117 // Keep the current configuration to detect the change when onConfigurationC hanged() is called.
109 private Configuration mCurrentConfig; 118 private Configuration mCurrentConfig;
110 119
111 /** 120 /**
112 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to 121 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to
113 * InputMethodManager. 122 * InputMethodManager.
114 * @param embedder The view that is used for callbacks from ImeAdapter. 123 * @param embedder The view that is used for callbacks from ImeAdapter.
115 */ 124 */
116 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { 125 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) {
117 mInputMethodManagerWrapper = wrapper; 126 mInputMethodManagerWrapper = wrapper;
118 mViewEmbedder = embedder; 127 mViewEmbedder = embedder;
119 mInputConnectionFactory = new AdapterInputConnectionFactory(); 128 mInputConnectionFactory = new AdapterInputConnectionFactory();
120 mEditable = Editable.Factory.getInstance().newEditable(""); 129 mEditable = Editable.Factory.getInstance().newEditable("");
121 Selection.setSelection(mEditable, 0); 130 Selection.setSelection(mEditable, 0);
122 // Deep copy newConfig so that we can notice the difference. 131 // Deep copy newConfig so that we can notice the difference.
123 mCurrentConfig = new Configuration( 132 mCurrentConfig = new Configuration(
124 mViewEmbedder.getAttachedView().getResources().getConfiguration( )); 133 mViewEmbedder.getAttachedView().getResources().getConfiguration( ));
134 mCursorAnchorInfoController = CursorAnchorInfoController.create(wrapper,
135 new CursorAnchorInfoController.ComposingTextDelegate() {
aelias_OOO_until_Jul13 2016/02/26 08:25:33 It's a bit odd to be new'ing this object just to i
kinaba 2016/03/01 08:46:46 Done.
136 @Override
137 public CharSequence getText() {
138 return mEditable;
139 }
140 @Override
141 public int getSelectionStart() {
142 return Selection.getSelectionStart(mEditable);
143 }
144 @Override
145 public int getSelectionEnd() {
146 return Selection.getSelectionEnd(mEditable);
147 }
148 @Override
149 public int getComposingTextStart() {
150 return BaseInputConnection.getComposingSpanStart(mEditab le);
aelias_OOO_until_Jul13 2016/02/26 08:25:33 The refactoring https://codereview.chromium.org/12
kinaba 2016/03/01 08:46:46 Done.
151 }
152 @Override
153 public int getComposingTextEnd() {
154 return BaseInputConnection.getComposingSpanEnd(mEditable );
155 }
156 });
125 } 157 }
126 158
127 /** 159 /**
128 * Default factory for AdapterInputConnection classes. 160 * Default factory for AdapterInputConnection classes.
129 */ 161 */
130 static class AdapterInputConnectionFactory { 162 static class AdapterInputConnectionFactory {
131 AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initial SelStart, 163 AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initial SelStart,
132 int initialSelEnd, EditorInfo outAttrs) { 164 int initialSelEnd, EditorInfo outAttrs) {
133 return new AdapterInputConnection( 165 return new AdapterInputConnection(
134 view, imeAdapter, initialSelStart, initialSelEnd, outAttrs); 166 view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
(...skipping 20 matching lines...) Expand all
155 if (!isTextInputType(mTextInputType)) { 187 if (!isTextInputType(mTextInputType)) {
156 // Although onCheckIsTextEditor will return false in this case, the EditorInfo 188 // Although onCheckIsTextEditor will return false in this case, the EditorInfo
157 // is still used by the InputMethodService. Need to make sure the IM E doesn't 189 // is still used by the InputMethodService. Need to make sure the IM E doesn't
158 // enter fullscreen mode. 190 // enter fullscreen mode.
159 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; 191 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
160 } 192 }
161 int initialSelStart = Selection.getSelectionStart(mEditable); 193 int initialSelStart = Selection.getSelectionStart(mEditable);
162 int initialSelEnd = outAttrs.initialSelEnd = Selection.getSelectionEnd(m Editable); 194 int initialSelEnd = outAttrs.initialSelEnd = Selection.getSelectionEnd(m Editable);
163 mInputConnection = mInputConnectionFactory.get( 195 mInputConnection = mInputConnectionFactory.get(
164 mViewEmbedder.getAttachedView(), this, initialSelStart, initialS elEnd, outAttrs); 196 mViewEmbedder.getAttachedView(), this, initialSelStart, initialS elEnd, outAttrs);
197 if (mCursorAnchorInfoController != null) {
198 mCursorAnchorInfoController.resetMonitoringState();
199 }
165 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection"); 200 if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection");
166 return mInputConnection; 201 return mInputConnection;
167 } 202 }
168 203
169 /** 204 /**
170 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to 205 * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make call s to
171 * InputMethodManager. 206 * InputMethodManager.
172 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager. 207 * @param immw InputMethodManagerWrapper that should be used to call InputMe thodManager.
173 */ 208 */
174 @VisibleForTesting 209 @VisibleForTesting
175 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper im mw) { 210 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper im mw) {
176 mInputMethodManagerWrapper = immw; 211 mInputMethodManagerWrapper = immw;
212 if (mCursorAnchorInfoController != null) {
213 mCursorAnchorInfoController.setInputMethodManagerWrapper(immw);
214 }
177 } 215 }
178 216
179 @VisibleForTesting 217 @VisibleForTesting
180 void setInputConnectionFactory(AdapterInputConnectionFactory factory) { 218 void setInputConnectionFactory(AdapterInputConnectionFactory factory) {
181 mInputConnectionFactory = factory; 219 mInputConnectionFactory = factory;
182 } 220 }
183 221
184 /** 222 /**
185 * Set the current active InputConnection when a new InputConnection is cons tructed. 223 * Set the current active InputConnection when a new InputConnection is cons tructed.
186 * @param inputConnection The input connection that is currently used with I ME. 224 * @param inputConnection The input connection that is currently used with I ME.
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 * @param selectionEnd The character offset of the selection end, or the car et position if there 316 * @param selectionEnd The character offset of the selection end, or the car et position if there
279 * is no selection. 317 * is no selection.
280 * @param compositionStart The character offset of the composition start, or -1 if there is no 318 * @param compositionStart The character offset of the composition start, or -1 if there is no
281 * composition. 319 * composition.
282 * @param compositionEnd The character offset of the composition end, or -1 if there is no 320 * @param compositionEnd The character offset of the composition end, or -1 if there is no
283 * selection. 321 * selection.
284 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript). 322 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript).
285 */ 323 */
286 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart, 324 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart,
287 int compositionEnd, boolean isNonImeChange) { 325 int compositionEnd, boolean isNonImeChange) {
288 if (mInputConnection == null) return; 326 if (mInputConnection != null) {
289 mInputConnection.updateState(text, selectionStart, selectionEnd, composi tionStart, 327 mInputConnection.updateState(text, selectionStart, selectionEnd, com positionStart,
290 compositionEnd, isNonImeChange); 328 compositionEnd, isNonImeChange);
329 }
330 if (mCursorAnchorInfoController != null) {
331 mCursorAnchorInfoController.invalidateLastCursorAnchorInfo();
332 }
291 } 333 }
292 334
293 /** 335 /**
294 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding 336 * Attaches the imeAdapter to its native counterpart. This is needed to star t forwarding
295 * keyboard events to WebKit. 337 * keyboard events to WebKit.
296 * @param nativeImeAdapter The pointer to the native ImeAdapter object. 338 * @param nativeImeAdapter The pointer to the native ImeAdapter object.
297 */ 339 */
298 public void attach(long nativeImeAdapter) { 340 public void attach(long nativeImeAdapter) {
299 if (mNativeImeAdapterAndroid == nativeImeAdapter) return; 341 if (mNativeImeAdapterAndroid == nativeImeAdapter) return;
300 if (mNativeImeAdapterAndroid != 0) { 342 if (mNativeImeAdapterAndroid != 0) {
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 */ 597 */
556 boolean setComposingRegion(CharSequence text, int start, int end) { 598 boolean setComposingRegion(CharSequence text, int start, int end) {
557 if (mNativeImeAdapterAndroid == 0) return false; 599 if (mNativeImeAdapterAndroid == 0) return false;
558 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end); 600 nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end);
559 return true; 601 return true;
560 } 602 }
561 603
562 @CalledByNative 604 @CalledByNative
563 private void focusedNodeChanged(boolean isEditable) { 605 private void focusedNodeChanged(boolean isEditable) {
564 if (DEBUG_LOGS) Log.w(TAG, "focusedNodeChanged: isEditable [%b]", isEdit able); 606 if (DEBUG_LOGS) Log.w(TAG, "focusedNodeChanged: isEditable [%b]", isEdit able);
607
608 // Update controller before the connection is restarted.
609 if (mCursorAnchorInfoController != null) {
610 mCursorAnchorInfoController.focusedNodeChanged(isEditable);
611 }
612
565 if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) { 613 if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) {
566 restartInput(); 614 restartInput();
567 } 615 }
568 } 616 }
569 617
618 public boolean onRequestCursorUpdates(int cursorUpdateMode) {
619 if (mCursorAnchorInfoController == null) return false;
620 return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMo de,
621 mViewEmbedder.getAttachedView());
622 }
623
624 /**
625 * Notify the location of composing characters to the IME if it explicitly r equested them.
626 * @param renderCoordinates coordinate information to convert CSS (document) coordinates to
627 * View-local Physical (screen) coordinates
628 * @param hasInsertionMarker Whether the insertion marker is visible or not.
629 * @param insertionMarkerHorizontal X coordinates (in view-local DIP pixels) of the insertion
630 * marker if it exists. Will be ignored otherwise.
631 * @param insertionMarkerTop Y coordinates (in view-local DIP pixels) of the top of the
632 * insertion marker if it exists. Will be ignored otherwise.
633 * @param insertionMarkerBottom Y coordinates (in view-local DIP pixels) of the bottom of
634 * the insertion marker if it exists. Will be ignored otherwise.
635 */
636 public void onUpdateFrameInfo(RenderCoordinates renderCoordinates, boolean h asInsertionMarker,
637 boolean isInsertionMarkerVisible, float insertionMarkerHorizontal,
638 float insertionMarkerTop, float insertionMarkerBottom) {
639 if (mCursorAnchorInfoController == null) return;
640 mCursorAnchorInfoController.onUpdateFrameInfo(renderCoordinates, hasInse rtionMarker,
641 isInsertionMarkerVisible, insertionMarkerHorizontal, insertionMa rkerTop,
642 insertionMarkerBottom, mViewEmbedder.getAttachedView());
643 }
644
570 @CalledByNative 645 @CalledByNative
571 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { 646 private void populateUnderlinesFromSpans(CharSequence text, long underlines) {
572 if (DEBUG_LOGS) { 647 if (DEBUG_LOGS) {
573 Log.w(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines); 648 Log.w(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines);
574 } 649 }
575 if (!(text instanceof SpannableString)) return; 650 if (!(text instanceof SpannableString)) return;
576 651
577 SpannableString spannableString = ((SpannableString) text); 652 SpannableString spannableString = ((SpannableString) text);
578 CharacterStyle spans[] = 653 CharacterStyle spans[] =
579 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; 654 spannableString.getSpans(0, text.length(), CharacterStyle.class) ;
580 for (CharacterStyle span : spans) { 655 for (CharacterStyle span : spans) {
581 if (span instanceof BackgroundColorSpan) { 656 if (span instanceof BackgroundColorSpan) {
582 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), 657 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span),
583 spannableString.getSpanEnd(span), 658 spannableString.getSpanEnd(span),
584 ((BackgroundColorSpan) span).getBackgroundColor()); 659 ((BackgroundColorSpan) span).getBackgroundColor());
585 } else if (span instanceof UnderlineSpan) { 660 } else if (span instanceof UnderlineSpan) {
586 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), 661 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span),
587 spannableString.getSpanEnd(span)); 662 spannableString.getSpanEnd(span));
588 } 663 }
589 } 664 }
590 } 665 }
591 666
592 @CalledByNative 667 @CalledByNative
593 private void cancelComposition() { 668 private void cancelComposition() {
594 if (DEBUG_LOGS) Log.w(TAG, "cancelComposition"); 669 if (DEBUG_LOGS) Log.w(TAG, "cancelComposition");
595 if (mInputConnection != null) restartInput(); 670 if (mInputConnection != null) restartInput();
596 } 671 }
597 672
598 @CalledByNative 673 @CalledByNative
674 private void setCharacterBounds(float[] characterBounds) {
675 if (mCursorAnchorInfoController == null) return;
676 mCursorAnchorInfoController.setCompositionCharacterBounds(characterBound s);
677 }
678
679 @CalledByNative
599 private void detach() { 680 private void detach() {
600 if (DEBUG_LOGS) Log.w(TAG, "detach"); 681 if (DEBUG_LOGS) Log.w(TAG, "detach");
601 mNativeImeAdapterAndroid = 0; 682 mNativeImeAdapterAndroid = 0;
683 mTextInputType = 0;
aelias_OOO_until_Jul13 2016/02/26 08:25:33 Another deleted line accidentally reintroduced?
kinaba 2016/03/01 08:46:46 Ouch. Sorry for my carelessness.. Done,.
684 if (mCursorAnchorInfoController != null) {
685 mCursorAnchorInfoController.focusedNodeChanged(false);
686 }
602 } 687 }
603 688
604 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, 689 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid,
605 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar); 690 int eventType, long timestampMs, int keyCode, int modifiers, int uni codeChar);
606 691
607 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, 692 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event,
608 int action, int modifiers, long timestampMs, int keyCode, int scanCo de, 693 int action, int modifiers, long timestampMs, int keyCode, int scanCo de,
609 boolean isSystemKey, int unicodeChar); 694 boolean isSystemKey, int unicodeChar);
610 695
611 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end); 696 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end);
(...skipping 13 matching lines...) Expand all
625 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid, 710 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid,
626 int start, int end); 711 int start, int end);
627 712
628 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end); 713 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end);
629 714
630 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , 715 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid ,
631 int before, int after); 716 int before, int after);
632 717
633 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); 718 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid);
634 } 719 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698