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

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: handles render crash and navigation 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 /** 31 /**
34 * Selection value should be -1 if not known. See EditorInfo.java for detail s. 32 * Selection value should be -1 if not known. See EditorInfo.java for detail s.
35 */ 33 */
36 public static final int INVALID_SELECTION = -1; 34 public static final int INVALID_SELECTION = -1;
35
37 public static final int INVALID_COMPOSITION = -1; 36 public static final int INVALID_COMPOSITION = -1;
38 37
39 private final ImeAdapter mImeAdapter; 38 private final ImeAdapter mImeAdapter;
40 39
40 // This holds the state of editable text (e.g. contents of <input>, contente ditable) of
41 // a focused element.
42 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
43 // state must be reflected to this to keep consistency.
44 private final Editable mEditable;
45
41 private boolean mSingleLine; 46 private boolean mSingleLine;
42 private int mNumNestedBatchEdits = 0; 47 private int mNumNestedBatchEdits = 0;
43 private int mPendingAccent; 48 private int mPendingAccent;
49 private final ThreadManager mThreadManager;
44 50
45 private int mLastUpdateSelectionStart = INVALID_SELECTION; 51 /**
46 private int mLastUpdateSelectionEnd = INVALID_SELECTION; 52 * Default factory for AdapterInputConnection classes.
47 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; 53 */
48 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; 54 static class Factory implements ChromiumBaseInputConnection.Factory {
55 // Note: we share Editable among input connections so that data remains the same on
56 // switching inputs. However, the downside is that initial value cannot be correct, and
57 // wrong value will be used when jumping from one input to another.
58 protected final Editable mEditable;
Ted C 2016/02/02 23:14:43 why not private?
Changwan Ryu 2016/02/11 16:21:08 Done.
59 private final ThreadManager mThreadManager;
60
61 Factory() {
62 mThreadManager = new ThreadManager(new Handler(Looper.getMainLooper( )));
63 mEditable = Editable.Factory.getInstance().newEditable("");
64 Selection.setSelection(mEditable, 0);
65 }
66
67 @Override
68 public ReplicaInputConnection initializeAndGet(View view, ImeAdapter ime Adapter,
69 int inputType, int inputFlags, EditorInfo outAttrs) {
70 return new ReplicaInputConnection(
71 view, imeAdapter, mThreadManager, mEditable, inputType, inpu tFlags, outAttrs);
72 }
73
74 @Override
75 public ThreadManager getThreadManager() {
76 return mThreadManager;
77 }
78 }
49 79
50 @VisibleForTesting 80 @VisibleForTesting
51 AdapterInputConnection(View view, ImeAdapter imeAdapter, int initialSelStart , int initialSelEnd, 81 ReplicaInputConnection(View view, ImeAdapter imeAdapter, ThreadManager threa dManager,
52 EditorInfo outAttrs) { 82 Editable editable, int inputType, int inputFlags, EditorInfo outAttr s) {
53 super(view, true); 83 super(view, true);
54 mImeAdapter = imeAdapter; 84 mImeAdapter = imeAdapter;
55 mImeAdapter.setInputConnection(this); 85 mEditable = editable;
86 mThreadManager = threadManager;
56 87
57 mSingleLine = true; 88 int initialSelStart = Selection.getSelectionStart(editable);
58 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN 89 int initialSelEnd = Selection.getSelectionEnd(editable);
59 | EditorInfo.IME_FLAG_NO_EXTRACT_UI; 90 ImeUtils.computeEditorInfo(inputType, inputFlags, initialSelStart, initi alSelEnd, outAttrs);
60 outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
61 | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
62 91
63 int inputType = imeAdapter.getTextInputType(); 92 Log.d(TAG, "Constructor called with outAttrs: %s", ImeUtils.dumpEditorIn fo(outAttrs));
64 int inputFlags = imeAdapter.getTextInputFlags();
65 if ((inputFlags & WebTextInputFlags.AutocompleteOff) != 0) {
66 outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
67 }
68
69 if (inputType == TextInputType.TEXT) {
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 } 93 }
137 94
138 private static String dumpEditorInfo(EditorInfo editorInfo) { 95 @Override
139 StringBuilder builder = new StringBuilder(); 96 public void updateStateOnUiThread(String text, int selectionStart, int selec tionEnd,
140 StringBuilderPrinter printer = new StringBuilderPrinter(builder); 97 int compositionStart, int compositionEnd, boolean singleLine, boolea n isNonImeChange) {
141 editorInfo.dump(printer, ""); 98 Log.d(TAG, "updateState [%s] [%s %s] [%s %s] [%b] [%b]", text, selection Start,
142 return builder.toString(); 99 selectionEnd, compositionStart, compositionEnd, singleLine, isNo nImeChange);
143 } 100 mSingleLine = singleLine;
144 101
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 }
153
154 /**
155 * 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
157 * getEditable() method. If the text has not changed, this also calls update Selection on the
158 * InputMethodManager.
159 *
160 * @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
162 * there is no selection.
163 * @param selectionEnd The character offset of the selection end, or the car et position if there
164 * is no selection.
165 * @param compositionStart The character offset of the composition start, or -1 if there is no
166 * composition.
167 * @param compositionEnd The character offset of the composition end, or -1 if there is no
168 * selection.
169 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript).
170 */
171 @VisibleForTesting
172 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart,
173 int compositionEnd, boolean isNonImeChange) {
174 Log.d(TAG, "updateState [%s] [%s %s] [%s %s] [%b]", text, selectionStart ,
175 selectionEnd, compositionStart, compositionEnd, isNonImeChange);
176 // If this update is from the IME, no further state modification is nece ssary because the 102 // 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. 103 // state should have been updated already by the IM framework directly.
178 if (!isNonImeChange) return; 104 if (!isNonImeChange) return;
179 105
180 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces. 106 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces.
181 text = text.replace('\u00A0', ' '); 107 text = text.replace('\u00A0', ' ');
182 108
183 selectionStart = Math.min(selectionStart, text.length()); 109 selectionStart = Math.min(selectionStart, text.length());
184 selectionEnd = Math.min(selectionEnd, text.length()); 110 selectionEnd = Math.min(selectionEnd, text.length());
185 compositionStart = Math.min(compositionStart, text.length()); 111 compositionStart = Math.min(compositionStart, text.length());
186 compositionEnd = Math.min(compositionEnd, text.length()); 112 compositionEnd = Math.min(compositionEnd, text.length());
187 113
188 Editable editable = getEditableInternal(); 114 String prevText = mEditable.toString();
189
190 String prevText = editable.toString();
191 boolean textUnchanged = prevText.equals(text); 115 boolean textUnchanged = prevText.equals(text);
192 116
193 if (!textUnchanged) { 117 if (!textUnchanged) {
194 editable.replace(0, editable.length(), text); 118 mEditable.replace(0, mEditable.length(), text);
195 } 119 }
196 120
197 Selection.setSelection(editable, selectionStart, selectionEnd); 121 Selection.setSelection(mEditable, selectionStart, selectionEnd);
198 122
199 if (compositionStart == compositionEnd) { 123 if (compositionStart == compositionEnd) {
200 removeComposingSpans(editable); 124 removeComposingSpans(mEditable);
201 } else { 125 } else {
202 super.setComposingRegion(compositionStart, compositionEnd); 126 super.setComposingRegion(compositionStart, compositionEnd);
203 } 127 }
204 updateSelectionIfRequired(); 128 updateSelectionIfRequired();
205 } 129 }
206 130
207 /** 131 /**
208 * @see BaseInputConnection#getEditable() 132 * @see BaseInputConnection#getEditable()
209 */ 133 */
210 @Override 134 @Override
211 public Editable getEditable() { 135 public Editable getEditable() {
212 Editable editable = getEditableInternal(); 136 Log.d(TAG, "getEditable: %s", ImeUtils.dumpEditable(mEditable));
213 Log.d(TAG, "getEditable: %s", dumpEditable(editable)); 137 return mEditable;
214 return editable;
215 }
216
217 private Editable getEditableInternal() {
218 return mImeAdapter.getEditable();
219 } 138 }
220 139
221 /** 140 /**
222 * Sends selection update to the InputMethodManager unless we are currently in a batch edit or 141 * 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. 142 * if the exact same selection and composition update was sent already.
224 */ 143 */
225 private void updateSelectionIfRequired() { 144 private void updateSelectionIfRequired() {
226 if (mNumNestedBatchEdits != 0) return; 145 if (mNumNestedBatchEdits != 0) return;
227 Editable editable = getEditableInternal(); 146 int selectionStart = Selection.getSelectionStart(mEditable);
228 int selectionStart = Selection.getSelectionStart(editable); 147 int selectionEnd = Selection.getSelectionEnd(mEditable);
229 int selectionEnd = Selection.getSelectionEnd(editable); 148 int compositionStart = getComposingSpanStart(mEditable);
230 int compositionStart = getComposingSpanStart(editable); 149 int compositionEnd = getComposingSpanEnd(mEditable);
231 int compositionEnd = getComposingSpanEnd(editable);
232 // Avoid sending update if we sent an exact update already previously. 150 // Avoid sending update if we sent an exact update already previously.
233 if (mLastUpdateSelectionStart == selectionStart
234 && mLastUpdateSelectionEnd == selectionEnd
235 && mLastUpdateCompositionStart == compositionStart
236 && mLastUpdateCompositionEnd == compositionEnd) {
237 return;
238 }
239 Log.d(TAG, "updateSelectionIfRequired [%d %d] [%d %d]", selectionStart, selectionEnd, 151 Log.d(TAG, "updateSelectionIfRequired [%d %d] [%d %d]", selectionStart, selectionEnd,
240 compositionStart, compositionEnd); 152 compositionStart, compositionEnd);
241 // updateSelection should be called every time the selection or composit ion changes 153 // 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. 154 // 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); 155 mImeAdapter.updateSelection(selectionStart, selectionEnd, compositionSta rt, compositionEnd);
244 mLastUpdateSelectionStart = selectionStart;
245 mLastUpdateSelectionEnd = selectionEnd;
246 mLastUpdateCompositionStart = compositionStart;
247 mLastUpdateCompositionEnd = compositionEnd;
248 } 156 }
249 157
250 /** 158 /**
251 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) 159 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int)
252 */ 160 */
253 @Override 161 @Override
254 public boolean setComposingText(CharSequence text, int newCursorPosition) { 162 public boolean setComposingText(CharSequence text, int newCursorPosition) {
255 Log.d(TAG, "setComposingText [%s] [%d]", text, newCursorPosition); 163 Log.d(TAG, "setComposingText [%s] [%d]", text, newCursorPosition);
256 mPendingAccent = 0; 164 mPendingAccent = 0;
257 super.setComposingText(text, newCursorPosition); 165 super.setComposingText(text, newCursorPosition);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 return mImeAdapter.performContextMenuAction(id); 197 return mImeAdapter.performContextMenuAction(id);
290 } 198 }
291 199
292 /** 200 /**
293 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest, 201 * @see BaseInputConnection#getExtractedText(android.view.inputmethod.Extrac tedTextRequest,
294 * int) 202 * int)
295 */ 203 */
296 @Override 204 @Override
297 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) { 205 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) {
298 Log.d(TAG, "getExtractedText"); 206 Log.d(TAG, "getExtractedText");
299 Editable editable = getEditableInternal();
300 ExtractedText et = new ExtractedText(); 207 ExtractedText et = new ExtractedText();
301 et.text = editable.toString(); 208 et.text = mEditable.toString();
302 et.partialEndOffset = editable.length(); 209 et.partialEndOffset = mEditable.length();
303 et.selectionStart = Selection.getSelectionStart(editable); 210 et.selectionStart = Selection.getSelectionStart(mEditable);
304 et.selectionEnd = Selection.getSelectionEnd(editable); 211 et.selectionEnd = Selection.getSelectionEnd(mEditable);
305 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0; 212 et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
306 return et; 213 return et;
307 } 214 }
308 215
309 /** 216 /**
310 * @see BaseInputConnection#beginBatchEdit() 217 * @see BaseInputConnection#beginBatchEdit()
311 */ 218 */
312 @Override 219 @Override
313 public boolean beginBatchEdit() { 220 public boolean beginBatchEdit() {
314 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0)); 221 Log.d(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 } 256 }
350 257
351 private boolean deleteSurroundingTextImpl( 258 private boolean deleteSurroundingTextImpl(
352 int beforeLength, int afterLength, boolean fromPhysicalKey) { 259 int beforeLength, int afterLength, boolean fromPhysicalKey) {
353 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey); 260 Log.d(TAG, "deleteSurroundingText [%d %d %b]", beforeLength, afterLength , fromPhysicalKey);
354 261
355 if (mPendingAccent != 0) { 262 if (mPendingAccent != 0) {
356 finishComposingText(); 263 finishComposingText();
357 } 264 }
358 265
359 Editable editable = getEditableInternal(); 266 int selectionStart = Selection.getSelectionStart(mEditable);
360 int selectionStart = Selection.getSelectionStart(editable); 267 int selectionEnd = Selection.getSelectionEnd(mEditable);
361 int selectionEnd = Selection.getSelectionEnd(editable);
362 int availableBefore = selectionStart; 268 int availableBefore = selectionStart;
363 int availableAfter = editable.length() - selectionEnd; 269 int availableAfter = mEditable.length() - selectionEnd;
364 beforeLength = Math.min(beforeLength, availableBefore); 270 beforeLength = Math.min(beforeLength, availableBefore);
365 afterLength = Math.min(afterLength, availableAfter); 271 afterLength = Math.min(afterLength, availableAfter);
366 272
367 // Adjust these values even before calling super.deleteSurroundingText() to be consistent 273 // Adjust these values even before calling super.deleteSurroundingText() to be consistent
368 // with the super class. 274 // with the super class.
369 if (isIndexBetweenUtf16SurrogatePair(editable, selectionStart - beforeLe ngth)) { 275 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionStart - beforeL ength)) {
370 beforeLength += 1; 276 beforeLength += 1;
371 } 277 }
372 if (isIndexBetweenUtf16SurrogatePair(editable, selectionEnd + afterLengt h)) { 278 if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionEnd + afterLeng th)) {
373 afterLength += 1; 279 afterLength += 1;
374 } 280 }
375 281
376 super.deleteSurroundingText(beforeLength, afterLength); 282 super.deleteSurroundingText(beforeLength, afterLength);
377 updateSelectionIfRequired(); 283 updateSelectionIfRequired();
378 284
379 // If this was called due to a physical key, no need to generate a key e vent here as 285 // 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. 286 // the caller will take care of forwarding the original.
381 if (fromPhysicalKey) { 287 if (fromPhysicalKey) {
382 return true; 288 return true;
383 } 289 }
384 290
385 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength); 291 return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
386 } 292 }
387 293
388 /** 294 /**
295 * @see ChromiumBaseInputConnection#sendKeyEventOnUiThread(KeyEvent)
296 */
297 @Override
298 public boolean sendKeyEventOnUiThread(KeyEvent event) {
299 return sendKeyEvent(event);
300 }
301
302 /**
389 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent) 303 * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
390 */ 304 */
391 @Override 305 @Override
392 public boolean sendKeyEvent(KeyEvent event) { 306 public boolean sendKeyEvent(KeyEvent event) {
393 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(), 307 Log.d(TAG, "sendKeyEvent [%d] [%d] [%d]", event.getAction(), event.getKe yCode(),
394 event.getUnicodeChar()); 308 event.getUnicodeChar());
395 309
396 int action = event.getAction(); 310 int action = event.getAction();
397 int keycode = event.getKeyCode(); 311 int keycode = event.getKeyCode();
398 int unicodeChar = event.getUnicodeChar(); 312 int unicodeChar = event.getUnicodeChar();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 return true; 356 return true;
443 } 357 }
444 358
445 /** 359 /**
446 * Update the Editable to reflect what Blink will do in response to the KeyD own for a 360 * Update the Editable to reflect what Blink will do in response to the KeyD own for a
447 * unicode-mapped key event. 361 * unicode-mapped key event.
448 * @param unicodeChar The Unicode character to update selection with. 362 * @param unicodeChar The Unicode character to update selection with.
449 */ 363 */
450 private void replaceSelectionWithUnicodeChar(int unicodeChar) { 364 private void replaceSelectionWithUnicodeChar(int unicodeChar) {
451 if (unicodeChar == 0) return; 365 if (unicodeChar == 0) return;
452 Editable editable = getEditableInternal(); 366 int selectionStart = Selection.getSelectionStart(mEditable);
453 int selectionStart = Selection.getSelectionStart(editable); 367 int selectionEnd = Selection.getSelectionEnd(mEditable);
454 int selectionEnd = Selection.getSelectionEnd(editable);
455 if (selectionStart > selectionEnd) { 368 if (selectionStart > selectionEnd) {
456 int temp = selectionStart; 369 int temp = selectionStart;
457 selectionStart = selectionEnd; 370 selectionStart = selectionEnd;
458 selectionEnd = temp; 371 selectionEnd = temp;
459 } 372 }
460 editable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar)); 373 mEditable.replace(selectionStart, selectionEnd, Character.toString((char ) unicodeChar));
461 updateSelectionIfRequired(); 374 updateSelectionIfRequired();
462 } 375 }
463 376
464 /** 377 /**
465 * @see BaseInputConnection#finishComposingText() 378 * @see BaseInputConnection#finishComposingText()
466 */ 379 */
467 @Override 380 @Override
468 public boolean finishComposingText() { 381 public boolean finishComposingText() {
469 Log.d(TAG, "finishComposingText"); 382 Log.d(TAG, "finishComposingText");
470 mPendingAccent = 0; 383 mPendingAccent = 0;
471 384
472 if (getComposingSpanStart(getEditableInternal()) 385 if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
473 == getComposingSpanEnd(getEditableInternal())) {
474 return true; 386 return true;
475 } 387 }
476 388
477 super.finishComposingText(); 389 super.finishComposingText();
478 updateSelectionIfRequired(); 390 updateSelectionIfRequired();
479 mImeAdapter.finishComposingText(); 391 mImeAdapter.finishComposingText();
480 392
481 return true; 393 return true;
482 } 394 }
483 395
484 /** 396 /**
485 * @see BaseInputConnection#setSelection(int, int) 397 * @see BaseInputConnection#setSelection(int, int)
486 */ 398 */
487 @Override 399 @Override
488 public boolean setSelection(int start, int end) { 400 public boolean setSelection(int start, int end) {
489 Log.d(TAG, "setSelection [%d %d]", start, end); 401 Log.d(TAG, "setSelection [%d %d]", start, end);
490 int textLength = getEditableInternal().length(); 402 int textLength = mEditable.length();
491 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true; 403 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true;
492 super.setSelection(start, end); 404 super.setSelection(start, end);
493 updateSelectionIfRequired(); 405 updateSelectionIfRequired();
494 return mImeAdapter.setEditableSelectionOffsets(start, end); 406 return mImeAdapter.setEditableSelectionOffsets(start, end);
495 } 407 }
496 408
497 /** 409 /**
498 * Call this when restartInput() is called.
499 */
500 void onRestartInput() {
501 Log.d(TAG, "onRestartInput");
502 mNumNestedBatchEdits = 0;
503 mPendingAccent = 0;
504 }
505
506 /**
507 * @see BaseInputConnection#setComposingRegion(int, int) 410 * @see BaseInputConnection#setComposingRegion(int, int)
508 */ 411 */
509 @Override 412 @Override
510 public boolean setComposingRegion(int start, int end) { 413 public boolean setComposingRegion(int start, int end) {
511 Log.d(TAG, "setComposingRegion [%d %d]", start, end); 414 Log.d(TAG, "setComposingRegion [%d %d]", start, end);
512 Editable editable = getEditableInternal(); 415 int textLength = mEditable.length();
513 int textLength = editable.length();
514 int a = Math.min(start, end); 416 int a = Math.min(start, end);
515 int b = Math.max(start, end); 417 int b = Math.max(start, end);
516 if (a < 0) a = 0; 418 if (a < 0) a = 0;
517 if (b < 0) b = 0; 419 if (b < 0) b = 0;
518 if (a > textLength) a = textLength; 420 if (a > textLength) a = textLength;
519 if (b > textLength) b = textLength; 421 if (b > textLength) b = textLength;
520 422
521 if (a == b) { 423 if (a == b) {
522 removeComposingSpans(editable); 424 removeComposingSpans(mEditable);
523 } else { 425 } else {
524 super.setComposingRegion(a, b); 426 super.setComposingRegion(a, b);
525 } 427 }
526 updateSelectionIfRequired(); 428 updateSelectionIfRequired();
429 return mImeAdapter.setComposingRegion(a, b);
430 }
527 431
528 CharSequence regionText = null; 432 @Override
529 if (b > a) { 433 public void onRestartInputOnUiThread() {
530 regionText = editable.subSequence(a, b); 434 Log.d(TAG, "onRestartInputOnUiThread");
531 } 435 mNumNestedBatchEdits = 0;
532 return mImeAdapter.setComposingRegion(regionText, a, b); 436 mPendingAccent = 0;
437 }
438
439 @Override
440 public void moveCursorToSelectionEndOnUiThread() {
441 Log.d(TAG, "movecursorToEnd");
442 int selectionEnd = Selection.getSelectionEnd(mEditable);
443 setSelection(selectionEnd, selectionEnd);
444 }
445
446 @Override
447 public void unblockOnUiThread() {}
448
449 @Override
450 public ThreadManager getThreadManager() {
451 return mThreadManager;
533 } 452 }
534 453
535 @VisibleForTesting 454 @VisibleForTesting
536 static class ImeState { 455 static class ImeState {
537 public final String text; 456 public final String text;
538 public final int selectionStart; 457 public final int selectionStart;
539 public final int selectionEnd; 458 public final int selectionEnd;
540 public final int compositionStart; 459 public final int compositionStart;
541 public final int compositionEnd; 460 public final int compositionEnd;
542 461
543 public ImeState(String text, int selectionStart, int selectionEnd, 462 public ImeState(String text, int selectionStart, int selectionEnd,
544 int compositionStart, int compositionEnd) { 463 int compositionStart, int compositionEnd) {
545 this.text = text; 464 this.text = text;
546 this.selectionStart = selectionStart; 465 this.selectionStart = selectionStart;
547 this.selectionEnd = selectionEnd; 466 this.selectionEnd = selectionEnd;
548 this.compositionStart = compositionStart; 467 this.compositionStart = compositionStart;
549 this.compositionEnd = compositionEnd; 468 this.compositionEnd = compositionEnd;
550 } 469 }
551 } 470 }
552 471
553 @VisibleForTesting 472 @VisibleForTesting
554 ImeState getImeStateForTesting() { 473 ImeState getImeStateForTesting() {
555 Editable editable = getEditableInternal(); 474 String text = mEditable.toString();
556 String text = editable.toString(); 475 int selectionStart = Selection.getSelectionStart(mEditable);
557 int selectionStart = Selection.getSelectionStart(editable); 476 int selectionEnd = Selection.getSelectionEnd(mEditable);
558 int selectionEnd = Selection.getSelectionEnd(editable); 477 int compositionStart = getComposingSpanStart(mEditable);
559 int compositionStart = getComposingSpanStart(editable); 478 int compositionEnd = getComposingSpanEnd(mEditable);
560 int compositionEnd = getComposingSpanEnd(editable);
561 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); 479 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd);
562 } 480 }
563 } 481 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698