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

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

Powered by Google App Engine
This is Rietveld 408576698