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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java

Issue 2896143002: Move batchedit related logics into InputConnection (Closed)
Patch Set: test fixed in another CL and rebased Created 3 years, 7 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
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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.chrome.browser.omnibox; 5 package org.chromium.chrome.browser.omnibox;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.graphics.Rect; 8 import android.graphics.Rect;
9 import android.os.StrictMode; 9 import android.os.StrictMode;
10 import android.text.Editable; 10 import android.text.Editable;
(...skipping 25 matching lines...) Expand all
36 36
37 private final AutocompleteSpan mAutocompleteSpan; 37 private final AutocompleteSpan mAutocompleteSpan;
38 private final AccessibilityManager mAccessibilityManager; 38 private final AccessibilityManager mAccessibilityManager;
39 39
40 /** 40 /**
41 * Whether default TextView scrolling should be disabled because autocomplet e has been added. 41 * Whether default TextView scrolling should be disabled because autocomplet e has been added.
42 * This allows the user entered text to be shown instead of the end of the a utocomplete. 42 * This allows the user entered text to be shown instead of the end of the a utocomplete.
43 */ 43 */
44 private boolean mDisableTextScrollingFromAutocomplete; 44 private boolean mDisableTextScrollingFromAutocomplete;
45 45
46 private boolean mInBatchEditMode; 46 private int mBatchEditNestCount;
Ted C 2017/05/26 23:43:45 The thing I struggle with is that this moves more
Changwan Ryu 2017/06/05 19:07:39 Hmm.. I didn’t really think much about how to spli
47 private int mBeforeBatchEditAutocompleteIndex = -1; 47 private int mBeforeBatchEditAutocompleteIndex = -1;
48 private String mBeforeBatchEditFullText; 48 private String mBeforeBatchEditFullText;
49 private boolean mSelectionChangedInBatchMode; 49 private boolean mSelectionChangedInBatchMode;
50 private boolean mTextDeletedInBatchMode; 50 private boolean mTextDeletedInBatchMode;
51 51
52 // Set to true when the text is modified programmatically. Initially set to true until the old 52 // Set to true when the text is modified programmatically. Initially set to true until the old
53 // state has been loaded. 53 // state has been loaded.
54 private boolean mIgnoreTextChangeFromAutocomplete = true; 54 private boolean mIgnoreTextChangeFromAutocomplete = true;
55 private boolean mLastEditWasDelete; 55 private boolean mLastEditWasDelete;
56 56
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 int expectedSelectionStart = getText().getSpanStart(mAutocompleteSpan); 91 int expectedSelectionStart = getText().getSpanStart(mAutocompleteSpan);
92 int expectedSelectionEnd = getText().length(); 92 int expectedSelectionEnd = getText().length();
93 if (expectedSelectionStart < 0) { 93 if (expectedSelectionStart < 0) {
94 expectedSelectionStart = expectedSelectionEnd; 94 expectedSelectionStart = expectedSelectionEnd;
95 } 95 }
96 96
97 return selectionStart == expectedSelectionStart && selectionEnd == expec tedSelectionEnd; 97 return selectionStart == expectedSelectionStart && selectionEnd == expec tedSelectionEnd;
98 } 98 }
99 99
100 /** 100 /**
101 * @return Whether the URL is currently in batch edit mode triggered by an I ME. No external
102 * text changes should be triggered while this is true.
103 */
104 // isInBatchEditMode is a package protected method on TextView, so we intent ionally chose
105 // a different name.
106 private boolean isHandlingBatchInput() {
107 return mInBatchEditMode;
108 }
109
110 /**
111 * @return The user text without the autocomplete text. 101 * @return The user text without the autocomplete text.
112 */ 102 */
113 public String getTextWithoutAutocomplete() { 103 public String getTextWithoutAutocomplete() {
114 int autoCompleteIndex = getText().getSpanStart(mAutocompleteSpan); 104 int autoCompleteIndex = getText().getSpanStart(mAutocompleteSpan);
115 if (autoCompleteIndex < 0) { 105 if (autoCompleteIndex < 0) {
116 return getTextWithAutocomplete(); 106 return getTextWithAutocomplete();
117 } else { 107 } else {
118 return getTextWithAutocomplete().substring(0, autoCompleteIndex); 108 return getTextWithAutocomplete().substring(0, autoCompleteIndex);
119 } 109 }
120 } 110 }
121 111
122 /** @return Whether any autocomplete information is specified on the current text. */ 112 /** @return Whether any autocomplete information is specified on the current text. */
123 @VisibleForTesting 113 @VisibleForTesting
124 public boolean hasAutocomplete() { 114 public boolean hasAutocomplete() {
125 return getText().getSpanStart(mAutocompleteSpan) >= 0 115 return getText().getSpanStart(mAutocompleteSpan) >= 0
126 || mAutocompleteSpan.mAutocompleteText != null 116 || mAutocompleteSpan.mAutocompleteText != null
127 || mAutocompleteSpan.mUserText != null; 117 || mAutocompleteSpan.mUserText != null;
128 } 118 }
129 119
130 /** 120 /**
131 * Whether we want to be showing inline autocomplete results. We don't want to show them as the 121 * Whether we want to be showing inline autocomplete results. We don't want to show them as the
132 * user deletes input. Also if there is a composition (e.g. while using the Japanese IME), 122 * user deletes input. Also if there is a composition (e.g. while using the Japanese IME),
133 * we must not autocomplete or we'll destroy the composition. 123 * we must not autocomplete or we'll destroy the composition.
134 * @return Whether we want to be showing inline autocomplete results. 124 * @return Whether we want to be showing inline autocomplete results.
135 */ 125 */
136 public boolean shouldAutocomplete() { 126 public boolean shouldAutocomplete() {
137 if (mLastEditWasDelete) return false; 127 if (mLastEditWasDelete) return false;
138 Editable text = getText(); 128 Editable text = getText();
139 129
140 return isCursorAtEndOfTypedText() && !isHandlingBatchInput() 130 return isCursorAtEndOfTypedText() && mBatchEditNestCount == 0
141 && BaseInputConnection.getComposingSpanEnd(text) 131 && BaseInputConnection.getComposingSpanEnd(text)
142 == BaseInputConnection.getComposingSpanStart(text); 132 == BaseInputConnection.getComposingSpanStart(text);
143 } 133 }
144 134
145 @Override 135 private void onPostEndBatchEdit() {
146 public void onBeginBatchEdit() {
147 if (DEBUG) Log.i(TAG, "onBeginBatchEdit");
148 mBeforeBatchEditAutocompleteIndex = getText().getSpanStart(mAutocomplete Span);
149 mBeforeBatchEditFullText = getText().toString();
150
151 super.onBeginBatchEdit();
152 mInBatchEditMode = true;
153 mTextDeletedInBatchMode = false;
154 }
155
156 @Override
157 public void onEndBatchEdit() {
158 if (DEBUG) Log.i(TAG, "onEndBatchEdit");
159 super.onEndBatchEdit();
160 mInBatchEditMode = false;
161 if (mSelectionChangedInBatchMode) { 136 if (mSelectionChangedInBatchMode) {
162 validateSelection(getSelectionStart(), getSelectionEnd()); 137 validateSelection(getSelectionStart(), getSelectionEnd());
163 mSelectionChangedInBatchMode = false; 138 mSelectionChangedInBatchMode = false;
164 } 139 }
165 140
166 String newText = getText().toString(); 141 String newText = getText().toString();
167 if (!TextUtils.equals(mBeforeBatchEditFullText, newText) 142 if (!TextUtils.equals(mBeforeBatchEditFullText, newText)
168 || getText().getSpanStart(mAutocompleteSpan) != mBeforeBatchEdit AutocompleteIndex) { 143 || getText().getSpanStart(mAutocompleteSpan) != mBeforeBatchEdit AutocompleteIndex) {
169 // If the text being typed is a single character that matches the ne xt character in the 144 // If the text being typed is a single character that matches the ne xt character in the
170 // previously visible autocomplete text, we reapply the autocomplete text to prevent 145 // previously visible autocomplete text, we reapply the autocomplete text to prevent
171 // a visual flickering when the autocomplete text is cleared and the n quickly reapplied 146 // a visual flickering when the autocomplete text is cleared and the n quickly reapplied
172 // when the next round of suggestions is received. 147 // when the next round of suggestions is received.
173 if (shouldAutocomplete() && mBeforeBatchEditAutocompleteIndex != -1 148 if (shouldAutocomplete() && mBeforeBatchEditAutocompleteIndex != -1
174 && mBeforeBatchEditFullText != null 149 && mBeforeBatchEditFullText != null
175 && mBeforeBatchEditFullText.startsWith(newText) && !mTextDel etedInBatchMode 150 && mBeforeBatchEditFullText.startsWith(newText) && !mTextDel etedInBatchMode
176 && newText.length() - mBeforeBatchEditAutocompleteIndex == 1 ) { 151 && newText.length() - mBeforeBatchEditAutocompleteIndex == 1 ) {
177 setAutocompleteText(newText, mBeforeBatchEditFullText.substring( newText.length())); 152 setAutocompleteText(newText, mBeforeBatchEditFullText.substring( newText.length()));
178 } 153 }
179 notifyAutocompleteTextStateChanged(mTextDeletedInBatchMode, true); 154 notifyAutocompleteTextStateChanged(mTextDeletedInBatchMode, true);
180 } 155 }
181 156
182 mTextDeletedInBatchMode = false; 157 mTextDeletedInBatchMode = false;
183 mBeforeBatchEditAutocompleteIndex = -1; 158 mBeforeBatchEditAutocompleteIndex = -1;
184 mBeforeBatchEditFullText = null; 159 mBeforeBatchEditFullText = null;
185 } 160 }
186 161
187 @Override 162 @Override
188 protected void onSelectionChanged(int selStart, int selEnd) { 163 protected void onSelectionChanged(int selStart, int selEnd) {
189 if (DEBUG) Log.i(TAG, "onSelectionChanged -- selStart: %d, selEnd: %d", selStart, selEnd); 164 if (DEBUG) Log.i(TAG, "onSelectionChanged -- selStart: %d, selEnd: %d", selStart, selEnd);
190 if (!mInBatchEditMode) { 165 if (mBatchEditNestCount == 0) {
191 int beforeTextLength = getText().length(); 166 int beforeTextLength = getText().length();
192 if (validateSelection(selStart, selEnd)) { 167 if (validateSelection(selStart, selEnd)) {
193 boolean textDeleted = getText().length() < beforeTextLength; 168 boolean textDeleted = getText().length() < beforeTextLength;
194 notifyAutocompleteTextStateChanged(textDeleted, false); 169 notifyAutocompleteTextStateChanged(textDeleted, false);
195 } 170 }
196 } else { 171 } else {
197 mSelectionChangedInBatchMode = true; 172 mSelectionChangedInBatchMode = true;
198 } 173 }
199 super.onSelectionChanged(selStart, selEnd); 174 super.onSelectionChanged(selStart, selEnd);
200 } 175 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 // in the case of autocomplete we want the last typed character to b e shown, which 235 // in the case of autocomplete we want the last typed character to b e shown, which
261 // is the start of selection. 236 // is the start of selection.
262 mDisableTextScrollingFromAutocomplete = false; 237 mDisableTextScrollingFromAutocomplete = false;
263 bringPointIntoView(getSelectionStart()); 238 bringPointIntoView(getSelectionStart());
264 retVal = true; 239 retVal = true;
265 } 240 }
266 return retVal; 241 return retVal;
267 } 242 }
268 243
269 /** 244 /**
270 * Autocompletes the text on the url bar and selects the text that was not e ntered by the 245 * Autocompletes the text and selects the text that was not entered by the u ser. Using append()
271 * user. Using append() instead of setText() to preserve the soft-keyboard l ayout. 246 * instead of setText() to preserve the soft-keyboard layout.
272 * @param userText user The text entered by the user. 247 * @param userText user The text entered by the user.
273 * @param inlineAutocompleteText The suggested autocompletion for the user's text. 248 * @param inlineAutocompleteText The suggested autocompletion for the user's text.
274 */ 249 */
275 public void setAutocompleteText(CharSequence userText, CharSequence inlineAu tocompleteText) { 250 public void setAutocompleteText(CharSequence userText, CharSequence inlineAu tocompleteText) {
276 if (DEBUG) { 251 if (DEBUG) {
277 Log.i(TAG, "setAutocompleteText -- userText: %s, inlineAutocompleteT ext: %s", userText, 252 Log.i(TAG, "setAutocompleteText -- userText: %s, inlineAutocompleteT ext: %s", userText,
278 inlineAutocompleteText); 253 inlineAutocompleteText);
279 } 254 }
280 boolean emptyAutocomplete = TextUtils.isEmpty(inlineAutocompleteText); 255 boolean emptyAutocomplete = TextUtils.isEmpty(inlineAutocompleteText);
281 256
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 306
332 @Override 307 @Override
333 protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { 308 protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
334 if (DEBUG) { 309 if (DEBUG) {
335 Log.i(TAG, "onTextChanged -- text: %s, start: %d, lengthBefore: %d, lengthAfter: %d", 310 Log.i(TAG, "onTextChanged -- text: %s, start: %d, lengthBefore: %d, lengthAfter: %d",
336 text, start, lengthBefore, lengthAfter); 311 text, start, lengthBefore, lengthAfter);
337 } 312 }
338 313
339 super.onTextChanged(text, start, lengthBefore, lengthAfter); 314 super.onTextChanged(text, start, lengthBefore, lengthAfter);
340 boolean textDeleted = lengthAfter == 0; 315 boolean textDeleted = lengthAfter == 0;
341 if (!mInBatchEditMode) { 316 if (mBatchEditNestCount == 0) {
342 notifyAutocompleteTextStateChanged(textDeleted, true); 317 notifyAutocompleteTextStateChanged(textDeleted, true);
343 } else { 318 } else {
344 mTextDeletedInBatchMode = textDeleted; 319 mTextDeletedInBatchMode = textDeleted;
345 } 320 }
346 } 321 }
347 322
348 @Override 323 @Override
349 public void setText(CharSequence text, BufferType type) { 324 public void setText(CharSequence text, BufferType type) {
350 if (DEBUG) Log.i(TAG, "setText -- text: %s", text); 325 if (DEBUG) Log.i(TAG, "setText -- text: %s", text);
351 326
352 mDisableTextScrollingFromAutocomplete = false; 327 mDisableTextScrollingFromAutocomplete = false;
353 328
354 // Avoid setting the same text to the URL bar as it will mess up the scr oll/cursor 329 // Avoid setting the same text as it will mess up the scroll/cursor posi tion.
355 // position.
356 // Setting the text is also quite expensive, so only do it when the text has changed 330 // Setting the text is also quite expensive, so only do it when the text has changed
357 // (since we apply spans when the URL is not focused, we only optimize t his when the 331 // (since we apply spans when the view is not focused, we only optimize this when the
358 // URL is being edited). 332 // text is being edited).
359 if (!TextUtils.equals(getEditableText(), text)) { 333 if (!TextUtils.equals(getEditableText(), text)) {
360 // Certain OEM implementations of setText trigger disk reads. crbug. com/633298 334 // Certain OEM implementations of setText trigger disk reads. crbug. com/633298
361 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads( ); 335 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads( );
362 try { 336 try {
363 super.setText(text, type); 337 super.setText(text, type);
364 } finally { 338 } finally {
365 StrictMode.setThreadPolicy(oldPolicy); 339 StrictMode.setThreadPolicy(oldPolicy);
366 } 340 }
367 } 341 }
368 342
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 397
424 @VisibleForTesting 398 @VisibleForTesting
425 public void setIgnoreImeForTest(boolean ignore) { 399 public void setIgnoreImeForTest(boolean ignore) {
426 mIgnoreImeForTest = ignore; 400 mIgnoreImeForTest = ignore;
427 } 401 }
428 402
429 private InputConnectionWrapper mInputConnection = new InputConnectionWrapper (null, true) { 403 private InputConnectionWrapper mInputConnection = new InputConnectionWrapper (null, true) {
430 private final char[] mTempSelectionChar = new char[1]; 404 private final char[] mTempSelectionChar = new char[1];
431 405
432 @Override 406 @Override
407 public boolean beginBatchEdit() {
408 ++mBatchEditNestCount;
409 if (mBatchEditNestCount == 1) {
410 if (DEBUG) Log.i(TAG, "beginBatchEdit");
411 mBeforeBatchEditAutocompleteIndex = getText().getSpanStart(mAuto completeSpan);
412 mBeforeBatchEditFullText = getText().toString();
413
414 boolean retVal = super.beginBatchEdit();
415 mTextDeletedInBatchMode = false;
416 return retVal;
417 }
418 return super.beginBatchEdit();
419 }
420
421 @Override
422 public boolean endBatchEdit() {
423 mBatchEditNestCount = Math.max(mBatchEditNestCount - 1, 0);
424 if (mBatchEditNestCount == 0) {
425 if (DEBUG) Log.i(TAG, "endBatchEdit");
426 boolean retVal = super.endBatchEdit();
427 onPostEndBatchEdit();
428 return retVal;
429 }
430 return super.endBatchEdit();
431 }
432
433 @Override
433 public boolean commitText(CharSequence text, int newCursorPosition) { 434 public boolean commitText(CharSequence text, int newCursorPosition) {
434 if (DEBUG) Log.i(TAG, "commitText: [%s]", text); 435 if (DEBUG) Log.i(TAG, "commitText: [%s]", text);
435 Editable currentText = getText(); 436 Editable currentText = getText();
436 if (currentText == null) return super.commitText(text, newCursorPosi tion); 437 if (currentText == null) return super.commitText(text, newCursorPosi tion);
437 438
438 int selectionStart = Selection.getSelectionStart(currentText); 439 int selectionStart = Selection.getSelectionStart(currentText);
439 int selectionEnd = Selection.getSelectionEnd(currentText); 440 int selectionEnd = Selection.getSelectionEnd(currentText);
440 int autocompleteIndex = currentText.getSpanStart(mAutocompleteSpan); 441 int autocompleteIndex = currentText.getSpanStart(mAutocompleteSpan);
441 // If the text being committed is a single character that matches th e next character 442 // If the text being committed is a single character that matches th e next character
442 // in the selection (assumed to be the autocomplete text), we only m ove the text 443 // in the selection (assumed to be the autocomplete text), we only m ove the text
(...skipping 15 matching lines...) Expand all
458 AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); 459 AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
459 event.setFromIndex(selectionStart); 460 event.setFromIndex(selectionStart);
460 event.setRemovedCount(0); 461 event.setRemovedCount(0);
461 event.setAddedCount(1); 462 event.setAddedCount(1);
462 event.setBeforeText(currentText.toString().substring(0, selectionStart)); 463 event.setBeforeText(currentText.toString().substring(0, selectionStart));
463 sendAccessibilityEventUnchecked(event); 464 sendAccessibilityEventUnchecked(event);
464 } 465 }
465 466
466 setAutocompleteText(currentText.subSequence(0, selectionStar t + 1), 467 setAutocompleteText(currentText.subSequence(0, selectionStar t + 1),
467 currentText.subSequence(selectionStart + 1, selectio nEnd)); 468 currentText.subSequence(selectionStart + 1, selectio nEnd));
468 if (!mInBatchEditMode) { 469 if (mBatchEditNestCount == 0) {
469 notifyAutocompleteTextStateChanged(false, false); 470 notifyAutocompleteTextStateChanged(false, false);
470 } 471 }
471 return true; 472 return true;
472 } 473 }
473 } 474 }
474 475
475 boolean retVal = super.commitText(text, newCursorPosition); 476 boolean retVal = super.commitText(text, newCursorPosition);
476 477
477 // Ensure the autocomplete span is removed if it is no longer valid after committing the 478 // Ensure the autocomplete span is removed if it is no longer valid after committing the
478 // text. 479 // text.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 } 595 }
595 596
596 /** Removes this span from the current text and clears the internal stat e. */ 597 /** Removes this span from the current text and clears the internal stat e. */
597 public void clearSpan() { 598 public void clearSpan() {
598 getText().removeSpan(this); 599 getText().removeSpan(this);
599 mAutocompleteText = null; 600 mAutocompleteText = null;
600 mUserText = null; 601 mUserText = null;
601 } 602 }
602 } 603 }
603 } 604 }
OLDNEW
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698