OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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.ClipData; | 7 import android.content.ClipData; |
8 import android.content.ClipboardManager; | 8 import android.content.ClipboardManager; |
9 import android.content.Context; | 9 import android.content.Context; |
10 import android.content.res.Resources; | 10 import android.content.res.Resources; |
11 import android.graphics.Canvas; | 11 import android.graphics.Canvas; |
12 import android.graphics.Paint; | 12 import android.graphics.Paint; |
13 import android.graphics.Rect; | 13 import android.graphics.Rect; |
14 import android.net.Uri; | 14 import android.net.Uri; |
15 import android.os.Build; | 15 import android.os.Build; |
16 import android.os.StrictMode; | 16 import android.os.StrictMode; |
17 import android.os.SystemClock; | 17 import android.os.SystemClock; |
18 import android.text.Editable; | 18 import android.text.Editable; |
19 import android.text.Layout; | 19 import android.text.Layout; |
20 import android.text.Selection; | 20 import android.text.Selection; |
21 import android.text.Spanned; | |
22 import android.text.TextUtils; | 21 import android.text.TextUtils; |
23 import android.text.style.ReplacementSpan; | 22 import android.text.style.ReplacementSpan; |
24 import android.util.AttributeSet; | 23 import android.util.AttributeSet; |
25 import android.util.Pair; | 24 import android.util.Pair; |
26 import android.view.GestureDetector; | 25 import android.view.GestureDetector; |
27 import android.view.KeyEvent; | 26 import android.view.KeyEvent; |
28 import android.view.MotionEvent; | 27 import android.view.MotionEvent; |
29 import android.view.View; | 28 import android.view.View; |
30 import android.view.accessibility.AccessibilityEvent; | |
31 import android.view.accessibility.AccessibilityManager; | |
32 import android.view.accessibility.AccessibilityNodeInfo; | 29 import android.view.accessibility.AccessibilityNodeInfo; |
33 import android.view.inputmethod.BaseInputConnection; | |
34 import android.view.inputmethod.EditorInfo; | |
35 import android.view.inputmethod.InputConnection; | |
36 import android.view.inputmethod.InputConnectionWrapper; | |
37 import android.widget.TextView; | 30 import android.widget.TextView; |
38 | 31 |
39 import org.chromium.base.ApiCompatibilityUtils; | 32 import org.chromium.base.ApiCompatibilityUtils; |
40 import org.chromium.base.Log; | 33 import org.chromium.base.Log; |
41 import org.chromium.base.SysUtils; | 34 import org.chromium.base.SysUtils; |
42 import org.chromium.base.VisibleForTesting; | 35 import org.chromium.base.VisibleForTesting; |
43 import org.chromium.chrome.R; | 36 import org.chromium.chrome.R; |
44 import org.chromium.chrome.browser.WindowDelegate; | 37 import org.chromium.chrome.browser.WindowDelegate; |
45 import org.chromium.chrome.browser.metrics.StartupMetrics; | 38 import org.chromium.chrome.browser.metrics.StartupMetrics; |
46 import org.chromium.chrome.browser.omnibox.LocationBarLayout.OmniboxLivenessList ener; | 39 import org.chromium.chrome.browser.omnibox.LocationBarLayout.OmniboxLivenessList ener; |
40 import org.chromium.chrome.browser.omnibox.view.AutocompleteEditText; | |
47 import org.chromium.chrome.browser.tab.Tab; | 41 import org.chromium.chrome.browser.tab.Tab; |
48 import org.chromium.chrome.browser.util.UrlUtilities; | 42 import org.chromium.chrome.browser.util.UrlUtilities; |
49 import org.chromium.chrome.browser.widget.VerticallyFixedEditText; | |
50 import org.chromium.content.browser.ContentViewCore; | 43 import org.chromium.content.browser.ContentViewCore; |
51 import org.chromium.ui.UiUtils; | 44 import org.chromium.ui.UiUtils; |
52 | 45 |
53 import java.net.MalformedURLException; | 46 import java.net.MalformedURLException; |
54 import java.net.URI; | 47 import java.net.URI; |
55 import java.net.URISyntaxException; | 48 import java.net.URISyntaxException; |
56 import java.net.URL; | 49 import java.net.URL; |
57 | 50 |
58 /** | 51 /** |
59 * The URL text entry view for the Omnibox. | 52 * The URL text entry view for the Omnibox. |
60 */ | 53 */ |
61 public class UrlBar extends VerticallyFixedEditText { | 54 public class UrlBar extends AutocompleteEditText { |
62 private static final String TAG = "cr_UrlBar"; | 55 private static final String TAG = "cr_UrlBar"; |
63 | 56 |
64 private static final boolean DEBUG = false; | 57 private static final boolean DEBUG = false; |
65 | 58 |
66 // TextView becomes very slow on long strings, so we limit maximum length | 59 // TextView becomes very slow on long strings, so we limit maximum length |
67 // of what is displayed to the user, see limitDisplayableLength(). | 60 // of what is displayed to the user, see limitDisplayableLength(). |
68 private static final int MAX_DISPLAYABLE_LENGTH = 4000; | 61 private static final int MAX_DISPLAYABLE_LENGTH = 4000; |
69 private static final int MAX_DISPLAYABLE_LENGTH_LOW_END = 1000; | 62 private static final int MAX_DISPLAYABLE_LENGTH_LOW_END = 1000; |
70 | 63 |
71 // Unicode "Left-To-Right Mark" (LRM) character. | 64 // Unicode "Left-To-Right Mark" (LRM) character. |
(...skipping 10 matching lines...) Expand all Loading... | |
82 /** | 75 /** |
83 * The text direction of the URL or query: LAYOUT_DIRECTION_LOCALE, LAYOUT_D IRECTION_LTR, or | 76 * The text direction of the URL or query: LAYOUT_DIRECTION_LOCALE, LAYOUT_D IRECTION_LTR, or |
84 * LAYOUT_DIRECTION_RTL. | 77 * LAYOUT_DIRECTION_RTL. |
85 * */ | 78 * */ |
86 private int mUrlDirection; | 79 private int mUrlDirection; |
87 | 80 |
88 private UrlBarDelegate mUrlBarDelegate; | 81 private UrlBarDelegate mUrlBarDelegate; |
89 | 82 |
90 private UrlDirectionListener mUrlDirectionListener; | 83 private UrlDirectionListener mUrlDirectionListener; |
91 | 84 |
92 private final AutocompleteSpan mAutocompleteSpan; | |
93 | |
94 /** | 85 /** |
95 * The gesture detector is used to detect long presses. Long presses require special treatment | 86 * The gesture detector is used to detect long presses. Long presses require special treatment |
96 * because the URL bar has custom touch event handling. See: {@link #onTouch Event}. | 87 * because the URL bar has custom touch event handling. See: {@link #onTouch Event}. |
97 */ | 88 */ |
98 private final GestureDetector mGestureDetector; | 89 private final GestureDetector mGestureDetector; |
99 | 90 |
100 private final KeyboardHideHelper mKeyboardHideHelper; | 91 private final KeyboardHideHelper mKeyboardHideHelper; |
101 | 92 |
102 private boolean mFocused; | 93 private boolean mFocused; |
103 private boolean mAllowFocus = true; | 94 private boolean mAllowFocus = true; |
104 | 95 |
105 private final int mDarkHintColor; | 96 private final int mDarkHintColor; |
106 private final int mDarkDefaultTextColor; | 97 private final int mDarkDefaultTextColor; |
107 private final int mDarkHighlightColor; | 98 private final int mDarkHighlightColor; |
108 | 99 |
109 private final int mLightHintColor; | 100 private final int mLightHintColor; |
110 private final int mLightDefaultTextColor; | 101 private final int mLightDefaultTextColor; |
111 private final int mLightHighlightColor; | 102 private final int mLightHighlightColor; |
112 | 103 |
113 private Boolean mUseDarkColors; | 104 private Boolean mUseDarkColors; |
114 | 105 |
115 private AccessibilityManager mAccessibilityManager; | |
116 | |
117 /** | |
118 * Whether default TextView scrolling should be disabled because autocomplet e has been added. | |
119 * This allows the user entered text to be shown instead of the end of the a utocomplete. | |
120 */ | |
121 private boolean mDisableTextScrollingFromAutocomplete; | |
122 | |
123 private OmniboxLivenessListener mOmniboxLivenessListener; | 106 private OmniboxLivenessListener mOmniboxLivenessListener; |
124 | 107 |
125 private long mFirstFocusTimeMs; | 108 private long mFirstFocusTimeMs; |
126 | 109 |
127 private boolean mInBatchEditMode; | |
128 private int mBeforeBatchEditAutocompleteIndex = -1; | |
129 private String mBeforeBatchEditFullText; | |
130 private boolean mSelectionChangedInBatchMode; | |
131 private boolean mTextDeletedInBatchMode; | |
132 | |
133 private boolean mIsPastedText; | |
134 // Used as a hint to indicate the text may contain an ellipsize span. This will be true if an | 110 // Used as a hint to indicate the text may contain an ellipsize span. This will be true if an |
135 // ellispize span was applied the last time the text changed. A true value here does not | 111 // ellispize span was applied the last time the text changed. A true value here does not |
136 // guarantee that the text does contain the span currently as newly set text may have cleared | 112 // guarantee that the text does contain the span currently as newly set text may have cleared |
137 // this (and it the value will only be recalculated after the text has been changed). | 113 // this (and it the value will only be recalculated after the text has been changed). |
138 private boolean mDidEllipsizeTextHint; | 114 private boolean mDidEllipsizeTextHint; |
139 | 115 |
140 // Set to true when the URL bar text is modified programmatically. Initially set | |
141 // to true until the old state has been loaded. | |
142 private boolean mIgnoreTextChangeFromAutocomplete = true; | |
143 private boolean mLastUrlEditWasDelete; | |
144 | |
145 /** This tracks whether or not the last ACTION_DOWN event was when the url b ar had focus. */ | 116 /** This tracks whether or not the last ACTION_DOWN event was when the url b ar had focus. */ |
146 boolean mDownEventHadFocus; | 117 boolean mDownEventHadFocus; |
147 | 118 |
148 /** | 119 /** |
149 * Implement this to get updates when the direction of the text in the URL b ar changes. | 120 * Implement this to get updates when the direction of the text in the URL b ar changes. |
150 * E.g. If the user is typing a URL, then erases it and starts typing a quer y in Arabic, | 121 * E.g. If the user is typing a URL, then erases it and starts typing a quer y in Arabic, |
151 * the direction will change from left-to-right to right-to-left. | 122 * the direction will change from left-to-right to right-to-left. |
152 */ | 123 */ |
153 interface UrlDirectionListener { | 124 interface UrlDirectionListener { |
154 /** | 125 /** |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 mLightDefaultTextColor = | 172 mLightDefaultTextColor = |
202 ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_l ight_default_text); | 173 ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_l ight_default_text); |
203 mLightHintColor = | 174 mLightHintColor = |
204 ApiCompatibilityUtils.getColor(resources, R.color.locationbar_li ght_hint_text); | 175 ApiCompatibilityUtils.getColor(resources, R.color.locationbar_li ght_hint_text); |
205 mLightHighlightColor = ApiCompatibilityUtils.getColor(resources, | 176 mLightHighlightColor = ApiCompatibilityUtils.getColor(resources, |
206 R.color.locationbar_light_selection_color); | 177 R.color.locationbar_light_selection_color); |
207 | 178 |
208 setUseDarkTextColors(true); | 179 setUseDarkTextColors(true); |
209 | 180 |
210 mUrlDirection = LAYOUT_DIRECTION_LOCALE; | 181 mUrlDirection = LAYOUT_DIRECTION_LOCALE; |
211 mAutocompleteSpan = new AutocompleteSpan(); | |
212 | 182 |
213 // The URL Bar is derived from an text edit class, and as such is focusa ble by | 183 // The URL Bar is derived from an text edit class, and as such is focusa ble by |
214 // default. This means that if it is created before the first draw of th e UI it | 184 // default. This means that if it is created before the first draw of th e UI it |
215 // will (as the only focusable element of the UI) get focus on the first draw. | 185 // will (as the only focusable element of the UI) get focus on the first draw. |
216 // We react to this by greying out the tab area and bringing up the keyb oard, | 186 // We react to this by greying out the tab area and bringing up the keyb oard, |
217 // which we don't want to do at startup. Prevent this by disabling focus until | 187 // which we don't want to do at startup. Prevent this by disabling focus until |
218 // the first draw. | 188 // the first draw. |
219 setFocusable(false); | 189 setFocusable(false); |
220 setFocusableInTouchMode(false); | 190 setFocusableInTouchMode(false); |
221 | 191 |
(...skipping 10 matching lines...) Expand all Loading... | |
232 return true; | 202 return true; |
233 } | 203 } |
234 }); | 204 }); |
235 mGestureDetector.setOnDoubleTapListener(null); | 205 mGestureDetector.setOnDoubleTapListener(null); |
236 mKeyboardHideHelper = new KeyboardHideHelper(this, new Runnable() { | 206 mKeyboardHideHelper = new KeyboardHideHelper(this, new Runnable() { |
237 @Override | 207 @Override |
238 public void run() { | 208 public void run() { |
239 if (mUrlBarDelegate != null) mUrlBarDelegate.backKeyPressed(); | 209 if (mUrlBarDelegate != null) mUrlBarDelegate.backKeyPressed(); |
240 } | 210 } |
241 }); | 211 }); |
242 | |
243 mAccessibilityManager = | |
244 (AccessibilityManager) context.getSystemService(Context.ACCESSIB ILITY_SERVICE); | |
245 } | 212 } |
246 | 213 |
247 /** | 214 /** |
248 * Initialize the delegate that allows interaction with the Window. | 215 * Initialize the delegate that allows interaction with the Window. |
249 */ | 216 */ |
250 public void setWindowDelegate(WindowDelegate windowDelegate) { | 217 public void setWindowDelegate(WindowDelegate windowDelegate) { |
251 mKeyboardHideHelper.setWindowDelegate(windowDelegate); | 218 mKeyboardHideHelper.setWindowDelegate(windowDelegate); |
252 } | 219 } |
253 | 220 |
254 /** | 221 /** |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 } | 263 } |
297 | 264 |
298 @Override | 265 @Override |
299 public boolean onKeyPreIme(int keyCode, KeyEvent event) { | 266 public boolean onKeyPreIme(int keyCode, KeyEvent event) { |
300 if (KeyEvent.KEYCODE_BACK == keyCode && event.getAction() == KeyEvent.AC TION_UP) { | 267 if (KeyEvent.KEYCODE_BACK == keyCode && event.getAction() == KeyEvent.AC TION_UP) { |
301 mKeyboardHideHelper.monitorForKeyboardHidden(); | 268 mKeyboardHideHelper.monitorForKeyboardHidden(); |
302 } | 269 } |
303 return super.onKeyPreIme(keyCode, event); | 270 return super.onKeyPreIme(keyCode, event); |
304 } | 271 } |
305 | 272 |
306 /** | |
307 * Sets whether text changes should trigger autocomplete. | |
308 * <p> | |
309 * {@link #setDelegate(UrlBarDelegate)} must be called with a non-null insta nce prior to | |
310 * enabling autocomplete. | |
311 * | |
312 * @param ignoreAutocomplete Whether text changes should be ignored and no a uto complete | |
313 * triggered. | |
314 */ | |
315 public void setIgnoreTextChangesForAutocomplete(boolean ignoreAutocomplete) { | |
316 assert mUrlBarDelegate != null; | |
Ted C
2017/05/17 18:29:32
should we keep this but call super.setIgnore...
Changwan Ryu
2017/05/17 20:18:56
Done
| |
317 | |
318 mIgnoreTextChangeFromAutocomplete = ignoreAutocomplete; | |
319 } | |
320 | |
321 /** | |
322 * @return The search query text (non-null). | |
323 */ | |
324 public String getQueryText() { | |
325 return getEditableText() != null ? getEditableText().toString() : ""; | |
326 } | |
327 | |
328 /** | |
329 * @return Whether the current cursor position is at the end of the user typ ed text (i.e. | |
330 * at the beginning of the inline autocomplete text if present other wise the very | |
331 * end of the current text). | |
332 */ | |
333 private boolean isCursorAtEndOfTypedText() { | |
334 final int selectionStart = getSelectionStart(); | |
335 final int selectionEnd = getSelectionEnd(); | |
336 | |
337 int expectedSelectionStart = getText().getSpanStart(mAutocompleteSpan); | |
338 int expectedSelectionEnd = getText().length(); | |
339 if (expectedSelectionStart < 0) { | |
340 expectedSelectionStart = expectedSelectionEnd; | |
341 } | |
342 | |
343 return selectionStart == expectedSelectionStart && selectionEnd == expec tedSelectionEnd; | |
344 } | |
345 | |
346 /** | |
347 * @return Whether the URL is currently in batch edit mode triggered by an I ME. No external | |
348 * text changes should be triggered while this is true. | |
349 */ | |
350 // isInBatchEditMode is a package protected method on TextView, so we intent ionally chose | |
351 // a different name. | |
352 private boolean isHandlingBatchInput() { | |
353 return mInBatchEditMode; | |
354 } | |
355 | |
356 /** | |
357 * @return The user text without the autocomplete text. | |
358 */ | |
359 public String getTextWithoutAutocomplete() { | |
360 int autoCompleteIndex = getText().getSpanStart(mAutocompleteSpan); | |
361 if (autoCompleteIndex < 0) { | |
362 return getQueryText(); | |
363 } else { | |
364 return getQueryText().substring(0, autoCompleteIndex); | |
365 } | |
366 } | |
367 | |
368 /** @return Whether any autocomplete information is specified on the current text. */ | |
369 @VisibleForTesting | |
370 protected boolean hasAutocomplete() { | |
371 return getText().getSpanStart(mAutocompleteSpan) >= 0 | |
372 || mAutocompleteSpan.mAutocompleteText != null | |
373 || mAutocompleteSpan.mUserText != null; | |
374 } | |
375 | |
376 /** | |
377 * Whether we want to be showing inline autocomplete results. We don't want to show them as the | |
378 * user deletes input. Also if there is a composition (e.g. while using the Japanese IME), | |
379 * we must not autocomplete or we'll destroy the composition. | |
380 * @return Whether we want to be showing inline autocomplete results. | |
381 */ | |
382 public boolean shouldAutocomplete() { | |
383 if (mLastUrlEditWasDelete) return false; | |
384 Editable text = getText(); | |
385 | |
386 return isCursorAtEndOfTypedText() | |
387 && !isPastedText() | |
388 && !isHandlingBatchInput() | |
389 && BaseInputConnection.getComposingSpanEnd(text) | |
390 == BaseInputConnection.getComposingSpanStart(text); | |
391 } | |
392 | |
393 @Override | |
394 public void onBeginBatchEdit() { | |
395 if (DEBUG) Log.i(TAG, "onBeginBatchEdit"); | |
396 mBeforeBatchEditAutocompleteIndex = getText().getSpanStart(mAutocomplete Span); | |
397 mBeforeBatchEditFullText = getText().toString(); | |
398 | |
399 super.onBeginBatchEdit(); | |
400 mInBatchEditMode = true; | |
401 mTextDeletedInBatchMode = false; | |
402 } | |
403 | |
404 @Override | |
405 public void onEndBatchEdit() { | |
406 if (DEBUG) Log.i(TAG, "onEndBatchEdit"); | |
407 super.onEndBatchEdit(); | |
408 mInBatchEditMode = false; | |
409 limitDisplayableLength(); | |
410 if (mSelectionChangedInBatchMode) { | |
411 validateSelection(getSelectionStart(), getSelectionEnd()); | |
412 mSelectionChangedInBatchMode = false; | |
413 } | |
414 | |
415 String newText = getText().toString(); | |
416 if (!TextUtils.equals(mBeforeBatchEditFullText, newText) | |
417 || getText().getSpanStart(mAutocompleteSpan) != mBeforeBatchEdit AutocompleteIndex) { | |
418 // If the text being typed is a single character that matches the ne xt character in the | |
419 // previously visible autocomplete text, we reapply the autocomplete text to prevent | |
420 // a visual flickering when the autocomplete text is cleared and the n quickly reapplied | |
421 // when the next round of suggestions is received. | |
422 if (shouldAutocomplete() && mBeforeBatchEditAutocompleteIndex != -1 | |
423 && mBeforeBatchEditFullText != null | |
424 && mBeforeBatchEditFullText.startsWith(newText) | |
425 && !mTextDeletedInBatchMode | |
426 && newText.length() - mBeforeBatchEditAutocompleteIndex == 1 ) { | |
427 setAutocompleteText(newText, mBeforeBatchEditFullText.substring( newText.length())); | |
428 } | |
429 notifyAutocompleteTextStateChanged(mTextDeletedInBatchMode); | |
430 } | |
431 | |
432 mTextDeletedInBatchMode = false; | |
433 mBeforeBatchEditAutocompleteIndex = -1; | |
434 mBeforeBatchEditFullText = null; | |
435 } | |
436 | |
437 @Override | |
438 protected void onSelectionChanged(int selStart, int selEnd) { | |
439 if (DEBUG) Log.i(TAG, "onSelectionChanged -- selStart: %d, selEnd: %d", selStart, selEnd); | |
440 if (!mInBatchEditMode) { | |
441 int beforeTextLength = getText().length(); | |
442 if (validateSelection(selStart, selEnd)) { | |
443 boolean textDeleted = getText().length() < beforeTextLength; | |
444 notifyAutocompleteTextStateChanged(textDeleted); | |
445 } | |
446 } else { | |
447 mSelectionChangedInBatchMode = true; | |
448 } | |
449 super.onSelectionChanged(selStart, selEnd); | |
450 } | |
451 | |
452 /** | |
453 * Validates the selection and clears the autocomplete span if needed. The autocomplete text | |
454 * will be deleted if the selection occurs entirely before the autocomplete region. | |
455 * | |
456 * @param selStart The start of the selection. | |
457 * @param selEnd The end of the selection. | |
458 * @return Whether the autocomplete span was removed as a result of this val idation. | |
459 */ | |
460 private boolean validateSelection(int selStart, int selEnd) { | |
461 int spanStart = getText().getSpanStart(mAutocompleteSpan); | |
462 int spanEnd = getText().getSpanEnd(mAutocompleteSpan); | |
463 | |
464 if (DEBUG) { | |
465 Log.i(TAG, "validateSelection -- selStart: %d, selEnd: %d, spanStart : %d, spanEnd: %d", | |
466 selStart, selEnd, spanStart, spanEnd); | |
467 } | |
468 | |
469 if (spanStart >= 0 && (spanStart != selStart || spanEnd != selEnd)) { | |
470 CharSequence previousAutocompleteText = mAutocompleteSpan.mAutocompl eteText; | |
471 | |
472 // On selection changes, the autocomplete text has been accepted by the user or needs | |
473 // to be deleted below. | |
474 mAutocompleteSpan.clearSpan(); | |
475 | |
476 // The autocomplete text will be deleted any time the selection occu rs entirely before | |
477 // the start of the autocomplete text. This is required because cer tain keyboards will | |
478 // insert characters temporarily when starting a key entry gesture ( whether it be | |
479 // swyping a word or long pressing to get a special character). Whe n this temporary | |
480 // character appears, Chrome may decide to append some autocomplete, but the keyboard | |
481 // will then remove this temporary character only while leaving the autocomplete text | |
482 // alone. See crbug/273763 for more details. | |
483 if (selEnd <= spanStart && TextUtils.equals(previousAutocompleteText , | |
484 getText().subSequence(spanStart, getText().length()))) { | |
485 getText().delete(spanStart, getText().length()); | |
486 } | |
487 return true; | |
488 } | |
489 return false; | |
490 } | |
491 | |
492 @Override | 273 @Override |
493 protected void onFocusChanged(boolean focused, int direction, Rect previousl yFocusedRect) { | 274 protected void onFocusChanged(boolean focused, int direction, Rect previousl yFocusedRect) { |
494 mFocused = focused; | 275 mFocused = focused; |
495 if (!focused) mAutocompleteSpan.clearSpan(); | |
496 super.onFocusChanged(focused, direction, previouslyFocusedRect); | 276 super.onFocusChanged(focused, direction, previouslyFocusedRect); |
497 | 277 |
498 if (focused && mFirstFocusTimeMs == 0) { | 278 if (focused && mFirstFocusTimeMs == 0) { |
499 mFirstFocusTimeMs = SystemClock.elapsedRealtime(); | 279 mFirstFocusTimeMs = SystemClock.elapsedRealtime(); |
500 if (mOmniboxLivenessListener != null) mOmniboxLivenessListener.onOmn iboxFocused(); | 280 if (mOmniboxLivenessListener != null) mOmniboxLivenessListener.onOmn iboxFocused(); |
501 } | 281 } |
502 | 282 |
503 if (focused) StartupMetrics.getInstance().recordFocusedOmnibox(); | 283 if (focused) StartupMetrics.getInstance().recordFocusedOmnibox(); |
504 | 284 |
505 fixupTextDirection(); | 285 fixupTextDirection(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
596 @Override | 376 @Override |
597 public boolean performLongClick(float x, float y) { | 377 public boolean performLongClick(float x, float y) { |
598 // If the touch event that triggered this was when the url bar was in a different focus | 378 // If the touch event that triggered this was when the url bar was in a different focus |
599 // state, ignore the event. | 379 // state, ignore the event. |
600 if (mDownEventHadFocus != mFocused) return true; | 380 if (mDownEventHadFocus != mFocused) return true; |
601 | 381 |
602 return super.performLongClick(x, y); | 382 return super.performLongClick(x, y); |
603 } | 383 } |
604 | 384 |
605 @Override | 385 @Override |
606 public boolean bringPointIntoView(int offset) { | |
607 if (mDisableTextScrollingFromAutocomplete) return false; | |
608 return super.bringPointIntoView(offset); | |
609 } | |
610 | |
611 @Override | |
612 public boolean onPreDraw() { | |
613 boolean retVal = super.onPreDraw(); | |
614 if (mDisableTextScrollingFromAutocomplete) { | |
615 // super.onPreDraw will put the selection at the end of the text sel ection, but | |
616 // in the case of autocomplete we want the last typed character to b e shown, which | |
617 // is the start of selection. | |
618 mDisableTextScrollingFromAutocomplete = false; | |
619 bringPointIntoView(getSelectionStart()); | |
620 retVal = true; | |
621 } | |
622 return retVal; | |
623 } | |
624 | |
625 @Override | |
626 public void onDraw(Canvas canvas) { | 386 public void onDraw(Canvas canvas) { |
627 super.onDraw(canvas); | 387 super.onDraw(canvas); |
628 | 388 |
629 if (!mFirstDrawComplete) { | 389 if (!mFirstDrawComplete) { |
630 mFirstDrawComplete = true; | 390 mFirstDrawComplete = true; |
631 | 391 |
632 // We have now avoided the first draw problem (see the comment in | 392 // We have now avoided the first draw problem (see the comment in |
633 // the constructor) so we want to make the URL bar focusable so that | 393 // the constructor) so we want to make the URL bar focusable so that |
634 // touches etc. activate it. | 394 // touches etc. activate it. |
635 setFocusable(mAllowFocus); | 395 setFocusable(mAllowFocus); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 if (isFocused()) { | 496 if (isFocused()) { |
737 final int selStart = getSelectionStart(); | 497 final int selStart = getSelectionStart(); |
738 final int selEnd = getSelectionEnd(); | 498 final int selEnd = getSelectionEnd(); |
739 | 499 |
740 min = Math.max(0, Math.min(selStart, selEnd)); | 500 min = Math.max(0, Math.min(selStart, selEnd)); |
741 max = Math.max(0, Math.max(selStart, selEnd)); | 501 max = Math.max(0, Math.max(selStart, selEnd)); |
742 } | 502 } |
743 | 503 |
744 Selection.setSelection(getText(), max); | 504 Selection.setSelection(getText(), max); |
745 getText().replace(min, max, pasteString); | 505 getText().replace(min, max, pasteString); |
746 mIsPastedText = true; | 506 onPaste(); |
747 return true; | 507 return true; |
748 } | 508 } |
749 } | 509 } |
750 | 510 |
751 if (mOriginalUrlLocation == null || mFormattedUrlLocation == null) { | 511 if (mOriginalUrlLocation == null || mFormattedUrlLocation == null) { |
752 return super.onTextContextMenuItem(id); | 512 return super.onTextContextMenuItem(id); |
753 } | 513 } |
754 | 514 |
755 int selectedStartIndex = getSelectionStart(); | 515 int selectedStartIndex = getSelectionStart(); |
756 int selectedEndIndex = getSelectionEnd(); | 516 int selectedEndIndex = getSelectionEnd(); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
818 | 578 |
819 Editable previousText = getEditableText(); | 579 Editable previousText = getEditableText(); |
820 setText(formattedUrl); | 580 setText(formattedUrl); |
821 | 581 |
822 if (!isFocused()) scrollToTLD(); | 582 if (!isFocused()) scrollToTLD(); |
823 | 583 |
824 return !TextUtils.equals(previousText, getEditableText()); | 584 return !TextUtils.equals(previousText, getEditableText()); |
825 } | 585 } |
826 | 586 |
827 /** | 587 /** |
828 * Autocompletes the text on the url bar and selects the text that was not e ntered by the | |
829 * user. Using append() instead of setText() to preserve the soft-keyboard l ayout. | |
830 * @param userText user The text entered by the user. | |
831 * @param inlineAutocompleteText The suggested autocompletion for the user's text. | |
832 */ | |
833 public void setAutocompleteText(CharSequence userText, CharSequence inlineAu tocompleteText) { | |
834 if (DEBUG) { | |
835 Log.i(TAG, "setAutocompleteText -- userText: %s, inlineAutocompleteT ext: %s", | |
836 userText, inlineAutocompleteText); | |
837 } | |
838 boolean emptyAutocomplete = TextUtils.isEmpty(inlineAutocompleteText); | |
839 | |
840 if (!emptyAutocomplete) mDisableTextScrollingFromAutocomplete = true; | |
841 | |
842 int autocompleteIndex = userText.length(); | |
843 | |
844 String previousText = getQueryText(); | |
845 CharSequence newText = TextUtils.concat(userText, inlineAutocompleteText ); | |
846 | |
847 setIgnoreTextChangesForAutocomplete(true); | |
848 | |
849 if (!TextUtils.equals(previousText, newText)) { | |
850 // The previous text may also have included autocomplete text, so we only | |
851 // append the new autocomplete text that has changed. | |
852 if (TextUtils.indexOf(newText, previousText) == 0) { | |
853 append(newText.subSequence(previousText.length(), newText.length ())); | |
854 } else { | |
855 setUrl(newText.toString(), null); | |
856 } | |
857 } | |
858 | |
859 if (getSelectionStart() != autocompleteIndex | |
860 || getSelectionEnd() != getText().length()) { | |
861 setSelection(autocompleteIndex, getText().length()); | |
862 | |
863 if (inlineAutocompleteText.length() != 0) { | |
864 // Sending a TYPE_VIEW_TEXT_SELECTION_CHANGED accessibility even t causes the | |
865 // previous TYPE_VIEW_TEXT_CHANGED event to be swallowed. As a r esult the user | |
866 // hears the autocomplete text but *not* the text they typed. In stead we send a | |
867 // TYPE_ANNOUNCEMENT event, which doesn't swallow the text-chang ed event. | |
868 announceForAccessibility(inlineAutocompleteText); | |
869 } | |
870 } | |
871 | |
872 if (emptyAutocomplete) { | |
873 mAutocompleteSpan.clearSpan(); | |
874 } else { | |
875 mAutocompleteSpan.setSpan(userText, inlineAutocompleteText); | |
876 } | |
877 | |
878 setIgnoreTextChangesForAutocomplete(false); | |
879 } | |
880 | |
881 /** | |
882 * Returns the length of the autocomplete text currently displayed, zero if none is | |
883 * currently displayed. | |
884 */ | |
885 public int getAutocompleteLength() { | |
886 int autoCompleteIndex = getText().getSpanStart(mAutocompleteSpan); | |
887 if (autoCompleteIndex < 0) return 0; | |
888 return getText().length() - autoCompleteIndex; | |
889 } | |
890 | |
891 /** | |
892 * Scroll to ensure the TLD is visible. | 588 * Scroll to ensure the TLD is visible. |
893 * @return Whether the TLD was discovered and successfully scrolled to. | 589 * @return Whether the TLD was discovered and successfully scrolled to. |
894 */ | 590 */ |
895 public boolean scrollToTLD() { | 591 public boolean scrollToTLD() { |
896 Editable url = getText(); | 592 Editable url = getText(); |
897 if (url == null || url.length() < 1) return false; | 593 if (url == null || url.length() < 1) return false; |
898 String urlString = url.toString(); | 594 String urlString = url.toString(); |
899 Pair<String, String> urlComponents = | 595 Pair<String, String> urlComponents = |
900 LocationBarLayout.splitPathFromUrlDisplayText(urlString); | 596 LocationBarLayout.splitPathFromUrlDisplayText(urlString); |
901 | 597 |
902 if (TextUtils.isEmpty(urlComponents.first)) return false; | 598 if (TextUtils.isEmpty(urlComponents.first)) return false; |
903 | 599 |
904 // Do not scroll to the end of the host for URLs such as data:, javascri pt:, etc... | 600 // Do not scroll to the end of the host for URLs such as data:, javascri pt:, etc... |
905 if (urlComponents.second == null) { | 601 if (urlComponents.second == null) { |
906 Uri uri = Uri.parse(urlString); | 602 Uri uri = Uri.parse(urlString); |
907 String scheme = uri.getScheme(); | 603 String scheme = uri.getScheme(); |
908 if (!TextUtils.isEmpty(scheme) | 604 if (!TextUtils.isEmpty(scheme) |
909 && LocationBarLayout.UNSUPPORTED_SCHEMES_TO_SPLIT.contains(s cheme)) { | 605 && LocationBarLayout.UNSUPPORTED_SCHEMES_TO_SPLIT.contains(s cheme)) { |
910 return false; | 606 return false; |
911 } | 607 } |
912 } | 608 } |
913 | 609 |
914 setSelection(urlComponents.first.length()); | 610 setSelection(urlComponents.first.length()); |
915 return true; | 611 return true; |
916 } | 612 } |
917 | 613 |
918 @Override | 614 @Override |
919 protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { | |
920 if (DEBUG) { | |
921 Log.i(TAG, "onTextChanged -- text: %s, start: %d, lengthBefore: %d, lengthAfter: %d", | |
922 text, start, lengthBefore, lengthAfter); | |
923 } | |
924 | |
925 super.onTextChanged(text, start, lengthBefore, lengthAfter); | |
926 if (!mInBatchEditMode) { | |
927 limitDisplayableLength(); | |
928 notifyAutocompleteTextStateChanged(lengthAfter == 0); | |
929 } else { | |
930 mTextDeletedInBatchMode = lengthAfter == 0; | |
931 } | |
932 mIsPastedText = false; | |
933 } | |
934 | |
935 @Override | |
936 public void setText(CharSequence text, BufferType type) { | 615 public void setText(CharSequence text, BufferType type) { |
937 if (DEBUG) Log.i(TAG, "setText -- text: %s", text); | 616 if (DEBUG) Log.i(TAG, "setText -- text: %s", text); |
938 | 617 super.setText(text, type); |
939 mDisableTextScrollingFromAutocomplete = false; | |
940 | |
941 // Avoid setting the same text to the URL bar as it will mess up the scr oll/cursor | |
942 // position. | |
943 // Setting the text is also quite expensive, so only do it when the text has changed | |
944 // (since we apply spans when the URL is not focused, we only optimize t his when the | |
945 // URL is being edited). | |
946 if (!TextUtils.equals(getEditableText(), text)) { | |
947 // Certain OEM implementations of setText trigger disk reads. crbug. com/633298 | |
948 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads( ); | |
949 try { | |
950 super.setText(text, type); | |
951 } finally { | |
952 StrictMode.setThreadPolicy(oldPolicy); | |
953 } | |
954 } | |
955 | |
956 // Verify the autocomplete is still valid after the text change. | |
957 // Note: mAutocompleteSpan may be still null here if setText() is called in View | |
958 // constructor. | |
959 if (mAutocompleteSpan != null | |
960 && mAutocompleteSpan.mUserText != null | |
961 && mAutocompleteSpan.mAutocompleteText != null) { | |
962 if (getText().getSpanStart(mAutocompleteSpan) < 0) { | |
963 mAutocompleteSpan.clearSpan(); | |
964 } else { | |
965 clearAutocompleteSpanIfInvalid(); | |
966 } | |
967 } | |
968 | |
969 fixupTextDirection(); | 618 fixupTextDirection(); |
970 } | 619 } |
971 | 620 |
972 private void clearAutocompleteSpanIfInvalid() { | |
973 Editable editableText = getEditableText(); | |
974 CharSequence previousUserText = mAutocompleteSpan.mUserText; | |
975 CharSequence previousAutocompleteText = mAutocompleteSpan.mAutocompleteT ext; | |
976 if (editableText.length() | |
977 != (previousUserText.length() + previousAutocompleteText.length( ))) { | |
978 mAutocompleteSpan.clearSpan(); | |
979 } else if (TextUtils.indexOf(getText(), previousUserText) != 0 | |
980 || TextUtils.indexOf(getText(), | |
981 previousAutocompleteText, previousUserText.length()) != 0) { | |
982 mAutocompleteSpan.clearSpan(); | |
983 } | |
984 } | |
985 | |
986 private void limitDisplayableLength() { | 621 private void limitDisplayableLength() { |
987 // To limit displayable length we replace middle portion of the string w ith ellipsis. | 622 // To limit displayable length we replace middle portion of the string w ith ellipsis. |
988 // That affects only presentation of the text, and doesn't affect other aspects like | 623 // That affects only presentation of the text, and doesn't affect other aspects like |
989 // copying to the clipboard, getting text with getText(), etc. | 624 // copying to the clipboard, getting text with getText(), etc. |
990 final int maxLength = SysUtils.isLowEndDevice() | 625 final int maxLength = SysUtils.isLowEndDevice() |
991 ? MAX_DISPLAYABLE_LENGTH_LOW_END : MAX_DISPLAYABLE_LENGTH; | 626 ? MAX_DISPLAYABLE_LENGTH_LOW_END : MAX_DISPLAYABLE_LENGTH; |
992 | 627 |
993 Editable text = getText(); | 628 Editable text = getText(); |
994 int textLength = text.length(); | 629 int textLength = text.length(); |
995 if (textLength <= maxLength) { | 630 if (textLength <= maxLength) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1032 if (pathIndex > 0) { | 667 if (pathIndex > 0) { |
1033 urlPrePath = url.substring(0, pathIndex); | 668 urlPrePath = url.substring(0, pathIndex); |
1034 } else { | 669 } else { |
1035 urlPrePath = url; | 670 urlPrePath = url; |
1036 } | 671 } |
1037 } | 672 } |
1038 return urlPrePath; | 673 return urlPrePath; |
1039 } | 674 } |
1040 | 675 |
1041 @Override | 676 @Override |
1042 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { | |
1043 if (mIgnoreTextChangeFromAutocomplete) { | |
1044 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_SELECT ION_CHANGED | |
1045 || event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT _CHANGED) { | |
1046 return; | |
1047 } | |
1048 } | |
1049 super.sendAccessibilityEventUnchecked(event); | |
1050 } | |
1051 | |
1052 @Override | |
1053 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { | 677 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { |
1054 // Certain OEM implementations of onInitializeAccessibilityNodeInfo trig ger disk reads | 678 // Certain OEM implementations of onInitializeAccessibilityNodeInfo trig ger disk reads |
1055 // to access the clipboard. crbug.com/640993 | 679 // to access the clipboard. crbug.com/640993 |
1056 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); | 680 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); |
1057 try { | 681 try { |
1058 super.onInitializeAccessibilityNodeInfo(info); | 682 super.onInitializeAccessibilityNodeInfo(info); |
1059 } finally { | 683 } finally { |
1060 StrictMode.setThreadPolicy(oldPolicy); | 684 StrictMode.setThreadPolicy(oldPolicy); |
1061 } | 685 } |
1062 } | 686 } |
1063 | 687 |
1064 @VisibleForTesting | |
1065 InputConnectionWrapper mInputConnection = new InputConnectionWrapper(null, t rue) { | |
1066 private final char[] mTempSelectionChar = new char[1]; | |
1067 | |
1068 @Override | |
1069 public boolean commitText(CharSequence text, int newCursorPosition) { | |
1070 Editable currentText = getText(); | |
1071 if (currentText == null) return super.commitText(text, newCursorPosi tion); | |
1072 | |
1073 int selectionStart = Selection.getSelectionStart(currentText); | |
1074 int selectionEnd = Selection.getSelectionEnd(currentText); | |
1075 int autocompleteIndex = currentText.getSpanStart(mAutocompleteSpan); | |
1076 // If the text being committed is a single character that matches th e next character | |
1077 // in the selection (assumed to be the autocomplete text), we only m ove the text | |
1078 // selection instead clearing the autocomplete text causing flickeri ng as the | |
1079 // autocomplete text will appear once the next suggestions are recei ved. | |
1080 // | |
1081 // To be confident that the selection is an autocomplete, we ensure the selection | |
1082 // is at least one character and the end of the selection is the end of the | |
1083 // currently entered text. | |
1084 if (newCursorPosition == 1 && selectionStart > 0 && selectionStart ! = selectionEnd | |
1085 && selectionEnd >= currentText.length() | |
1086 && autocompleteIndex == selectionStart | |
1087 && text.length() == 1) { | |
1088 currentText.getChars(selectionStart, selectionStart + 1, mTempSe lectionChar, 0); | |
1089 if (mTempSelectionChar[0] == text.charAt(0)) { | |
1090 | |
1091 // Since the text isn't changing, TalkBack won't read out th e typed characters. | |
1092 // To work around this, explicitly send an accessibility eve nt. crbug.com/416595 | |
1093 if (mAccessibilityManager != null && mAccessibilityManager.i sEnabled()) { | |
1094 AccessibilityEvent event = AccessibilityEvent.obtain( | |
1095 AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); | |
1096 event.setFromIndex(selectionStart); | |
1097 event.setRemovedCount(0); | |
1098 event.setAddedCount(1); | |
1099 event.setBeforeText(currentText.toString().substring(0, selectionStart)); | |
1100 sendAccessibilityEventUnchecked(event); | |
1101 } | |
1102 | |
1103 setAutocompleteText( | |
1104 currentText.subSequence(0, selectionStart + 1), | |
1105 currentText.subSequence(selectionStart + 1, selectio nEnd)); | |
1106 if (!mInBatchEditMode) { | |
1107 notifyAutocompleteTextStateChanged(false); | |
1108 } | |
1109 return true; | |
1110 } | |
1111 } | |
1112 | |
1113 boolean retVal = super.commitText(text, newCursorPosition); | |
1114 | |
1115 // Ensure the autocomplete span is removed if it is no longer valid after committing the | |
1116 // text. | |
1117 if (getText().getSpanStart(mAutocompleteSpan) >= 0) clearAutocomplet eSpanIfInvalid(); | |
1118 | |
1119 return retVal; | |
1120 } | |
1121 | |
1122 @Override | |
1123 public boolean setComposingText(CharSequence text, int newCursorPosition ) { | |
1124 Editable currentText = getText(); | |
1125 int autoCompleteSpanStart = currentText.getSpanStart(mAutocompleteSp an); | |
1126 if (autoCompleteSpanStart >= 0) { | |
1127 int composingEnd = BaseInputConnection.getComposingSpanEnd(curre ntText); | |
1128 | |
1129 // On certain device/keyboard combinations, the composing region s are specified | |
1130 // with a noticeable delay after the initial character is typed, and in certain | |
1131 // circumstances it does not check that the current state of the text matches the | |
1132 // expectations of it's composing region. | |
1133 // For example, you can be typing: | |
1134 // chrome://f | |
1135 // Chrome will autocomplete to: | |
1136 // chrome://f[lags] | |
1137 // And after the autocomplete has been set, the keyboard will se t the composing | |
1138 // region to the last character and it assumes it is 'f' as it w as the last | |
1139 // character the keyboard sent. If we commit this composition, the text will | |
1140 // look like: | |
1141 // chrome://flag[f] | |
1142 // And if we use the autocomplete clearing logic below, it will look like: | |
1143 // chrome://f[f] | |
1144 // To work around this, we see if the composition matches all th e characters prior | |
1145 // to the autocomplete and just readjust the composing region to be that subset. | |
1146 // | |
1147 // See crbug.com/366732 | |
1148 if (composingEnd == currentText.length() | |
1149 && autoCompleteSpanStart >= text.length() | |
1150 && TextUtils.equals( | |
1151 currentText.subSequence( | |
1152 autoCompleteSpanStart - text.length(), | |
1153 autoCompleteSpanStart), | |
1154 text)) { | |
1155 setComposingRegion( | |
1156 autoCompleteSpanStart - text.length(), autoCompleteS panStart); | |
1157 } | |
1158 | |
1159 // Once composing text is being modified, the autocomplete text has been accepted | |
1160 // or has to be deleted. | |
1161 mAutocompleteSpan.clearSpan(); | |
1162 Selection.setSelection(currentText, autoCompleteSpanStart); | |
1163 currentText.delete(autoCompleteSpanStart, currentText.length()); | |
1164 } | |
1165 return super.setComposingText(text, newCursorPosition); | |
1166 } | |
1167 }; | |
1168 | |
1169 @Override | |
1170 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { | |
1171 mInputConnection.setTarget(super.onCreateInputConnection(outAttrs)); | |
1172 return mInputConnection; | |
1173 } | |
1174 | |
1175 /** | 688 /** |
1176 * Emphasize components of the URL for readability. | 689 * Emphasize components of the URL for readability. |
1177 */ | 690 */ |
1178 public void emphasizeUrl() { | 691 public void emphasizeUrl() { |
1179 Editable url = getText(); | 692 Editable url = getText(); |
1180 if (OmniboxUrlEmphasizer.hasEmphasisSpans(url) || hasFocus()) { | 693 if (OmniboxUrlEmphasizer.hasEmphasisSpans(url) || hasFocus()) { |
1181 return; | 694 return; |
1182 } | 695 } |
1183 | 696 |
1184 if (url.length() < 1) { | 697 if (url.length() < 1) { |
(...skipping 16 matching lines...) Expand all Loading... | |
1201 mUseDarkColors, mUrlBarDelegate.shouldEmphasizeHttpsScheme()); | 714 mUseDarkColors, mUrlBarDelegate.shouldEmphasizeHttpsScheme()); |
1202 } | 715 } |
1203 | 716 |
1204 /** | 717 /** |
1205 * Reset the modifications done to emphasize components of the URL. | 718 * Reset the modifications done to emphasize components of the URL. |
1206 */ | 719 */ |
1207 public void deEmphasizeUrl() { | 720 public void deEmphasizeUrl() { |
1208 OmniboxUrlEmphasizer.deEmphasizeUrl(getText()); | 721 OmniboxUrlEmphasizer.deEmphasizeUrl(getText()); |
1209 } | 722 } |
1210 | 723 |
1211 /** | |
1212 * @return Whether the current UrlBar input has been pasted from the clipboa rd. | |
1213 */ | |
1214 public boolean isPastedText() { | |
1215 return mIsPastedText; | |
1216 } | |
1217 | |
1218 @Override | 724 @Override |
1219 public CharSequence getAccessibilityClassName() { | 725 public CharSequence getAccessibilityClassName() { |
1220 // When UrlBar is used as a read-only TextView, force Talkback to pronou nce it like | 726 // When UrlBar is used as a read-only TextView, force Talkback to pronou nce it like |
1221 // TextView. Otherwise Talkback will say "Edit box, http://...". crbug.c om/636988 | 727 // TextView. Otherwise Talkback will say "Edit box, http://...". crbug.c om/636988 |
1222 if (isEnabled()) { | 728 if (isEnabled()) { |
1223 return super.getAccessibilityClassName(); | 729 return super.getAccessibilityClassName(); |
1224 } else { | 730 } else { |
1225 return TextView.class.getName(); | 731 return TextView.class.getName(); |
1226 } | 732 } |
1227 } | 733 } |
1228 | 734 |
1229 private void notifyAutocompleteTextStateChanged(boolean textDeleted) { | 735 /** |
736 * @return The search query text (non-null). | |
737 */ | |
738 public String getQueryText() { | |
Ted C
2017/05/17 18:29:32
Can we just convert all the callers to use getText
Changwan Ryu
2017/05/17 20:18:56
Done.
| |
739 return getTextWithAutocomplete(); | |
740 } | |
741 | |
742 @Override | |
743 public void setTextFromAutocomplete(String text) { | |
744 setUrl(text, null); | |
745 } | |
746 | |
747 @Override | |
748 public void onAutocompleteTextStateChanged(boolean textDeleted, boolean upda teDisplay) { | |
1230 if (mUrlBarDelegate == null) return; | 749 if (mUrlBarDelegate == null) return; |
1231 if (!hasFocus()) return; | 750 if (updateDisplay) limitDisplayableLength(); |
1232 if (mIgnoreTextChangeFromAutocomplete) return; | |
1233 | 751 |
1234 mLastUrlEditWasDelete = textDeleted; | |
1235 mUrlBarDelegate.onTextChangedForAutocomplete(textDeleted); | 752 mUrlBarDelegate.onTextChangedForAutocomplete(textDeleted); |
1236 } | 753 } |
1237 | 754 |
1238 /** | 755 /** |
1239 * Simple span used for tracking the current autocomplete state. | |
1240 */ | |
1241 private class AutocompleteSpan { | |
1242 private CharSequence mUserText; | |
1243 private CharSequence mAutocompleteText; | |
1244 | |
1245 /** | |
1246 * Adds the span to the current text. | |
1247 * @param userText The user entered text. | |
1248 * @param autocompleteText The autocomplete text being appended. | |
1249 */ | |
1250 public void setSpan(CharSequence userText, CharSequence autocompleteText ) { | |
1251 Editable text = getText(); | |
1252 text.removeSpan(this); | |
1253 mAutocompleteText = autocompleteText; | |
1254 mUserText = userText; | |
1255 text.setSpan( | |
1256 this, | |
1257 userText.length(), | |
1258 text.length(), | |
1259 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); | |
1260 } | |
1261 | |
1262 /** Removes this span from the current text and clears the internal stat e. */ | |
1263 public void clearSpan() { | |
1264 getText().removeSpan(this); | |
1265 mAutocompleteText = null; | |
1266 mUserText = null; | |
1267 } | |
1268 } | |
1269 | |
1270 /** | |
1271 * Span that displays ellipsis instead of the text. Used to hide portion of | 756 * Span that displays ellipsis instead of the text. Used to hide portion of |
1272 * very large string to get decent performance from TextView. | 757 * very large string to get decent performance from TextView. |
1273 */ | 758 */ |
1274 private static class EllipsisSpan extends ReplacementSpan { | 759 private static class EllipsisSpan extends ReplacementSpan { |
1275 private static final String ELLIPSIS = "..."; | 760 private static final String ELLIPSIS = "..."; |
1276 | 761 |
1277 public static final EllipsisSpan INSTANCE = new EllipsisSpan(); | 762 public static final EllipsisSpan INSTANCE = new EllipsisSpan(); |
1278 | 763 |
1279 @Override | 764 @Override |
1280 public int getSize(Paint paint, CharSequence text, | 765 public int getSize(Paint paint, CharSequence text, |
1281 int start, int end, Paint.FontMetricsInt fm) { | 766 int start, int end, Paint.FontMetricsInt fm) { |
1282 return (int) paint.measureText(ELLIPSIS); | 767 return (int) paint.measureText(ELLIPSIS); |
1283 } | 768 } |
1284 | 769 |
1285 @Override | 770 @Override |
1286 public void draw(Canvas canvas, CharSequence text, int start, int end, | 771 public void draw(Canvas canvas, CharSequence text, int start, int end, |
1287 float x, int top, int y, int bottom, Paint paint) { | 772 float x, int top, int y, int bottom, Paint paint) { |
1288 canvas.drawText(ELLIPSIS, x, y, paint); | 773 canvas.drawText(ELLIPSIS, x, y, paint); |
1289 } | 774 } |
1290 } | 775 } |
1291 } | 776 } |
OLD | NEW |