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

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

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed a crash for LatinIME 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
aelias_OOO_until_Jul13 2016/01/23 03:21:39 Please add a comment mentioning that the "Replica"
Changwan Ryu 2016/01/26 03:25:28 Done.
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 ReplicaInputConnection
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 ReplicaInputConnection initializeAndGet(View view, ImeAdapter ime Adapter,
72 int inputType, int inputFlags, EditorInfo outAttrs) {
73 return new ReplicaInputConnection(
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 ReplicaInputConnection(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
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 return mImeAdapter.performContextMenuAction(id); 237 return mImeAdapter.performContextMenuAction(id);
290 } 238 }
291 239
292 /** 240 /**
293 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest, 241 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest,
294 * int) 242 * int)
295 */ 243 */
296 @Override 244 @Override
297 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) { 245 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) {
298 Log.d(TAG, "getExtractedText"); 246 Log.d(TAG, "getExtractedText");
299 Editable editable = getEditableInternal();
300 ExtractedText et = new ExtractedText(); 247 ExtractedText et = new ExtractedText();
301 et.text = editable.toString(); 248 et.text = mEditable.toString();
302 et.partialEndOffset = editable.length(); 249 et.partialEndOffset = mEditable.length();
303 et.selectionStart = Selection.getSelectionStart(editable); 250 et.selectionStart = Selection.getSelectionStart(mEditable);
304 et.selectionEnd = Selection.getSelectionEnd(editable); 251 et.selectionEnd = Selection.getSelectionEnd(mEditable);
305 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0; 252 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
306 return et; 253 return et;
307 } 254 }
308 255
309 /** 256 /**
310 * @see BaseInputConnection#beginBatchEdit() 257 * @see BaseInputConnection#beginBatchEdit()
311 */ 258 */
312 @Override 259 @Override
313 public boolean beginBatchEdit() { 260 public boolean beginBatchEdit() {
314 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0)); 261 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 } 296 }
350 297
351 private boolean deleteSurroundingTextImpl( 298 private boolean deleteSurroundingTextImpl(
352 int beforeLength, int afterLength, boolean fromPhysicalKey) { 299 int beforeLength, int afterLength, boolean fromPhysicalKey) {
353 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey); 300 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey);
354 301
355 if (mPendingAccent != 0) { 302 if (mPendingAccent != 0) {
356 finishComposingText(); 303 finishComposingText();
357 } 304 }
358 305
359 Editable editable = getEditableInternal(); 306 int selectionStart = Selection.getSelectionStart(mEditable);
360 int selectionStart = Selection.getSelectionStart(editable); 307 int selectionEnd = Selection.getSelectionEnd(mEditable);
361 int selectionEnd = Selection.getSelectionEnd(editable);
362 int availableBefore = selectionStart; 308 int availableBefore = selectionStart;
363 int availableAfter = editable.length() - selectionEnd; 309 int availableAfter = mEditable.length() - selectionEnd;
364 beforeLength = Math.min(beforeLength, availableBefore); 310 beforeLength = Math.min(beforeLength, availableBefore);
365 afterLength = Math.min(afterLength, availableAfter); 311 afterLength = Math.min(afterLength, availableAfter);
366 312
367 // Adjust these values even before calling super.deleteSurroundingText() to be consistent 313 // Adjust these values even before calling super.deleteSurroundingText() to be consistent
368 // with the super class. 314 // with the super class.
369 if (isIndexBetweenUtf16SurrogatePair(editable, selectionStart - beforeLe ngth)) { 315 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionStart - beforeL ength)) {
370 beforeLength += 1; 316 beforeLength += 1;
371 } 317 }
372 if (isIndexBetweenUtf16SurrogatePair(editable, selectionEnd + afterLengt h)) { 318 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionEnd + afterLeng th)) {
373 afterLength += 1; 319 afterLength += 1;
374 } 320 }
375 321
376 super.deleteSurroundingText(beforeLength, afterLength); 322 super.deleteSurroundingText(beforeLength, afterLength);
377 updateSelectionIfRequired(); 323 updateSelectionIfRequired();
378 324
379 // If this was called due to a physical key, no need to generate a key e vent here as 325 // If this was called due to a physical key, no need to generate a key e vent here as
380 // the caller will take care of forwarding the original. 326 // the caller will take care of forwarding the original.
381 if (fromPhysicalKey) { 327 if (fromPhysicalKey) {
382 return true; 328 return true;
383 } 329 }
384 330
385 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength); 331 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
386 } 332 }
387 333
388 /** 334 /**
335 * @see ChromiumBaseInputConnection#sendKeyEventOnUiThread(KeyEvent)
336 */
337 @Override
338 public boolean sendKeyEventOnUiThread(KeyEvent event) {
339 return sendKeyEvent(event);
340 }
341
342 /**
389 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent) 343 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
390 */ 344 */
391 @Override 345 @Override
392 public boolean sendKeyEvent(KeyEvent event) { 346 public boolean sendKeyEvent(KeyEvent event) {
393 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(), 347 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(),
394 event.getUnicodeChar()); 348 event.getUnicodeChar());
395 349
396 int action = event.getAction(); 350 int action = event.getAction();
397 int keycode = event.getKeyCode(); 351 int keycode = event.getKeyCode();
398 int unicodeChar = event.getUnicodeChar(); 352 int unicodeChar = event.getUnicodeChar();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 return true; 396 return true;
443 } 397 }
444 398
445 /** 399 /**
446 * Update the Editable to reflect what Blink will do in response to the KeyD own for a 400 * Update the Editable to reflect what Blink will do in response to the KeyD own for a
447 * unicode-mapped key event. 401 * unicode-mapped key event.
448 * @param unicodeChar The Unicode character to update selection with. 402 * @param unicodeChar The Unicode character to update selection with.
449 */ 403 */
450 private void replaceSelectionWithUnicodeChar(int unicodeChar) { 404 private void replaceSelectionWithUnicodeChar(int unicodeChar) {
451 if (unicodeChar == 0) return; 405 if (unicodeChar == 0) return;
452 Editable editable = getEditableInternal(); 406 int selectionStart = Selection.getSelectionStart(mEditable);
453 int selectionStart = Selection.getSelectionStart(editable); 407 int selectionEnd = Selection.getSelectionEnd(mEditable);
454 int selectionEnd = Selection.getSelectionEnd(editable);
455 if (selectionStart > selectionEnd) { 408 if (selectionStart > selectionEnd) {
456 int temp = selectionStart; 409 int temp = selectionStart;
457 selectionStart = selectionEnd; 410 selectionStart = selectionEnd;
458 selectionEnd = temp; 411 selectionEnd = temp;
459 } 412 }
460 editable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar)); 413 mEditable.replace(selectionStart, selectionEnd, Character.toString((char ) unicodeChar));
461 updateSelectionIfRequired(); 414 updateSelectionIfRequired();
462 } 415 }
463 416
464 /** 417 /**
465 * @see BaseInputConnection#finishComposingText() 418 * @see BaseInputConnection#finishComposingText()
466 */ 419 */
467 @Override 420 @Override
468 public boolean finishComposingText() { 421 public boolean finishComposingText() {
469 Log.d(TAG, "finishComposingText"); 422 Log.d(TAG, "finishComposingText");
470 mPendingAccent = 0; 423 mPendingAccent = 0;
471 424
472 if (getComposingSpanStart(getEditableInternal()) 425 if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
473 == getComposingSpanEnd(getEditableInternal())) {
474 return true; 426 return true;
475 } 427 }
476 428
477 super.finishComposingText(); 429 super.finishComposingText();
478 updateSelectionIfRequired(); 430 updateSelectionIfRequired();
479 mImeAdapter.finishComposingText(); 431 mImeAdapter.finishComposingText();
480 432
481 return true; 433 return true;
482 } 434 }
483 435
484 /** 436 /**
485 * @see BaseInputConnection#setSelection(int, int) 437 * @see BaseInputConnection#setSelection(int, int)
486 */ 438 */
487 @Override 439 @Override
488 public boolean setSelection(int start, int end) { 440 public boolean setSelection(int start, int end) {
489 Log.d(TAG, "setSelection [%d %d]", start, end); 441 Log.d(TAG, "setSelection [%d %d]", start, end);
490 int textLength = getEditableInternal().length(); 442 int textLength = mEditable.length();
491 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true; 443 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true;
492 super.setSelection(start, end); 444 super.setSelection(start, end);
493 updateSelectionIfRequired(); 445 updateSelectionIfRequired();
494 return mImeAdapter.setEditableSelectionOffsets(start, end); 446 return mImeAdapter.setEditableSelectionOffsets(start, end);
495 } 447 }
496 448
497 /** 449 @Override
498 * Call this when restartInput() is called. 450 public void onRestartInputOnUiThread() {
499 */ 451 Log.d(TAG, "onRestartInputOnUiThread");
500 void onRestartInput() {
501 Log.d(TAG, "onRestartInput");
502 mNumNestedBatchEdits = 0; 452 mNumNestedBatchEdits = 0;
503 mPendingAccent = 0; 453 mPendingAccent = 0;
504 } 454 }
505 455
506 /** 456 /**
507 * @see BaseInputConnection#setComposingRegion(int, int) 457 * @see BaseInputConnection#setComposingRegion(int, int)
508 */ 458 */
509 @Override 459 @Override
510 public boolean setComposingRegion(int start, int end) { 460 public boolean setComposingRegion(int start, int end) {
511 Log.d(TAG, "setComposingRegion [%d %d]", start, end); 461 Log.d(TAG, "setComposingRegion [%d %d]", start, end);
512 Editable editable = getEditableInternal(); 462 int textLength = mEditable.length();
513 int textLength = editable.length();
514 int a = Math.min(start, end); 463 int a = Math.min(start, end);
515 int b = Math.max(start, end); 464 int b = Math.max(start, end);
516 if (a < 0) a = 0; 465 if (a < 0) a = 0;
517 if (b < 0) b = 0; 466 if (b < 0) b = 0;
518 if (a > textLength) a = textLength; 467 if (a > textLength) a = textLength;
519 if (b > textLength) b = textLength; 468 if (b > textLength) b = textLength;
520 469
521 if (a == b) { 470 if (a == b) {
522 removeComposingSpans(editable); 471 removeComposingSpans(mEditable);
523 } else { 472 } else {
524 super.setComposingRegion(a, b); 473 super.setComposingRegion(a, b);
525 } 474 }
526 updateSelectionIfRequired(); 475 updateSelectionIfRequired();
476 return mImeAdapter.setComposingRegion(a, b);
477 }
527 478
528 CharSequence regionText = null; 479 @Override
529 if (b > a) { 480 public void moveCursorToSelectionEndOnUiThread() {
530 regionText = editable.subSequence(a, b); 481 Log.d(TAG, "movecursorToEnd");
531 } 482 int selectionEnd = Selection.getSelectionEnd(mEditable);
532 return mImeAdapter.setComposingRegion(regionText, a, b); 483 setSelection(selectionEnd, selectionEnd);
484 }
485
486 @Override
487 public ThreadManager getThreadManager() {
488 return mThreadManager;
533 } 489 }
534 490
535 @VisibleForTesting 491 @VisibleForTesting
536 static class ImeState { 492 static class ImeState {
537 public final String text; 493 public final String text;
538 public final int selectionStart; 494 public final int selectionStart;
539 public final int selectionEnd; 495 public final int selectionEnd;
540 public final int compositionStart; 496 public final int compositionStart;
541 public final int compositionEnd; 497 public final int compositionEnd;
542 498
543 public ImeState(String text, int selectionStart, int selectionEnd, 499 public ImeState(String text, int selectionStart, int selectionEnd,
544 int compositionStart, int compositionEnd) { 500 int compositionStart, int compositionEnd) {
545 this.text = text; 501 this.text = text;
546 this.selectionStart = selectionStart; 502 this.selectionStart = selectionStart;
547 this.selectionEnd = selectionEnd; 503 this.selectionEnd = selectionEnd;
548 this.compositionStart = compositionStart; 504 this.compositionStart = compositionStart;
549 this.compositionEnd = compositionEnd; 505 this.compositionEnd = compositionEnd;
550 } 506 }
551 } 507 }
552 508
553 @VisibleForTesting 509 @VisibleForTesting
554 ImeState getImeStateForTesting() { 510 ImeState getImeStateForTesting() {
555 Editable editable = getEditableInternal(); 511 String text = mEditable.toString();
556 String text = editable.toString(); 512 int selectionStart = Selection.getSelectionStart(mEditable);
557 int selectionStart = Selection.getSelectionStart(editable); 513 int selectionEnd = Selection.getSelectionEnd(mEditable);
558 int selectionEnd = Selection.getSelectionEnd(editable); 514 int compositionStart = getComposingSpanStart(mEditable);
559 int compositionStart = getComposingSpanStart(editable); 515 int compositionEnd = getComposingSpanEnd(mEditable);
560 int compositionEnd = getComposingSpanEnd(editable);
561 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); 516 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd);
562 } 517 }
563 } 518 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698