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

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

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed release test failures Created 4 years, 11 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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.text.Editable; 7 import android.text.Editable;
8 import android.text.InputType;
9 import android.text.Selection; 8 import android.text.Selection;
10 import android.util.StringBuilderPrinter;
11 import android.view.KeyCharacterMap; 9 import android.view.KeyCharacterMap;
12 import android.view.KeyEvent; 10 import android.view.KeyEvent;
13 import android.view.View; 11 import android.view.View;
14 import android.view.inputmethod.BaseInputConnection; 12 import android.view.inputmethod.BaseInputConnection;
15 import android.view.inputmethod.EditorInfo; 13 import android.view.inputmethod.EditorInfo;
16 import android.view.inputmethod.ExtractedText; 14 import android.view.inputmethod.ExtractedText;
17 import android.view.inputmethod.ExtractedTextRequest; 15 import android.view.inputmethod.ExtractedTextRequest;
18 16
19 import org.chromium.base.Log; 17 import org.chromium.base.Log;
18 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.VisibleForTesting; 19 import org.chromium.base.VisibleForTesting;
21 import org.chromium.blink_public.web.WebTextInputFlags;
22 import org.chromium.ui.base.ime.TextInputType;
23
24 import java.util.Locale;
25 20
26 /** 21 /**
27 * InputConnection is created by ContentView.onCreateInputConnection. 22 * InputConnection is created by ContentView.onCreateInputConnection.
28 * It then adapts android's IME to chrome's RenderWidgetHostView using the 23 * It then adapts android's IME to chrome's RenderWidgetHostView using the
29 * native ImeAdapterAndroid via the class ImeAdapter. 24 * native ImeAdapterAndroid via the class ImeAdapter.
30 */ 25 */
31 public class AdapterInputConnection extends BaseInputConnection { 26 public class AdapterInputConnection
aelias_OOO_until_Jul13 2016/01/21 07:43:04 Could you rename this class and file to ReplicaInp
Changwan Ryu 2016/01/22 10:22:16 Done.
27 extends BaseInputConnection implements ChromiumBaseInputConnection {
32 private static final String TAG = "cr_Ime"; 28 private static final String TAG = "cr_Ime";
33 /** 29 /**
34 * Selection value should be -1 if not known. See EditorInfo.java for detail s. 30 * Selection value should be -1 if not known. See EditorInfo.java for detail s.
35 */ 31 */
36 public static final int INVALID_SELECTION = -1; 32 public static final int INVALID_SELECTION = -1;
33
37 public static final int INVALID_COMPOSITION = -1; 34 public static final int INVALID_COMPOSITION = -1;
38 35
39 private final ImeAdapter mImeAdapter; 36 private final ImeAdapter mImeAdapter;
40 37
38 // This holds the state of editable text (e.g. contents of <input>, contente ditable) of
39 // a focused element.
40 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
41 // state must be reflected to this to keep consistency.
42 private final Editable mEditable;
43
41 private boolean mSingleLine; 44 private boolean mSingleLine;
42 private int mNumNestedBatchEdits = 0; 45 private int mNumNestedBatchEdits = 0;
43 private int mPendingAccent; 46 private int mPendingAccent;
47 private final ThreadManager mThreadManager;
44 48
45 private int mLastUpdateSelectionStart = INVALID_SELECTION; 49 private int mLastUpdateSelectionStart = INVALID_SELECTION;
46 private int mLastUpdateSelectionEnd = INVALID_SELECTION; 50 private int mLastUpdateSelectionEnd = INVALID_SELECTION;
47 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; 51 private int mLastUpdateCompositionStart = INVALID_COMPOSITION;
48 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; 52 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
49 53
54 /**
55 * Default factory for AdapterInputConnection classes.
56 */
57 static class Factory implements ChromiumBaseInputConnection.Factory {
58 // Note: we share Editable among input connections so that data remains the same on
59 // switching inputs. However, the downside is that initial value cannot be correct, and
60 // wrong value will be used when jumping from one input to another.
61 protected final Editable mEditable;
62 private final ThreadManager mThreadManager;
63
64 Factory() {
65 mThreadManager = new ThreadManager();
66 mEditable = Editable.Factory.getInstance().newEditable("");
67 Selection.setSelection(mEditable, 0);
68 }
69
70 @Override
71 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, int inputType,
72 int inputFlags, EditorInfo outAttrs) {
73 return new AdapterInputConnection(
74 view, imeAdapter, mThreadManager, mEditable, inputType, inpu tFlags, outAttrs);
75 }
76 }
77
78 static class ThreadManager implements ChromiumBaseInputConnection.ThreadMana ger {
79 @Override
80 public boolean runningOnThisThread() {
81 return ThreadUtils.runningOnUiThread();
82 }
83
84 @Override
85 public void post(Runnable runnable) {
86 ThreadUtils.postOnUiThread(runnable);
87 }
88 }
89
50 @VisibleForTesting 90 @VisibleForTesting
51 AdapterInputConnection(View view, ImeAdapter imeAdapter, int initialSelStart , int initialSelEnd, 91 AdapterInputConnection(View view, ImeAdapter imeAdapter, ThreadManager threa dManager,
52 EditorInfo outAttrs) { 92 Editable editable, int inputType, int inputFlags, EditorInfo outAttr s) {
53 super(view, true); 93 super(view, true);
54 mImeAdapter = imeAdapter; 94 mImeAdapter = imeAdapter;
55 mImeAdapter.setInputConnection(this); 95 mEditable = editable;
96 mThreadManager = threadManager;
56 97
57 mSingleLine = true; 98 int initialSelStart = Selection.getSelectionStart(editable);
58 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN 99 int initialSelEnd = Selection.getSelectionEnd(editable);
59 | EditorInfo.IME_FLAG_NO_EXTRACT_UI; 100 ImeUtils.computeEditorInfo(inputType, inputFlags, initialSelStart, initi alSelEnd, outAttrs);
60 outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
61 | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
62 101
63 int inputType = imeAdapter.getTextInputType(); 102 mLastUpdateSelectionStart = initialSelStart;
64 int inputFlags = imeAdapter.getTextInputFlags(); 103 mLastUpdateSelectionEnd = initialSelEnd;
65 if ((inputFlags & WebTextInputFlags.AutocompleteOff) != 0) {
66 outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
67 }
68 104
69 if (inputType == TextInputType.TEXT) { 105 Log.d(TAG, "Constructor called with outAttrs: %s", ImeUtils.dumpEditorIn fo(outAttrs));
70 // Normal text field
71 outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
72 if ((inputFlags & WebTextInputFlags.AutocorrectOff) == 0) {
73 outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
74 }
75 } else if (inputType == TextInputType.TEXT_AREA
76 || inputType == TextInputType.CONTENT_EDITABLE) {
77 outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
78 if ((inputFlags & WebTextInputFlags.AutocorrectOff) == 0) {
79 outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
80 }
81 outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE;
82 mSingleLine = false;
83 } else if (inputType == TextInputType.PASSWORD) {
84 // Password
85 outAttrs.inputType = InputType.TYPE_CLASS_TEXT
86 | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
87 outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
88 } else if (inputType == TextInputType.SEARCH) {
89 // Search
90 outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH;
91 } else if (inputType == TextInputType.URL) {
92 // Url
93 outAttrs.inputType = InputType.TYPE_CLASS_TEXT
94 | InputType.TYPE_TEXT_VARIATION_URI;
95 outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
96 } else if (inputType == TextInputType.EMAIL) {
97 // Email
98 outAttrs.inputType = InputType.TYPE_CLASS_TEXT
99 | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
100 outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
101 } else if (inputType == TextInputType.TELEPHONE) {
102 // Telephone
103 // Number and telephone do not have both a Tab key and an
104 // action in default OSK, so set the action to NEXT
105 outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
106 outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
107 } else if (inputType == TextInputType.NUMBER) {
108 // Number
109 outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
110 | InputType.TYPE_NUMBER_VARIATION_NORMAL
111 | InputType.TYPE_NUMBER_FLAG_DECIMAL;
112 outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
113 }
114
115 // Handling of autocapitalize. Blink will send the flag taking into acco unt the element's
116 // type. This is not using AutocapitalizeNone because Android does not a utocapitalize by
117 // default and there is no way to express no capitalization.
118 // Autocapitalize is meant as a hint to the virtual keyboard.
119 if ((inputFlags & WebTextInputFlags.AutocapitalizeCharacters) != 0) {
120 outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
121 } else if ((inputFlags & WebTextInputFlags.AutocapitalizeWords) != 0) {
122 outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
123 } else if ((inputFlags & WebTextInputFlags.AutocapitalizeSentences) != 0 ) {
124 outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
125 }
126 // Content editable doesn't use autocapitalize so we need to set it manu ally.
127 if (inputType == TextInputType.CONTENT_EDITABLE) {
128 outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
129 }
130
131 outAttrs.initialSelStart = initialSelStart;
132 outAttrs.initialSelEnd = initialSelEnd;
133 mLastUpdateSelectionStart = outAttrs.initialSelStart;
134 mLastUpdateSelectionEnd = outAttrs.initialSelEnd;
135 Log.d(TAG, "Constructor called with outAttrs: %s", dumpEditorInfo(outAtt rs));
136 }
137
138 private static String dumpEditorInfo(EditorInfo editorInfo) {
139 StringBuilder builder = new StringBuilder();
140 StringBuilderPrinter printer = new StringBuilderPrinter(builder);
141 editorInfo.dump(printer, "");
142 return builder.toString();
143 }
144
145 private static String dumpEditable(Editable editable) {
146 return String.format(Locale.US, "Editable {[%s] SEL[%d %d] COM[%d %d]}",
147 editable.toString(),
148 Selection.getSelectionStart(editable),
149 Selection.getSelectionEnd(editable),
150 getComposingSpanStart(editable),
151 getComposingSpanEnd(editable));
152 } 106 }
153 107
154 /** 108 /**
155 * Updates the AdapterInputConnection's internal representation of the text being edited and 109 * Updates the AdapterInputConnection's internal representation of the text being edited and
156 * its selection and composition properties. The resulting Editable is acces sible through the 110 * its selection and composition properties. The resulting Editable is acces sible through the
157 * getEditable() method. If the text has not changed, this also calls update Selection on the 111 * getEditable() method. If the text has not changed, this also calls update Selection on the
158 * InputMethodManager. 112 * InputMethodManager.
159 * 113 *
160 * @param text The String contents of the field being edited. 114 * @param text The String contents of the field being edited.
161 * @param selectionStart The character offset of the selection start, or the caret position if 115 * @param selectionStart The character offset of the selection start, or the caret position if
162 * there is no selection. 116 * there is no selection.
163 * @param selectionEnd The character offset of the selection end, or the car et position if there 117 * @param selectionEnd The character offset of the selection end, or the car et position if there
164 * is no selection. 118 * is no selection.
165 * @param compositionStart The character offset of the composition start, or -1 if there is no 119 * @param compositionStart The character offset of the composition start, or -1 if there is no
166 * composition. 120 * composition.
167 * @param compositionEnd The character offset of the composition end, or -1 if there is no 121 * @param compositionEnd The character offset of the composition end, or -1 if there is no
168 * selection. 122 * selection.
169 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript). 123 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript).
170 */ 124 */
171 @VisibleForTesting 125 @Override
172 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart, 126 public void updateStateOnUiThread(String text, int selectionStart, int selec tionEnd,
173 int compositionEnd, boolean isNonImeChange) { 127 int compositionStart, int compositionEnd, boolean singleLine, boolea n isNonImeChange) {
174 Log.d(TAG, "updateState [%s] [%s %s] [%s %s] [%b]", text, selectionStart , 128 Log.d(TAG, "updateState [%s] [%s %s] [%s %s] [%b] [%b]", text, selection Start,
175 selectionEnd, compositionStart, compositionEnd, isNonImeChange); 129 selectionEnd, compositionStart, compositionEnd, singleLine, isNo nImeChange);
130 mSingleLine = singleLine;
131
176 // If this update is from the IME, no further state modification is nece ssary because the 132 // If this update is from the IME, no further state modification is nece ssary because the
177 // state should have been updated already by the IM framework directly. 133 // state should have been updated already by the IM framework directly.
178 if (!isNonImeChange) return; 134 if (!isNonImeChange) return;
179 135
180 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces. 136 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces.
181 text = text.replace('\u00A0', ' '); 137 text = text.replace('\u00A0', ' ');
182 138
183 selectionStart = Math.min(selectionStart, text.length()); 139 selectionStart = Math.min(selectionStart, text.length());
184 selectionEnd = Math.min(selectionEnd, text.length()); 140 selectionEnd = Math.min(selectionEnd, text.length());
185 compositionStart = Math.min(compositionStart, text.length()); 141 compositionStart = Math.min(compositionStart, text.length());
186 compositionEnd = Math.min(compositionEnd, text.length()); 142 compositionEnd = Math.min(compositionEnd, text.length());
187 143
188 Editable editable = getEditableInternal(); 144 String prevText = mEditable.toString();
189
190 String prevText = editable.toString();
191 boolean textUnchanged = prevText.equals(text); 145 boolean textUnchanged = prevText.equals(text);
192 146
193 if (!textUnchanged) { 147 if (!textUnchanged) {
194 editable.replace(0, editable.length(), text); 148 mEditable.replace(0, mEditable.length(), text);
195 } 149 }
196 150
197 Selection.setSelection(editable, selectionStart, selectionEnd); 151 Selection.setSelection(mEditable, selectionStart, selectionEnd);
198 152
199 if (compositionStart == compositionEnd) { 153 if (compositionStart == compositionEnd) {
200 removeComposingSpans(editable); 154 removeComposingSpans(mEditable);
201 } else { 155 } else {
202 super.setComposingRegion(compositionStart, compositionEnd); 156 super.setComposingRegion(compositionStart, compositionEnd);
203 } 157 }
204 updateSelectionIfRequired(); 158 updateSelectionIfRequired();
205 } 159 }
206 160
207 /** 161 /**
208 * @see BaseInputConnection#getEditable() 162 * @see BaseInputConnection#getEditable()
209 */ 163 */
210 @Override 164 @Override
211 public Editable getEditable() { 165 public Editable getEditable() {
212 Editable editable = getEditableInternal(); 166 Log.d(TAG, "getEditable: %s", ImeUtils.dumpEditable(mEditable));
213 Log.d(TAG, "getEditable: %s", dumpEditable(editable)); 167 return mEditable;
214 return editable;
215 }
216
217 private Editable getEditableInternal() {
218 return mImeAdapter.getEditable();
219 } 168 }
220 169
221 /** 170 /**
222 * Sends selection update to the InputMethodManager unless we are currently in a batch edit or 171 * Sends selection update to the InputMethodManager unless we are currently in a batch edit or
223 * if the exact same selection and composition update was sent already. 172 * if the exact same selection and composition update was sent already.
224 */ 173 */
225 private void updateSelectionIfRequired() { 174 private void updateSelectionIfRequired() {
226 if (mNumNestedBatchEdits != 0) return; 175 if (mNumNestedBatchEdits != 0) return;
227 Editable editable = getEditableInternal(); 176 int selectionStart = Selection.getSelectionStart(mEditable);
228 int selectionStart = Selection.getSelectionStart(editable); 177 int selectionEnd = Selection.getSelectionEnd(mEditable);
229 int selectionEnd = Selection.getSelectionEnd(editable); 178 int compositionStart = getComposingSpanStart(mEditable);
230 int compositionStart = getComposingSpanStart(editable); 179 int compositionEnd = getComposingSpanEnd(mEditable);
231 int compositionEnd = getComposingSpanEnd(editable);
232 // Avoid sending update if we sent an exact update already previously. 180 // Avoid sending update if we sent an exact update already previously.
233 if (mLastUpdateSelectionStart == selectionStart 181 if (mLastUpdateSelectionStart == selectionStart
234 && mLastUpdateSelectionEnd == selectionEnd 182 && mLastUpdateSelectionEnd == selectionEnd
235 && mLastUpdateCompositionStart == compositionStart 183 && mLastUpdateCompositionStart == compositionStart
236 && mLastUpdateCompositionEnd == compositionEnd) { 184 && mLastUpdateCompositionEnd == compositionEnd) {
237 return; 185 return;
238 } 186 }
239 Log.d(TAG, "updateSelectionIfRequired [%d %d] [%d %d]", selectionStart, selectionEnd, 187 Log.d(TAG, "updateSelectionIfRequired [%d %d] [%d %d]", selectionStart, selectionEnd,
240 compositionStart, compositionEnd); 188 compositionStart, compositionEnd);
241 // updateSelection should be called every time the selection or composit ion changes 189 // updateSelection should be called every time the selection or composit ion changes
242 // if it happens not within a batch edit, or at the end of each top leve l batch edit. 190 // if it happens not within a batch edit, or at the end of each top leve l batch edit.
243 mImeAdapter.updateSelection(selectionStart, selectionEnd, compositionSta rt, compositionEnd); 191 mImeAdapter.updateSelection(selectionStart, selectionEnd, compositionSta rt, compositionEnd);
244 mLastUpdateSelectionStart = selectionStart; 192 mLastUpdateSelectionStart = selectionStart;
245 mLastUpdateSelectionEnd = selectionEnd; 193 mLastUpdateSelectionEnd = selectionEnd;
246 mLastUpdateCompositionStart = compositionStart; 194 mLastUpdateCompositionStart = compositionStart;
247 mLastUpdateCompositionEnd = compositionEnd; 195 mLastUpdateCompositionEnd = compositionEnd;
248 } 196 }
249 197
250 /** 198 /**
251 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) 199 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int)
252 */ 200 */
253 @Override 201 @Override
254 public boolean setComposingText(CharSequence text, int newCursorPosition) { 202 public boolean setComposingText(CharSequence text, int newCursorPosition) {
255 Log.d(TAG, "setComposingText [%s] [%d]", text, newCursorPosition); 203 Log.d(TAG, "setComposingText [%s] [%d]", text, newCursorPosition);
256 mPendingAccent = 0; 204 mPendingAccent = 0;
257 205
258 Editable editable = getEditableInternal(); 206 int selectionStartAfterReplacement = BaseInputConnection.getComposingSpa nStart(mEditable);
259 int selectionStartAfterReplacement = BaseInputConnection.getComposingSpa nStart(editable);
260 if (selectionStartAfterReplacement == INVALID_COMPOSITION) { 207 if (selectionStartAfterReplacement == INVALID_COMPOSITION) {
261 selectionStartAfterReplacement = Selection.getSelectionStart(editabl e); 208 selectionStartAfterReplacement = Selection.getSelectionStart(mEditab le);
262 } 209 }
263 int selectionEndAfterReplacement = selectionStartAfterReplacement + text .length(); 210 int selectionEndAfterReplacement = selectionStartAfterReplacement + text .length();
264 211
265 super.setComposingText(text, newCursorPosition); 212 super.setComposingText(text, newCursorPosition);
266 213
267 // Due to an error in BaseInputConnection (b/21476564), the new cursor p osition 214 // Due to an error in BaseInputConnection (b/21476564), the new cursor p osition
268 // may not be correct when newCursorPosition != 1. We fix it here: 215 // may not be correct when newCursorPosition != 1. We fix it here:
269 if (newCursorPosition > 1) { 216 if (newCursorPosition > 1) {
270 int newPos = selectionEndAfterReplacement - 1 + newCursorPosition; 217 int newPos = selectionEndAfterReplacement - 1 + newCursorPosition;
271 int len = editable.length(); 218 int len = mEditable.length();
272 if (newPos > len) newPos = len; 219 if (newPos > len) newPos = len;
273 Selection.setSelection(editable, newPos); 220 Selection.setSelection(mEditable, newPos);
274 } else if (newCursorPosition <= 0) { 221 } else if (newCursorPosition <= 0) {
275 int newPos = selectionStartAfterReplacement + newCursorPosition; 222 int newPos = selectionStartAfterReplacement + newCursorPosition;
276 if (newPos < 0) newPos = 0; 223 if (newPos < 0) newPos = 0;
277 Selection.setSelection(editable, newPos); 224 Selection.setSelection(mEditable, newPos);
278 } 225 }
279 226
280 updateSelectionIfRequired(); 227 updateSelectionIfRequired();
281 return mImeAdapter.setComposingText(text, newCursorPosition); 228 return mImeAdapter.setComposingText(text, newCursorPosition);
282 } 229 }
283 230
284 /** 231 /**
285 * @see BaseInputConnection#commitText(java.lang.CharSequence, int) 232 * @see BaseInputConnection#commitText(java.lang.CharSequence, int)
286 */ 233 */
287 @Override 234 @Override
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 return mImeAdapter.performContextMenuAction(id); 267 return mImeAdapter.performContextMenuAction(id);
321 } 268 }
322 269
323 /** 270 /**
324 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest, 271 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest,
325 * int) 272 * int)
326 */ 273 */
327 @Override 274 @Override
328 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) { 275 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) {
329 Log.d(TAG, "getExtractedText"); 276 Log.d(TAG, "getExtractedText");
330 Editable editable = getEditableInternal();
331 ExtractedText et = new ExtractedText(); 277 ExtractedText et = new ExtractedText();
332 et.text = editable.toString(); 278 et.text = mEditable.toString();
333 et.partialEndOffset = editable.length(); 279 et.partialEndOffset = mEditable.length();
334 et.selectionStart = Selection.getSelectionStart(editable); 280 et.selectionStart = Selection.getSelectionStart(mEditable);
335 et.selectionEnd = Selection.getSelectionEnd(editable); 281 et.selectionEnd = Selection.getSelectionEnd(mEditable);
336 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0; 282 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
337 return et; 283 return et;
338 } 284 }
339 285
340 /** 286 /**
341 * @see BaseInputConnection#beginBatchEdit() 287 * @see BaseInputConnection#beginBatchEdit()
342 */ 288 */
343 @Override 289 @Override
344 public boolean beginBatchEdit() { 290 public boolean beginBatchEdit() {
345 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0)); 291 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 } 326 }
381 327
382 private boolean deleteSurroundingTextImpl( 328 private boolean deleteSurroundingTextImpl(
383 int beforeLength, int afterLength, boolean fromPhysicalKey) { 329 int beforeLength, int afterLength, boolean fromPhysicalKey) {
384 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey); 330 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey);
385 331
386 if (mPendingAccent != 0) { 332 if (mPendingAccent != 0) {
387 finishComposingText(); 333 finishComposingText();
388 } 334 }
389 335
390 Editable editable = getEditableInternal(); 336 int selectionStart = Selection.getSelectionStart(mEditable);
391 int selectionStart = Selection.getSelectionStart(editable); 337 int selectionEnd = Selection.getSelectionEnd(mEditable);
392 int selectionEnd = Selection.getSelectionEnd(editable);
393 int availableBefore = selectionStart; 338 int availableBefore = selectionStart;
394 int availableAfter = editable.length() - selectionEnd; 339 int availableAfter = mEditable.length() - selectionEnd;
395 beforeLength = Math.min(beforeLength, availableBefore); 340 beforeLength = Math.min(beforeLength, availableBefore);
396 afterLength = Math.min(afterLength, availableAfter); 341 afterLength = Math.min(afterLength, availableAfter);
397 342
398 // Adjust these values even before calling super.deleteSurroundingText() to be consistent 343 // Adjust these values even before calling super.deleteSurroundingText() to be consistent
399 // with the super class. 344 // with the super class.
400 if (isIndexBetweenUtf16SurrogatePair(editable, selectionStart - beforeLe ngth)) { 345 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionStart - beforeL ength)) {
401 beforeLength += 1; 346 beforeLength += 1;
402 } 347 }
403 if (isIndexBetweenUtf16SurrogatePair(editable, selectionEnd + afterLengt h)) { 348 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionEnd + afterLeng th)) {
404 afterLength += 1; 349 afterLength += 1;
405 } 350 }
406 351
407 super.deleteSurroundingText(beforeLength, afterLength); 352 super.deleteSurroundingText(beforeLength, afterLength);
408 updateSelectionIfRequired(); 353 updateSelectionIfRequired();
409 354
410 // If this was called due to a physical key, no need to generate a key e vent here as 355 // If this was called due to a physical key, no need to generate a key e vent here as
411 // the caller will take care of forwarding the original. 356 // the caller will take care of forwarding the original.
412 if (fromPhysicalKey) { 357 if (fromPhysicalKey) {
413 return true; 358 return true;
414 } 359 }
415 360
416 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength); 361 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
417 } 362 }
418 363
419 /** 364 /**
365 * @see ChromiumBaseInputConnection#sendKeyEventOnUiThread(KeyEvent)
366 */
367 @Override
368 public boolean sendKeyEventOnUiThread(KeyEvent event) {
369 return sendKeyEvent(event);
370 }
371
372 /**
420 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent) 373 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
421 */ 374 */
422 @Override 375 @Override
423 public boolean sendKeyEvent(KeyEvent event) { 376 public boolean sendKeyEvent(KeyEvent event) {
424 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(), 377 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(),
425 event.getUnicodeChar()); 378 event.getUnicodeChar());
426 379
427 int action = event.getAction(); 380 int action = event.getAction();
428 int keycode = event.getKeyCode(); 381 int keycode = event.getKeyCode();
429 int unicodeChar = event.getUnicodeChar(); 382 int unicodeChar = event.getUnicodeChar();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 return true; 426 return true;
474 } 427 }
475 428
476 /** 429 /**
477 * Update the Editable to reflect what Blink will do in response to the KeyD own for a 430 * Update the Editable to reflect what Blink will do in response to the KeyD own for a
478 * unicode-mapped key event. 431 * unicode-mapped key event.
479 * @param unicodeChar The Unicode character to update selection with. 432 * @param unicodeChar The Unicode character to update selection with.
480 */ 433 */
481 private void replaceSelectionWithUnicodeChar(int unicodeChar) { 434 private void replaceSelectionWithUnicodeChar(int unicodeChar) {
482 if (unicodeChar == 0) return; 435 if (unicodeChar == 0) return;
483 Editable editable = getEditableInternal(); 436 int selectionStart = Selection.getSelectionStart(mEditable);
484 int selectionStart = Selection.getSelectionStart(editable); 437 int selectionEnd = Selection.getSelectionEnd(mEditable);
485 int selectionEnd = Selection.getSelectionEnd(editable);
486 if (selectionStart > selectionEnd) { 438 if (selectionStart > selectionEnd) {
487 int temp = selectionStart; 439 int temp = selectionStart;
488 selectionStart = selectionEnd; 440 selectionStart = selectionEnd;
489 selectionEnd = temp; 441 selectionEnd = temp;
490 } 442 }
491 editable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar)); 443 mEditable.replace(selectionStart, selectionEnd, Character.toString((char ) unicodeChar));
492 updateSelectionIfRequired(); 444 updateSelectionIfRequired();
493 } 445 }
494 446
495 /** 447 /**
496 * @see BaseInputConnection#finishComposingText() 448 * @see BaseInputConnection#finishComposingText()
497 */ 449 */
498 @Override 450 @Override
499 public boolean finishComposingText() { 451 public boolean finishComposingText() {
500 Log.d(TAG, "finishComposingText"); 452 Log.d(TAG, "finishComposingText");
501 mPendingAccent = 0; 453 mPendingAccent = 0;
502 454
503 if (getComposingSpanStart(getEditableInternal()) 455 if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
504 == getComposingSpanEnd(getEditableInternal())) {
505 return true; 456 return true;
506 } 457 }
507 458
508 super.finishComposingText(); 459 super.finishComposingText();
509 updateSelectionIfRequired(); 460 updateSelectionIfRequired();
510 mImeAdapter.finishComposingText(); 461 mImeAdapter.finishComposingText();
511 462
512 return true; 463 return true;
513 } 464 }
514 465
515 /** 466 /**
516 * @see BaseInputConnection#setSelection(int, int) 467 * @see BaseInputConnection#setSelection(int, int)
517 */ 468 */
518 @Override 469 @Override
519 public boolean setSelection(int start, int end) { 470 public boolean setSelection(int start, int end) {
520 Log.d(TAG, "setSelection [%d %d]", start, end); 471 Log.d(TAG, "setSelection [%d %d]", start, end);
521 int textLength = getEditableInternal().length(); 472 int textLength = mEditable.length();
522 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true; 473 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true;
523 super.setSelection(start, end); 474 super.setSelection(start, end);
524 updateSelectionIfRequired(); 475 updateSelectionIfRequired();
525 return mImeAdapter.setEditableSelectionOffsets(start, end); 476 return mImeAdapter.setEditableSelectionOffsets(start, end);
526 } 477 }
527 478
528 /** 479 @Override
529 * Call this when restartInput() is called. 480 public void onRestartInputOnUiThread() {
530 */ 481 Log.d(TAG, "onRestartInputOnUiThread");
531 void onRestartInput() {
532 Log.d(TAG, "onRestartInput");
533 mNumNestedBatchEdits = 0; 482 mNumNestedBatchEdits = 0;
534 mPendingAccent = 0; 483 mPendingAccent = 0;
535 } 484 }
536 485
537 /** 486 /**
538 * @see BaseInputConnection#setComposingRegion(int, int) 487 * @see BaseInputConnection#setComposingRegion(int, int)
539 */ 488 */
540 @Override 489 @Override
541 public boolean setComposingRegion(int start, int end) { 490 public boolean setComposingRegion(int start, int end) {
542 Log.d(TAG, "setComposingRegion [%d %d]", start, end); 491 Log.d(TAG, "setComposingRegion [%d %d]", start, end);
543 Editable editable = getEditableInternal(); 492 int textLength = mEditable.length();
544 int textLength = editable.length();
545 int a = Math.min(start, end); 493 int a = Math.min(start, end);
546 int b = Math.max(start, end); 494 int b = Math.max(start, end);
547 if (a < 0) a = 0; 495 if (a < 0) a = 0;
548 if (b < 0) b = 0; 496 if (b < 0) b = 0;
549 if (a > textLength) a = textLength; 497 if (a > textLength) a = textLength;
550 if (b > textLength) b = textLength; 498 if (b > textLength) b = textLength;
551 499
552 if (a == b) { 500 if (a == b) {
553 removeComposingSpans(editable); 501 removeComposingSpans(mEditable);
554 } else { 502 } else {
555 super.setComposingRegion(a, b); 503 super.setComposingRegion(a, b);
556 } 504 }
557 updateSelectionIfRequired(); 505 updateSelectionIfRequired();
506 return mImeAdapter.setComposingRegion(a, b);
507 }
558 508
559 CharSequence regionText = null; 509 @Override
560 if (b > a) { 510 public void moveCursorToSelectionEndOnUiThread() {
561 regionText = editable.subSequence(a, b); 511 Log.d(TAG, "movecursorToEnd");
562 } 512 int selectionEnd = Selection.getSelectionEnd(mEditable);
563 return mImeAdapter.setComposingRegion(regionText, a, b); 513 setSelection(selectionEnd, selectionEnd);
514 }
515
516 @Override
517 public ThreadManager getThreadManager() {
518 return mThreadManager;
564 } 519 }
565 520
566 @VisibleForTesting 521 @VisibleForTesting
567 static class ImeState { 522 static class ImeState {
568 public final String text; 523 public final String text;
569 public final int selectionStart; 524 public final int selectionStart;
570 public final int selectionEnd; 525 public final int selectionEnd;
571 public final int compositionStart; 526 public final int compositionStart;
572 public final int compositionEnd; 527 public final int compositionEnd;
573 528
574 public ImeState(String text, int selectionStart, int selectionEnd, 529 public ImeState(String text, int selectionStart, int selectionEnd,
575 int compositionStart, int compositionEnd) { 530 int compositionStart, int compositionEnd) {
576 this.text = text; 531 this.text = text;
577 this.selectionStart = selectionStart; 532 this.selectionStart = selectionStart;
578 this.selectionEnd = selectionEnd; 533 this.selectionEnd = selectionEnd;
579 this.compositionStart = compositionStart; 534 this.compositionStart = compositionStart;
580 this.compositionEnd = compositionEnd; 535 this.compositionEnd = compositionEnd;
581 } 536 }
582 } 537 }
583 538
584 @VisibleForTesting 539 @VisibleForTesting
585 ImeState getImeStateForTesting() { 540 ImeState getImeStateForTesting() {
586 Editable editable = getEditableInternal(); 541 String text = mEditable.toString();
587 String text = editable.toString(); 542 int selectionStart = Selection.getSelectionStart(mEditable);
588 int selectionStart = Selection.getSelectionStart(editable); 543 int selectionEnd = Selection.getSelectionEnd(mEditable);
589 int selectionEnd = Selection.getSelectionEnd(editable); 544 int compositionStart = getComposingSpanStart(mEditable);
590 int compositionStart = getComposingSpanStart(editable); 545 int compositionEnd = getComposingSpanEnd(mEditable);
591 int compositionEnd = getComposingSpanEnd(editable);
592 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); 546 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd);
593 } 547 }
594 } 548 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698