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

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

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.omnibox;
6
7 import static org.chromium.chrome.browser.toolbar.ToolbarPhone.URL_FOCUS_CHANGE_ ANIMATION_DURATION_MS;
8
9 import android.animation.Animator;
10 import android.animation.AnimatorListenerAdapter;
11 import android.animation.AnimatorSet;
12 import android.animation.ObjectAnimator;
13 import android.annotation.SuppressLint;
14 import android.app.Activity;
15 import android.content.ClipData;
16 import android.content.ClipboardManager;
17 import android.content.ContentResolver;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.res.ColorStateList;
21 import android.graphics.Color;
22 import android.graphics.PorterDuff;
23 import android.graphics.Rect;
24 import android.graphics.drawable.ColorDrawable;
25 import android.graphics.drawable.Drawable;
26 import android.net.Uri;
27 import android.os.Parcelable;
28 import android.os.SystemClock;
29 import android.provider.Settings;
30 import android.speech.RecognizerIntent;
31 import android.text.Editable;
32 import android.text.InputType;
33 import android.text.Selection;
34 import android.text.TextUtils;
35 import android.text.TextWatcher;
36 import android.util.AttributeSet;
37 import android.util.Log;
38 import android.util.Pair;
39 import android.util.SparseArray;
40 import android.view.ActionMode;
41 import android.view.KeyEvent;
42 import android.view.LayoutInflater;
43 import android.view.Menu;
44 import android.view.MenuItem;
45 import android.view.MotionEvent;
46 import android.view.View;
47 import android.view.View.OnClickListener;
48 import android.view.ViewGroup;
49 import android.view.ViewStub;
50 import android.view.inputmethod.BaseInputConnection;
51 import android.widget.FrameLayout;
52 import android.widget.ImageButton;
53 import android.widget.ImageView;
54 import android.widget.ListView;
55
56 import com.google.android.apps.chrome.R;
57
58 import org.chromium.base.ApiCompatibilityUtils;
59 import org.chromium.base.CollectionUtil;
60 import org.chromium.base.CommandLine;
61 import org.chromium.base.VisibleForTesting;
62 import org.chromium.base.metrics.RecordHistogram;
63 import org.chromium.base.metrics.RecordUserAction;
64 import org.chromium.chrome.browser.ChromeSwitches;
65 import org.chromium.chrome.browser.ContextualMenuBar;
66 import org.chromium.chrome.browser.ContextualMenuBar.ActionBarDelegate;
67 import org.chromium.chrome.browser.CustomSelectionActionModeCallback;
68 import org.chromium.chrome.browser.Tab;
69 import org.chromium.chrome.browser.WebsiteSettingsPopup;
70 import org.chromium.chrome.browser.WindowDelegate;
71 import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
72 import org.chromium.chrome.browser.document.BrandColorUtils;
73 import org.chromium.chrome.browser.dom_distiller.DomDistillerServiceFactory;
74 import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
75 import org.chromium.chrome.browser.ntp.NativePageFactory;
76 import org.chromium.chrome.browser.ntp.NewTabPage;
77 import org.chromium.chrome.browser.ntp.NewTabPage.FakeboxDelegate;
78 import org.chromium.chrome.browser.ntp.NewTabPageUma;
79 import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsR eceivedListener;
80 import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultIt em;
81 import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxSuggesti onDelegate;
82 import org.chromium.chrome.browser.omnibox.OmniboxSuggestion.Type;
83 import org.chromium.chrome.browser.omnibox.VoiceSuggestionProvider.VoiceResult;
84 import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
85 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager ;
86 import org.chromium.chrome.browser.profiles.Profile;
87 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
88 import org.chromium.chrome.browser.ssl.ConnectionSecurityHelperSecurityLevel;
89 import org.chromium.chrome.browser.tab.BackgroundContentViewHelper;
90 import org.chromium.chrome.browser.tab.ChromeTab;
91 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
92 import org.chromium.chrome.browser.util.FeatureUtilities;
93 import org.chromium.chrome.browser.util.KeyNavigationUtil;
94 import org.chromium.chrome.browser.util.ViewUtils;
95 import org.chromium.chrome.browser.widget.TintedImageButton;
96 import org.chromium.components.dom_distiller.core.DomDistillerService;
97 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
98 import org.chromium.content.browser.ContentViewCore;
99 import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
100 import org.chromium.content_public.browser.LoadUrlParams;
101 import org.chromium.content_public.browser.WebContents;
102 import org.chromium.ui.UiUtils;
103 import org.chromium.ui.base.DeviceFormFactor;
104 import org.chromium.ui.base.PageTransition;
105 import org.chromium.ui.base.WindowAndroid;
106 import org.chromium.ui.interpolators.BakedBezierInterpolator;
107
108 import java.util.ArrayList;
109 import java.util.HashSet;
110 import java.util.List;
111
112 /**
113 * This class represents the location bar where the user types in URLs and
114 * search terms.
115 */
116 public class LocationBarLayout extends FrameLayout implements OnClickListener,
117 OnSuggestionsReceivedListener, LocationBar, FakeboxDelegate,
118 WindowAndroid.IntentCallback {
119
120 // Delay triggering the omnibox results upon key press to allow the location bar to repaint
121 // with the new characters.
122 private static final long OMNIBOX_SUGGESTION_START_DELAY_MS = 30;
123
124 private static final int OMNIBOX_CONTAINER_BACKGROUND_FADE_MS = 250;
125
126 // The minimum confidence threshold that will result in navigating directly to a voice search
127 // response (as opposed to treating it like a typed string in the Omnibox).
128 private static final float VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD = 0.9f ;
129
130 private static final int CONTENT_OVERLAY_COLOR = Color.argb(166, 0, 0, 0);
131 private static final int OMNIBOX_RESULTS_BG_COLOR = Color.rgb(245, 245, 246) ;
132 private static final int OMNIBOX_INCOGNITO_RESULTS_BG_COLOR = Color.rgb(50, 50, 50);
133
134 /**
135 * URI schemes that ContentView can handle.
136 *
137 * Copied from UrlUtilities.java. UrlUtilities uses a URI to check for sche mes, which
138 * is more strict than Uri and causes the path stripping to fail.
139 *
140 * The following additions have been made: "chrome", "ftp".
141 */
142 private static final HashSet<String> ACCEPTED_SCHEMES = CollectionUtil.newHa shSet(
143 "about", "data", "file", "ftp", "http", "https", "inline", "javascri pt", "chrome");
144 private static final HashSet<String> UNSUPPORTED_SCHEMES_TO_SPLIT =
145 CollectionUtil.newHashSet("file", "javascript", "data");
146
147 protected ImageView mNavigationButton;
148 protected ImageButton mSecurityButton;
149 protected TintedImageButton mDeleteButton;
150 protected TintedImageButton mMicButton;
151 protected UrlBar mUrlBar;
152 protected UrlContainer mUrlContainer;
153 private ContextualMenuBar mContextualMenuBar = null;
154
155 private AutocompleteController mAutocomplete;
156
157 private ToolbarDataProvider mToolbarDataProvider;
158 private UrlFocusChangeListener mUrlFocusChangeListener;
159
160 private boolean mNativeInitialized;
161
162 private final List<Runnable> mDeferredNativeRunnables = new ArrayList<Runnab le>();
163
164 // The type of the navigation button currently showing.
165 private NavigationButtonType mNavigationButtonType;
166
167 // The type of the security icon currently active.
168 private int mSecurityIconType;
169
170 private final OmniboxResultsAdapter mSuggestionListAdapter;
171 private OmniboxSuggestionsList mSuggestionList;
172
173 private final List<OmniboxResultItem> mSuggestionItems;
174
175 /**
176 * The text shown in the URL bar (user text + inline autocomplete) after the most recent set of
177 * omnibox suggestions was received. When the user presses enter in the omni box, this value is
178 * compared to the URL bar text to determine whether the first suggestion is still valid.
179 */
180 private String mUrlTextAfterSuggestionsReceived;
181
182 // Set to true when the URL bar text is modified programmatically. Initially set
183 // to true until the old state has been loaded.
184 private boolean mIgnoreURLBarModification = true;
185 private boolean mIgnoreOmniboxItemSelection = true;
186
187 private boolean mLastUrlEditWasDelete = false;
188
189 // True if we are showing the search query instead of the url.
190 private boolean mQueryInTheOmnibox = false;
191
192 private String mOriginalUrl = "";
193
194 private WindowAndroid mWindowAndroid;
195 private WindowDelegate mWindowDelegate;
196
197 private Runnable mRequestSuggestions;
198
199 private ViewGroup mOmniboxResultsContainer;
200 private ObjectAnimator mFadeInOmniboxBackgroundAnimator;
201 private ObjectAnimator mFadeOutOmniboxBackgroundAnimator;
202 private Animator mOmniboxBackgroundAnimator;
203
204 private boolean mSuggestionsShown;
205 private boolean mUrlHasFocus;
206 private boolean mUrlFocusedFromFakebox;
207 private boolean mHasRecordedUrlFocusSource;
208
209 // Set to true when the user has started typing new input in the omnibox, se t to false
210 // when the omnibox loses focus or becomes empty.
211 private boolean mHasStartedNewOmniboxEditSession;
212 // The timestamp (using SystemClock.elapsedRealtime()) at the point when the user started
213 // modifying the omnibox with new input.
214 private long mNewOmniboxEditSessionTimestamp = -1;
215
216 private boolean mSecurityButtonShown;
217
218 private AnimatorSet mLocationBarIconActiveAnimator;
219 private AnimatorSet mSecurityButtonShowAnimator;
220 private AnimatorSet mNavigationIconShowAnimator;
221
222 private TextWatcher mTextWatcher;
223
224 private OmniboxPrerender mOmniboxPrerender;
225
226 private View mFocusedTabView;
227 private int mFocusedTabImportantForAccessibilityState;
228 private BrowserAccessibilityManager mFocusedTabAccessibilityManager;
229
230 // True if we are showing original url for preview page. This is will be tru e when there is a
231 // background page loaded in background content view.
232 private boolean mShowingOriginalUrlForPreview;
233
234 private boolean mSuggestionModalShown;
235 private boolean mUseDarkColors;
236
237 // True if the user has just selected a suggestion from the suggestion list. This suppresses
238 // the recording of the dismissal of the suggestion list. (The list is only considered to have
239 // been dismissed if the user didn't choose one of the suggestions shown.) T his signal is used
240 // instead of a parameter to hideSuggestions because that method is often ca lled from multiple
241 // code paths in a not necessarily obvious or even deterministic order.
242 private boolean mSuggestionSelectionInProgress;
243
244 private CustomSelectionActionModeCallback mDefaultActionModeCallbackForTextE dit;
245
246 /**
247 * Listener for receiving the messages related with interacting with the omn ibox during startup.
248 */
249 public interface OmniboxLivenessListener {
250 /**
251 * Called after the first draw when the omnibox can receive touch events .
252 */
253 void onOmniboxInteractive();
254
255 /**
256 * Called when the native libraries are loaded and listeners with native components
257 * have been initialized.
258 */
259 void onOmniboxFullyFunctional();
260
261 /**
262 * Called when the omnibox is focused.
263 */
264 void onOmniboxFocused();
265 }
266
267 /**
268 * Class to handle text changes in the URL bar, ensuring that the appropriat e
269 * buttons are displayed as the text changes, and requesting suggestions.
270 */
271 private final class UrlBarTextWatcher implements TextWatcher {
272 @Override
273 public void afterTextChanged(final Editable editableText) {
274 updateDeleteButtonVisibility();
275 updateNavigationButton();
276
277 if (mIgnoreURLBarModification) return;
278
279 if (!mHasStartedNewOmniboxEditSession && mNativeInitialized) {
280 RecordUserAction.record("MobileFirstEditInOmnibox");
281 mAutocomplete.resetSession();
282 mHasStartedNewOmniboxEditSession = true;
283 mNewOmniboxEditSessionTimestamp = SystemClock.elapsedRealtime();
284 }
285
286 if (!isInTouchMode() && mSuggestionList != null) {
287 mSuggestionList.setSelection(0);
288 }
289
290 final String textWithoutAutocomplete = mUrlBar.getTextWithoutAutocom plete();
291
292 stopAutocomplete(false);
293 if (TextUtils.isEmpty(textWithoutAutocomplete)) {
294 hideSuggestions();
295 startZeroSuggest();
296 } else {
297 assert mRequestSuggestions == null : "Multiple omnibox requests in flight.";
298 mRequestSuggestions = new Runnable() {
299 @Override
300 public void run() {
301 boolean preventAutocomplete = !shouldAutocomplete()
302 || (editableText != null && Selection.getSelecti onEnd(editableText)
303 != editableText.length());
304 mRequestSuggestions = null;
305 if (getCurrentTab() == null) return;
306 mAutocomplete.start(
307 getCurrentTab().getProfile(),
308 getCurrentTab().getUrl(),
309 textWithoutAutocomplete, preventAutocomplete);
310 }
311 };
312 if (mNativeInitialized) {
313 postDelayed(mRequestSuggestions, OMNIBOX_SUGGESTION_START_DE LAY_MS);
314 } else {
315 mDeferredNativeRunnables.add(mRequestSuggestions);
316 }
317 }
318
319 // Occasionally, was seeing the selection in the URL not being clear ed during
320 // very rapid editing. This is here to hopefully force a selection reset during
321 // deletes.
322 if (mLastUrlEditWasDelete) mUrlBar.setSelection(mUrlBar.getSelection Start());
323 }
324
325 @Override
326 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
327 cancelPendingAutocompleteStart();
328 }
329
330 @Override
331 public void onTextChanged(CharSequence s, int start, int before, int cou nt) {
332 // We need to determine whether the text change was triggered by a d elete (so we
333 // don't autocomplete of the entered text in that case). With soft-k eyboard, there
334 // is no way to know that the delete button was pressed, so we track text removal
335 // changes.
336 mLastUrlEditWasDelete = (count == 0);
337 }
338 }
339
340 /**
341 * Class to handle input from a hardware keyboard when the focus is on the U RL bar. In
342 * particular, handle navigating the suggestions list from the keyboard.
343 */
344 private final class UrlBarKeyListener implements OnKeyListener {
345 @Override
346 public boolean onKey(View v, int keyCode, KeyEvent event) {
347 if (KeyNavigationUtil.isGoDown(event)
348 && mSuggestionList != null
349 && mSuggestionList.isShown()) {
350 int suggestionCount = mSuggestionListAdapter.getCount();
351 if (mSuggestionList.getSelectedItemPosition() < suggestionCount - 1) {
352 if (suggestionCount > 0) mIgnoreOmniboxItemSelection = false ;
353 } else {
354 // Do not pass down events when the last item is already sel ected as it will
355 // dismiss the suggestion list.
356 return true;
357 }
358
359 if (mSuggestionList.getSelectedItemPosition()
360 == ListView.INVALID_POSITION) {
361 // When clearing the selection after a text change, state is not reset
362 // correctly so hitting down again will cause it to start fr om the previous
363 // selection point. We still have to send the key down event to let the list
364 // view items take focus, but then we select the first item explicitly.
365 boolean result = mSuggestionList.onKeyDown(keyCode, event);
366 mSuggestionList.setSelection(0);
367 return result;
368 } else {
369 return mSuggestionList.onKeyDown(keyCode, event);
370 }
371 } else if (KeyNavigationUtil.isGoUp(event)
372 && mSuggestionList != null
373 && mSuggestionList.isShown()) {
374 if (mSuggestionList.getSelectedItemPosition() != 0
375 && mSuggestionListAdapter.getCount() > 0) {
376 mIgnoreOmniboxItemSelection = false;
377 }
378 return mSuggestionList.onKeyDown(keyCode, event);
379 } else if (KeyNavigationUtil.isGoRight(event)
380 && mSuggestionList != null
381 && mSuggestionList.isShown()
382 && mSuggestionList.getSelectedItemPosition()
383 != ListView.INVALID_POSITION) {
384 OmniboxResultItem selectedItem =
385 (OmniboxResultItem) mSuggestionListAdapter.getItem(
386 mSuggestionList.getSelectedItemPosition());
387 // Set the UrlBar text to empty, so that it will trigger a text change when we
388 // set the text to the suggestion again.
389 setUrlBarText(null, null, "");
390 mUrlBar.setText(selectedItem.getSuggestion().getFillIntoEdit());
391 mSuggestionList.setSelection(0);
392 mUrlBar.setSelection(mUrlBar.getText().length());
393 return true;
394 } else if (KeyNavigationUtil.isEnter(event)
395 && LocationBarLayout.this.getVisibility() == VISIBLE) {
396 UiUtils.hideKeyboard(mUrlBar);
397 mSuggestionSelectionInProgress = true;
398 final String urlText = mUrlBar.getQueryText();
399 if (mNativeInitialized) {
400 findMatchAndLoadUrl(urlText);
401 } else {
402 mDeferredNativeRunnables.add(new Runnable() {
403 @Override
404 public void run() {
405 findMatchAndLoadUrl(urlText);
406 }
407 });
408 }
409 return true;
410 }
411
412 return false;
413 }
414
415 private void findMatchAndLoadUrl(String urlText) {
416 int suggestionMatchPosition;
417 OmniboxSuggestion suggestionMatch;
418
419 if (mSuggestionList != null
420 && mSuggestionList.isShown()
421 && mSuggestionList.getSelectedItemPosition()
422 != ListView.INVALID_POSITION) {
423 // Bluetooth keyboard case: the user highlighted a suggestion wi th the arrow
424 // keys, then pressed enter.
425 suggestionMatchPosition = mSuggestionList.getSelectedItemPositio n();
426 OmniboxResultItem selectedItem =
427 (OmniboxResultItem) mSuggestionListAdapter.getItem(sugge stionMatchPosition);
428 suggestionMatch = selectedItem.getSuggestion();
429 } else if (!mSuggestionItems.isEmpty()
430 && urlText.equals(mUrlTextAfterSuggestionsReceived)) {
431 // Common case: the user typed something, received suggestions, then pressed enter.
432 suggestionMatch = mSuggestionItems.get(0).getSuggestion();
433 suggestionMatchPosition = 0;
434 } else {
435 // Less common case: there are no valid omnibox suggestions. Thi s can happen if the
436 // user tapped the URL bar to dismiss the suggestions, then pres sed enter. This can
437 // also happen if the user presses enter before any suggestions have been received
438 // from the autocomplete controller.
439 suggestionMatch = mAutocomplete.classify(urlText);
440 suggestionMatchPosition = 0;
441
442 // If urlText couldn't be classified, bail.
443 if (suggestionMatch == null) return;
444 }
445
446 String suggestionMatchUrl = updateSuggestionUrlIfNeeded(suggestionMa tch,
447 suggestionMatchPosition);
448
449 // It's important to use the page transition from the suggestion or we might end
450 // up saving generated URLs as typed URLs, which would then pollute the subsequent
451 // omnibox results.
452 loadUrlFromOmniboxMatch(suggestionMatchUrl, suggestionMatch.getTrans ition(),
453 suggestionMatchPosition, suggestionMatch.getType());
454 }
455 }
456
457 /**
458 * Specifies the types of buttons shown to signify different types of naviga tion elements.
459 */
460 protected enum NavigationButtonType {
461 PAGE,
462 MAGNIFIER,
463 EMPTY,
464 }
465
466 /**
467 * @param outRect Populated with a {@link Rect} that represents the {@link T ab} specific content
468 * of this {@link LocationBar}.
469 */
470 public void getContentRect(Rect outRect) {
471 outRect.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRi ght(),
472 getHeight() - getPaddingBottom());
473 }
474
475 /**
476 * A widget for showing a list of omnibox suggestions.
477 */
478 @VisibleForTesting
479 public class OmniboxSuggestionsList extends ListView {
480 private final int mSuggestionHeight;
481 private final int mSuggestionAnswerHeight;
482 private final View mAnchorView;
483
484 private final int[] mTempPosition = new int[2];
485 private final Rect mTempRect = new Rect();
486
487 private final int mBackgroundVerticalPadding;
488
489 private float mMaxRequiredWidth;
490 private float mMaxMatchContentsWidth;
491
492 /**
493 * Constructs a new list designed for containing omnibox suggestions.
494 * @param context Context used for contained views.
495 */
496 public OmniboxSuggestionsList(Context context) {
497 super(context, null, android.R.attr.dropDownListViewStyle);
498 setDivider(null);
499 setFocusable(true);
500 setFocusableInTouchMode(true);
501
502 mSuggestionHeight = context.getResources().getDimensionPixelOffset(
503 R.dimen.omnibox_suggestion_height);
504 mSuggestionAnswerHeight = context.getResources().getDimensionPixelOf fset(
505 R.dimen.omnibox_suggestion_answer_height);
506
507 int paddingTop = context.getResources().getDimensionPixelOffset(
508 R.dimen.omnibox_suggestion_list_padding_top);
509 int paddingBottom = context.getResources().getDimensionPixelOffset(
510 R.dimen.omnibox_suggestion_list_padding_bottom);
511 ApiCompatibilityUtils.setPaddingRelative(this, 0, paddingTop, 0, pad dingBottom);
512
513 Drawable background = getSuggestionPopupBackground();
514 setBackground(background);
515 background.getPadding(mTempRect);
516
517 mBackgroundVerticalPadding =
518 mTempRect.top + mTempRect.bottom + getPaddingTop() + getPadd ingBottom();
519
520 mAnchorView = LocationBarLayout.this.getRootView().findViewById(R.id .toolbar);
521 }
522
523 private void show() {
524 updateLayoutParams();
525 if (getVisibility() != VISIBLE) {
526 mIgnoreOmniboxItemSelection = true; // Reset to default value.
527 setVisibility(VISIBLE);
528 if (getSelectedItemPosition() != 0) setSelection(0);
529 }
530 updateSuggestionsLayoutDirection(mUrlBar.getUrlDirection());
531 }
532
533 /**
534 * Invalidates all of the suggestion views in the list. Only applicable when this
535 * is visible.
536 */
537 public void invalidateSuggestionViews() {
538 if (!isShown()) return;
539 ListView suggestionsList = mSuggestionList;
540 for (int i = 0; i < suggestionsList.getChildCount(); i++) {
541 if (suggestionsList.getChildAt(i) instanceof SuggestionView) {
542 suggestionsList.getChildAt(i).postInvalidateOnAnimation();
543 }
544 }
545 }
546
547 /**
548 * Updates the maximum widths required to render the suggestions.
549 * This is needed for infinite suggestions where we try to vertically al ign the leading
550 * ellipsis.
551 */
552 public void resetMaxTextWidths() {
553 mMaxRequiredWidth = 0;
554 mMaxMatchContentsWidth = 0;
555 }
556
557 /**
558 * Updates the max text width values for the suggestions.
559 * @param requiredWidth a new required width.
560 * @param matchContentsWidth a new match contents width.
561 */
562 public void updateMaxTextWidths(float requiredWidth, float matchContents Width) {
563 mMaxRequiredWidth = Math.max(mMaxRequiredWidth, requiredWidth);
564 mMaxMatchContentsWidth = Math.max(mMaxMatchContentsWidth, matchConte ntsWidth);
565 }
566
567 /**
568 * @return max required width for the suggestions.
569 */
570 public float getMaxRequiredWidth() {
571 return mMaxRequiredWidth;
572 }
573
574 /**
575 * @return max match contents width for the suggestions.
576 */
577 public float getMaxMatchContentsWidth() {
578 return mMaxMatchContentsWidth;
579 }
580
581 private void updateLayoutParams() {
582 boolean updateLayout = false;
583 FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) g etLayoutParams();
584 if (layoutParams == null) {
585 layoutParams = new FrameLayout.LayoutParams(0, 0);
586 setLayoutParams(layoutParams);
587 }
588
589 // Compare the relative positions of the anchor view to the list par ent view to
590 // determine the offset to apply to the suggestions list. By using layout positioning,
591 // this avoids issues where getLocationInWindow can be inaccurate on certain devices.
592 View contentView =
593 LocationBarLayout.this.getRootView().findViewById(android.R. id.content);
594 ViewUtils.getRelativeLayoutPosition(contentView, mAnchorView, mTempP osition);
595 int anchorX = mTempPosition[0];
596 int anchorY = mTempPosition[1];
597
598 ViewUtils.getRelativeLayoutPosition(contentView, (View) getParent(), mTempPosition);
599 int parentY = mTempPosition[1];
600
601 int anchorBottomRelativeToContent = anchorY + mAnchorView.getMeasure dHeight();
602 int desiredTopMargin = anchorBottomRelativeToContent - parentY;
603 if (layoutParams.topMargin != desiredTopMargin) {
604 layoutParams.topMargin = desiredTopMargin;
605 updateLayout = true;
606 }
607
608 int contentLeft = contentView.getLeft();
609 int anchorLeftRelativeToContent = anchorX - contentLeft;
610 if (layoutParams.leftMargin != anchorLeftRelativeToContent) {
611 layoutParams.leftMargin = anchorLeftRelativeToContent;
612 updateLayout = true;
613 }
614
615 getWindowDelegate().getWindowVisibleDisplayFrame(mTempRect);
616 int decorHeight = getWindowDelegate().getDecorViewHeight();
617 int availableViewportHeight = Math.min(mTempRect.height(), decorHeig ht);
618 int availableListHeight = availableViewportHeight - anchorBottomRela tiveToContent;
619 int desiredHeight = Math.min(availableListHeight, getIdealHeight());
620 if (layoutParams.height != desiredHeight) {
621 layoutParams.height = desiredHeight;
622 updateLayout = true;
623 }
624
625 int desiredWidth = getDesiredWidth();
626 if (layoutParams.width != desiredWidth) {
627 layoutParams.width = desiredWidth;
628 updateLayout = true;
629 }
630
631 if (updateLayout) requestLayout();
632 }
633
634 private int getIdealHeight() {
635 int idealListSize = mBackgroundVerticalPadding;
636 for (int i = 0; i < mSuggestionItems.size(); i++) {
637 OmniboxResultItem item = mSuggestionItems.get(i);
638 if (!TextUtils.isEmpty(item.getSuggestion().getAnswerContents()) ) {
639 idealListSize += mSuggestionAnswerHeight;
640 } else {
641 idealListSize += mSuggestionHeight;
642 }
643 }
644 return idealListSize;
645 }
646
647 private int getDesiredWidth() {
648 return mAnchorView.getWidth();
649 }
650
651 @Override
652 public void onWindowFocusChanged(boolean hasWindowFocus) {
653 super.onWindowFocusChanged(hasWindowFocus);
654 if (!hasWindowFocus && !mSuggestionModalShown) hideSuggestions();
655 }
656
657 @Override
658 protected void layoutChildren() {
659 super.layoutChildren();
660 // In ICS, the selected view is not marked as selected despite calli ng setSelection(0),
661 // so we bootstrap this after the children have been laid out.
662 if (!isInTouchMode() && getSelectedView() != null) {
663 getSelectedView().setSelected(true);
664 }
665 }
666 }
667
668 public LocationBarLayout(Context context, AttributeSet attrs) {
669 super(context, attrs);
670
671 LayoutInflater.from(context).inflate(R.layout.location_bar, this, true);
672 mNavigationButton = (ImageView) findViewById(R.id.navigation_button);
673 assert mNavigationButton != null : "Missing navigation type view.";
674 mNavigationButtonType = DeviceFormFactor.isTablet(context)
675 ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
676
677 mSecurityButton = (ImageButton) findViewById(R.id.security_button);
678 mSecurityIconType = ConnectionSecurityHelperSecurityLevel.NONE;
679
680 mDeleteButton = (TintedImageButton) findViewById(R.id.delete_button);
681
682 mUrlBar = (UrlBar) findViewById(R.id.url_bar);
683 // The HTC Sense IME will attempt to autocomplete words in the Omnibox w hen Prediction is
684 // enabled. We want to disable this feature and rely on the Omnibox's i mplementation.
685 // Their IME does not respect ~TYPE_TEXT_FLAG_AUTO_COMPLETE nor any of t he other InputType
686 // options I tried, but setting the filter variation prevents it. Sadly , it also removes
687 // the .com button, but the prediction was buggy as it would autocomplet e words even when
688 // typing at the beginning of the omnibox text when other content was pr esent (messing up
689 // what was previously there). See bug: http://b/issue?id=6200071
690 String defaultIme = Settings.Secure.getString(getContext().getContentRes olver(),
691 Settings.Secure.DEFAULT_INPUT_METHOD);
692 if (defaultIme != null && defaultIme.contains("com.htc.android.htcime")) {
693 mUrlBar.setInputType(mUrlBar.getInputType() | InputType.TYPE_TEXT_VA RIATION_FILTER);
694 }
695 mUrlBar.setDelegate(this);
696
697 mUrlContainer = (UrlContainer) findViewById(R.id.url_container);
698
699 mSuggestionItems = new ArrayList<OmniboxResultItem>();
700 mSuggestionListAdapter = new OmniboxResultsAdapter(getContext(), this, m SuggestionItems);
701
702 mMicButton = (TintedImageButton) findViewById(R.id.mic_button);
703 }
704
705 @Override
706 protected void onFinishInflate() {
707 super.onFinishInflate();
708
709 mUrlBar.setCursorVisible(false);
710 mNavigationButton.setVisibility(VISIBLE);
711 mSecurityButton.setVisibility(INVISIBLE);
712
713 setLayoutTransition(null);
714
715 AnimatorListenerAdapter iconChangeAnimatorListener = new AnimatorListene rAdapter() {
716 @Override
717 public void onAnimationEnd(Animator animation) {
718 if (animation == mSecurityButtonShowAnimator) {
719 mNavigationButton.setVisibility(INVISIBLE);
720 } else if (animation == mNavigationIconShowAnimator) {
721 mSecurityButton.setVisibility(INVISIBLE);
722 }
723 }
724
725 @Override
726 public void onAnimationStart(Animator animation) {
727 if (animation == mSecurityButtonShowAnimator) {
728 mSecurityButton.setVisibility(VISIBLE);
729 } else if (animation == mNavigationIconShowAnimator) {
730 mNavigationButton.setVisibility(VISIBLE);
731 }
732 }
733 };
734
735 mSecurityButtonShowAnimator = new AnimatorSet();
736 mSecurityButtonShowAnimator.playTogether(
737 ObjectAnimator.ofFloat(mNavigationButton, ALPHA, 0),
738 ObjectAnimator.ofFloat(mSecurityButton, ALPHA, 1));
739 mSecurityButtonShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURAT ION_MS);
740 mSecurityButtonShowAnimator.addListener(iconChangeAnimatorListener);
741
742 mNavigationIconShowAnimator = new AnimatorSet();
743 mNavigationIconShowAnimator.playTogether(
744 ObjectAnimator.ofFloat(mNavigationButton, ALPHA, 1),
745 ObjectAnimator.ofFloat(mSecurityButton, ALPHA, 0));
746 mNavigationIconShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURAT ION_MS);
747 mNavigationIconShowAnimator.addListener(iconChangeAnimatorListener);
748
749 mUrlBar.setOnKeyListener(new UrlBarKeyListener());
750
751 mTextWatcher = new UrlBarTextWatcher();
752 mUrlBar.setLocationBarTextWatcher(mTextWatcher);
753
754 // mLocationBar's direction is tied to this UrlBar's text direction. Ico ns inside the
755 // location bar, e.g. lock, refresh, X, should be reversed if UrlBar's t ext is RTL.
756 mUrlBar.setUrlDirectionListener(new UrlBar.UrlDirectionListener() {
757 @Override
758 public void onUrlDirectionChanged(int layoutDirection) {
759 ApiCompatibilityUtils.setLayoutDirection(LocationBarLayout.this, layoutDirection);
760 updateSuggestionsLayoutDirection(layoutDirection);
761 }
762 });
763
764 mUrlBar.setSelectAllOnFocus(true);
765 }
766
767 @Override
768 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
769 updateLayoutParams();
770 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
771 }
772
773 private void updateSuggestionsLayoutDirection(int layoutDirection) {
774 if (mSuggestionList != null && mSuggestionList.isShown()) {
775 ListView listView = mSuggestionList;
776 ApiCompatibilityUtils.setLayoutDirection(listView, layoutDirection);
777 for (int i = 0; i < listView.getChildCount(); i++) {
778 ApiCompatibilityUtils.setLayoutDirection(listView.getChildAt(i),
779 layoutDirection);
780 }
781 }
782 }
783
784 @Override
785 public void initializeControls(WindowDelegate windowDelegate,
786 ActionBarDelegate actionBarDelegate, WindowAndroid windowAndroid) {
787 mWindowDelegate = windowDelegate;
788
789 mContextualMenuBar = new ContextualMenuBar(getContext(), actionBarDelega te);
790 mContextualMenuBar.setCustomSelectionActionModeCallback(
791 new CustomSelectionActionModeCallback() {
792 @Override
793 public boolean onPrepareActionMode(ActionMode mode, Menu men u) {
794 super.onPrepareActionMode(mode, menu);
795 mode.getMenuInflater().inflate(R.menu.textselectionmenu, menu);
796 return true;
797 }
798
799 @Override
800 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
801 if (item.getItemId() == R.id.copy_url) {
802 ClipboardManager clipboard =
803 (ClipboardManager) getContext().getSystemSer vice(
804 Context.CLIPBOARD_SERVICE);
805 ClipData clip = ClipData.newPlainText("url", mOrigin alUrl);
806 clipboard.setPrimaryClip(clip);
807 mode.finish();
808 return true;
809 } else {
810 return super.onActionItemClicked(mode, item);
811 }
812 }
813 });
814
815 mWindowAndroid = windowAndroid;
816 mMicButton.setOnClickListener(this);
817 }
818
819 /**
820 * @return The WindowDelegate for the LocationBar. This should be used for a ll Window related
821 * state queries.
822 */
823 protected WindowDelegate getWindowDelegate() {
824 return mWindowDelegate;
825 }
826
827 /**
828 * Handles native dependent initialization for this class.
829 */
830 @Override
831 public void onNativeLibraryReady() {
832 mNativeInitialized = true;
833
834 mSecurityButton.setOnClickListener(this);
835 mNavigationButton.setOnClickListener(this);
836 updateMicButtonState();
837 mDeleteButton.setOnClickListener(this);
838
839 mAutocomplete = new AutocompleteController(this);
840
841 mOmniboxPrerender = new OmniboxPrerender();
842
843 for (Runnable deferredRunnable : mDeferredNativeRunnables) {
844 post(deferredRunnable);
845 }
846 mDeferredNativeRunnables.clear();
847
848 mUrlBar.onOmniboxFullyFunctional();
849
850 updateCustomSelectionActionModeCallback();
851 updateVisualsForState();
852 }
853
854 /**
855 * @return Whether or not to animate icon changes.
856 */
857 protected boolean shouldAnimateIconChanges() {
858 return mUrlHasFocus;
859 }
860
861 /**
862 * Sets the autocomplete controller for the location bar.
863 *
864 * @param controller The controller that will handle autocomplete/omnibox su ggestions.
865 * @note Only used for testing.
866 */
867 @VisibleForTesting
868 public void setAutocompleteController(AutocompleteController controller) {
869 mAutocomplete = controller;
870 }
871
872 /**
873 * Updates the profile used for generating autocomplete suggestions.
874 * @param profile The profile to be used.
875 */
876 @Override
877 public void setAutocompleteProfile(Profile profile) {
878 // This will only be called once at least one tab exists, and the tab mo del is told to
879 // update its state. During Chrome initialization the tab model update h appens after the
880 // call to onNativeLibraryReady, so this assert will not fire.
881 assert mNativeInitialized :
882 "Setting Autocomplete Profile before native side initialized";
883 mAutocomplete.setProfile(profile);
884 mOmniboxPrerender.initializeForProfile(profile);
885 }
886
887 private void changeLocationBarIcon(boolean showSecurityButton) {
888 if (mLocationBarIconActiveAnimator != null && mLocationBarIconActiveAnim ator.isRunning()) {
889 mLocationBarIconActiveAnimator.cancel();
890 }
891 View viewToBeShown = showSecurityButton ? mSecurityButton : mNavigationB utton;
892 if (viewToBeShown.getVisibility() == VISIBLE && viewToBeShown.getAlpha() == 1) {
893 return;
894 }
895 if (showSecurityButton) {
896 mLocationBarIconActiveAnimator = mSecurityButtonShowAnimator;
897 } else {
898 mLocationBarIconActiveAnimator = mNavigationIconShowAnimator;
899 }
900 if (shouldAnimateIconChanges()) {
901 mLocationBarIconActiveAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATIO N_DURATION_MS);
902 } else {
903 mLocationBarIconActiveAnimator.setDuration(0);
904 }
905 mLocationBarIconActiveAnimator.start();
906 }
907
908 @Override
909 public void onUrlPreFocusChanged(boolean gainFocus) {
910 if (mToolbarDataProvider == null || mToolbarDataProvider.getTab() == nul l) return;
911
912 if (!mQueryInTheOmnibox
913 && FeatureUtilities.isDocumentMode(getContext())
914 && !TextUtils.isEmpty(mUrlBar.getText())) {
915 mUrlBar.setUrl(mToolbarDataProvider.getTab().getUrl(), null);
916 }
917 }
918
919 @Override
920 public void setUrlBarFocus(boolean shouldBeFocused) {
921 if (shouldBeFocused) {
922 mUrlBar.requestFocus();
923 } else {
924 mUrlBar.clearFocus();
925 }
926 }
927
928 @Override
929 public long getFirstUrlBarFocusTime() {
930 return mUrlBar.getFirstFocusTime();
931 }
932
933 /**
934 * Triggered when the URL input field has gained or lost focus.
935 * @param hasFocus Whether the URL field has gained focus.
936 */
937 public void onUrlFocusChange(boolean hasFocus) {
938 mUrlHasFocus = hasFocus;
939 updateFocusSource(hasFocus);
940 updateDeleteButtonVisibility();
941 Tab currentTab = getCurrentTab();
942 if (hasFocus) {
943 mUrlBar.deEmphasizeUrl();
944 } else {
945 hideSuggestions();
946
947 // Focus change caused by a close-tab may result in an invalid curre nt tab.
948 if (currentTab != null) {
949 setUrlToPageUrl();
950 emphasizeUrl();
951 }
952 }
953
954 if (getToolbarDataProvider().isUsingBrandColor()) {
955 updateVisualsForState();
956 if (mUrlHasFocus) mUrlBar.selectAll();
957 }
958
959 if (mUrlFocusChangeListener != null) mUrlFocusChangeListener.onUrlFocusC hange(hasFocus);
960 changeLocationBarIcon(
961 (!DeviceFormFactor.isTablet(getContext()) || !hasFocus) && isSec urityButtonShown());
962 mUrlBar.setCursorVisible(hasFocus);
963 if (mQueryInTheOmnibox) mUrlBar.setSelection(mUrlBar.getSelectionEnd());
964
965 updateOmniboxResultsContainer();
966 if (hasFocus) updateOmniboxResultsContainerBackground(true);
967
968 if (hasFocus && currentTab != null && !currentTab.isIncognito()) {
969 if (mNativeInitialized
970 && TemplateUrlService.getInstance().isDefaultSearchEngineGoo gle()) {
971 GeolocationHeader.primeLocationForGeoHeader(getContext());
972 } else {
973 mDeferredNativeRunnables.add(new Runnable() {
974 @Override
975 public void run() {
976 if (TemplateUrlService.getInstance().isDefaultSearchEngi neGoogle()) {
977 GeolocationHeader.primeLocationForGeoHeader(getConte xt());
978 }
979 }
980 });
981 }
982 }
983
984 if (mNativeInitialized) {
985 startZeroSuggest();
986 } else {
987 mDeferredNativeRunnables.add(new Runnable() {
988 @Override
989 public void run() {
990 if (TextUtils.isEmpty(mUrlBar.getQueryText())) {
991 startZeroSuggest();
992 }
993 }
994 });
995 }
996
997 // Add and remove text watcher from the URL bar with focus, so that it's
998 // not called when we modify the displayed information on focus.
999 if (hasFocus) {
1000 mUrlBar.addTextChangedListener(mTextWatcher);
1001 } else {
1002 mUrlBar.removeTextChangedListener(mTextWatcher);
1003 }
1004
1005 if (!hasFocus) {
1006 mHasStartedNewOmniboxEditSession = false;
1007 mNewOmniboxEditSessionTimestamp = -1;
1008 }
1009 }
1010
1011 /**
1012 * Make a zero suggest request if native is loaded, the URL bar has focus, a nd the
1013 * current tab is not incognito.
1014 */
1015 private void startZeroSuggest() {
1016 // Reset "edited" state in the omnibox if zero suggest is triggered -- n ew edits
1017 // now count as a new session.
1018 mHasStartedNewOmniboxEditSession = false;
1019 mNewOmniboxEditSessionTimestamp = -1;
1020 Tab currentTab = getCurrentTab();
1021 if (mNativeInitialized
1022 && mUrlHasFocus
1023 && currentTab != null
1024 && !currentTab.isIncognito()) {
1025 mAutocomplete.startZeroSuggest(currentTab.getProfile(), mUrlBar.getQ ueryText(),
1026 currentTab.getUrl(), mQueryInTheOmnibox, mUrlFocusedFromFake box);
1027 }
1028 }
1029
1030 @Override
1031 public void setDefaultTextEditActionModeCallback(CustomSelectionActionModeCa llback callback) {
1032 mDefaultActionModeCallbackForTextEdit = callback;
1033 }
1034
1035 /**
1036 * If query in the omnibox, sets UrlBar's ActionModeCallback to show copy ur l button. Else,
1037 * it is set to the default one.
1038 */
1039 private void updateCustomSelectionActionModeCallback() {
1040 if (mQueryInTheOmnibox) {
1041 mUrlBar.setCustomSelectionActionModeCallback(
1042 mContextualMenuBar.getCustomSelectionActionModeCallback());
1043 } else {
1044 mUrlBar.setCustomSelectionActionModeCallback(mDefaultActionModeCallb ackForTextEdit);
1045 }
1046 }
1047
1048 @Override
1049 public void requestUrlFocusFromFakebox(String pastedText) {
1050 mUrlFocusedFromFakebox = true;
1051 mUrlBar.requestFocus();
1052
1053 if (pastedText != null) {
1054 // This must be happen after requestUrlFocus(), which changes the se lection.
1055 mUrlBar.setUrl(pastedText, null);
1056 mUrlBar.setSelection(mUrlBar.getText().length());
1057 }
1058 }
1059
1060 /**
1061 * Sets the toolbar that owns this LocationBar.
1062 */
1063 @Override
1064 public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
1065 mToolbarDataProvider = toolbarDataProvider;
1066
1067 mUrlBar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
1068 @Override
1069 public void onFocusChange(View v, final boolean hasFocus) {
1070 onUrlFocusChange(hasFocus);
1071 }
1072 });
1073 }
1074
1075 @Override
1076 public void setMenuButtonHelper(AppMenuButtonHelper helper) { }
1077
1078 @Override
1079 public View getMenuAnchor() {
1080 return null;
1081 }
1082
1083 /**
1084 * Sets the URL focus change listner that will be notified when the URL gain s or loses focus.
1085 * @param listener The listener to be registered.
1086 */
1087 @Override
1088 public void setUrlFocusChangeListener(UrlFocusChangeListener listener) {
1089 mUrlFocusChangeListener = listener;
1090 }
1091
1092 /**
1093 * @return The toolbar data provider.
1094 */
1095 @VisibleForTesting
1096 protected ToolbarDataProvider getToolbarDataProvider() {
1097 return mToolbarDataProvider;
1098 }
1099
1100 private static NavigationButtonType suggestionTypeToNavigationButtonType(
1101 OmniboxSuggestion.Type suggestionType) {
1102 switch (suggestionType) {
1103 case NAVSUGGEST:
1104 case HISTORY_URL:
1105 case URL_WHAT_YOU_TYPED:
1106 case HISTORY_TITLE:
1107 case HISTORY_BODY:
1108 case HISTORY_KEYWORD:
1109 return NavigationButtonType.PAGE;
1110 case SEARCH_WHAT_YOU_TYPED:
1111 case SEARCH_HISTORY:
1112 case SEARCH_SUGGEST:
1113 case SEARCH_SUGGEST_ENTITY:
1114 case SEARCH_SUGGEST_TAIL:
1115 case SEARCH_SUGGEST_PERSONALIZED:
1116 case SEARCH_SUGGEST_PROFILE:
1117 case VOICE_SUGGEST:
1118 case SEARCH_OTHER_ENGINE:
1119 case OPEN_HISTORY_PAGE:
1120 return NavigationButtonType.MAGNIFIER;
1121 default:
1122 assert false;
1123 return NavigationButtonType.MAGNIFIER;
1124 }
1125 }
1126
1127 // Updates the navigation button based on the URL string
1128 private void updateNavigationButton() {
1129 boolean isTablet = DeviceFormFactor.isTablet(getContext());
1130 NavigationButtonType type = NavigationButtonType.EMPTY;
1131 if (isTablet && !mSuggestionItems.isEmpty()) {
1132 // If there are suggestions showing, show the icon for the default s uggestion.
1133 type = suggestionTypeToNavigationButtonType(
1134 mSuggestionItems.get(0).getSuggestion().getType());
1135 } else if (mQueryInTheOmnibox) {
1136 type = NavigationButtonType.MAGNIFIER;
1137 } else if (isTablet) {
1138 type = NavigationButtonType.PAGE;
1139 }
1140
1141 if (type != mNavigationButtonType) setNavigationButtonType(type);
1142 }
1143
1144 /**
1145 * @return Whether the query is shown in the omnibox instead of the url.
1146 */
1147 public boolean showingQueryInTheOmnibox() {
1148 return mQueryInTheOmnibox;
1149 }
1150
1151 /**
1152 * @return Whether original url is shown for preview page.
1153 */
1154 @Override
1155 public boolean showingOriginalUrlForPreview() {
1156 return mShowingOriginalUrlForPreview;
1157 }
1158
1159 private int getSecurityLevel() {
1160 if (getCurrentTab() == null) return ConnectionSecurityHelperSecurityLeve l.NONE;
1161 return getCurrentTab().getSecurityLevel();
1162 }
1163
1164 /**
1165 * Determines the icon that should be displayed for the current security lev el.
1166 * @param securityLevel The security level for which the resource will be re turned.
1167 * @param usingLightTheme Whether light themed security assets should be use d.
1168 * @return The resource ID of the icon that should be displayed, 0 if no ico n should show.
1169 */
1170 public static int getSecurityIconResource(int securityLevel, boolean usingLi ghtTheme) {
1171 switch (securityLevel) {
1172 case ConnectionSecurityHelperSecurityLevel.NONE:
1173 return 0;
1174 case ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING:
1175 return R.drawable.omnibox_https_warning;
1176 case ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR:
1177 return R.drawable.omnibox_https_invalid;
1178 case ConnectionSecurityHelperSecurityLevel.SECURE:
1179 case ConnectionSecurityHelperSecurityLevel.EV_SECURE:
1180 return usingLightTheme
1181 ? R.drawable.omnibox_https_valid_light : R.drawable.omni box_https_valid;
1182 default:
1183 assert false;
1184 }
1185 return 0;
1186 }
1187
1188 /**
1189 * Updates the security icon displayed in the LocationBar.
1190 */
1191 @Override
1192 public void updateSecurityIcon(int securityLevel) {
1193 if (showingOriginalUrlForPreview()) {
1194 securityLevel = ConnectionSecurityHelperSecurityLevel.NONE;
1195 }
1196 if (mQueryInTheOmnibox) {
1197 if (securityLevel == ConnectionSecurityHelperSecurityLevel.SECURE
1198 || securityLevel == ConnectionSecurityHelperSecurityLevel.EV _SECURE) {
1199 securityLevel = ConnectionSecurityHelperSecurityLevel.NONE;
1200 } else if (securityLevel == ConnectionSecurityHelperSecurityLevel.SE CURITY_WARNING
1201 || securityLevel == ConnectionSecurityHelperSecurityLevel.SE CURITY_ERROR) {
1202 setUrlToPageUrl();
1203 }
1204 }
1205
1206 // ImageView#setImageResource is no-op if given resource is the current one.
1207 mSecurityButton.setImageResource(
1208 getSecurityIconResource(securityLevel, !shouldEmphasizeHttpsSche me()));
1209
1210 if (mSecurityIconType == securityLevel) return;
1211 mSecurityIconType = securityLevel;
1212
1213 if (securityLevel == ConnectionSecurityHelperSecurityLevel.NONE) {
1214 updateSecurityButton(false);
1215 } else {
1216 updateSecurityButton(true);
1217 // Since we emphasize the schema of the URL based on the security ty pe, we need to
1218 // refresh the emphasis.
1219 mUrlBar.deEmphasizeUrl();
1220 }
1221 emphasizeUrl();
1222 }
1223
1224 private void emphasizeUrl() {
1225 if (!mQueryInTheOmnibox) mUrlBar.emphasizeUrl();
1226 }
1227
1228 @Override
1229 public boolean shouldEmphasizeHttpsScheme() {
1230 int securityLevel = getSecurityLevel();
1231 if (securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_ERRO R
1232 || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURI TY_WARNING
1233 || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURI TY_POLICY_WARNING) {
1234 return true;
1235 }
1236 if (getToolbarDataProvider().isUsingBrandColor()) return false;
1237 if (getToolbarDataProvider().isIncognito()) return false;
1238 return true;
1239 }
1240
1241 /**
1242 * Updates the display of the security button.
1243 * @param enabled Whether the security button should be displayed.
1244 */
1245 private void updateSecurityButton(boolean enabled) {
1246 changeLocationBarIcon(enabled
1247 && (!DeviceFormFactor.isTablet(getContext()) || !mUrlHasFocus));
1248 mSecurityButtonShown = enabled;
1249 updateLocationBarIconContainerVisibility();
1250 }
1251
1252 /**
1253 * @return Whether the security button is currently being displayed.
1254 */
1255 @VisibleForTesting
1256 public boolean isSecurityButtonShown() {
1257 return mSecurityButtonShown;
1258 }
1259
1260 /**
1261 * Sets the type of the current navigation type and updates the UI to match it.
1262 * @param buttonType The type of navigation button to be shown.
1263 */
1264 private void setNavigationButtonType(NavigationButtonType buttonType) {
1265 switch (buttonType) {
1266 case PAGE:
1267 Drawable page = ApiCompatibilityUtils.getDrawable(
1268 getResources(), R.drawable.ic_omnibox_page);
1269 page.setColorFilter(mUseDarkColors
1270 ? getResources().getColor(R.color.light_normal_color)
1271 : Color.WHITE, PorterDuff.Mode.SRC_IN);
1272 mNavigationButton.setImageDrawable(page);
1273 break;
1274 case MAGNIFIER:
1275 mNavigationButton.setImageResource(R.drawable.ic_omnibox_magnifi er);
1276 break;
1277 case EMPTY:
1278 mNavigationButton.setImageResource(0);
1279 break;
1280 default:
1281 assert false;
1282 }
1283
1284 if (mNavigationButton.getVisibility() != VISIBLE) {
1285 mNavigationButton.setVisibility(VISIBLE);
1286 }
1287 mNavigationButtonType = buttonType;
1288 updateLocationBarIconContainerVisibility();
1289 }
1290
1291 /**
1292 * Update the visibility of the location bar icon container based on the sta te of the
1293 * security and navigation icons.
1294 */
1295 protected void updateLocationBarIconContainerVisibility() {
1296 boolean showContainer =
1297 mSecurityButtonShown || mNavigationButtonType != NavigationButto nType.EMPTY;
1298 findViewById(R.id.location_bar_icon).setVisibility(showContainer ? VISIB LE : GONE);
1299 }
1300
1301 private boolean isStoredArticle(String url) {
1302 DomDistillerService domDistillerService =
1303 DomDistillerServiceFactory.getForProfile(Profile.getLastUsedProf ile());
1304 String entryIdFromUrl = DomDistillerUrlUtils.getValueForKeyInUrl(url, "e ntry_id");
1305 if (TextUtils.isEmpty(entryIdFromUrl)) return false;
1306 return domDistillerService.hasEntry(entryIdFromUrl);
1307 }
1308
1309 /**
1310 * Updates the layout params for the location bar start aligned views.
1311 */
1312 protected void updateLayoutParams() {
1313 int startMargin = 0;
1314 int urlContainerChildIndex = -1;
1315 for (int i = 0; i < getChildCount(); i++) {
1316 View childView = getChildAt(i);
1317 if (childView.getVisibility() != GONE) {
1318 LayoutParams childLayoutParams = (LayoutParams) childView.getLay outParams();
1319 if (ApiCompatibilityUtils.getMarginStart(childLayoutParams) != s tartMargin) {
1320 ApiCompatibilityUtils.setMarginStart(childLayoutParams, star tMargin);
1321 childView.setLayoutParams(childLayoutParams);
1322 }
1323 if (childView == mUrlContainer) {
1324 urlContainerChildIndex = i;
1325 break;
1326 }
1327 int widthMeasureSpec;
1328 int heightMeasureSpec;
1329 if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) {
1330 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
1331 getMeasuredWidth(), MeasureSpec.AT_MOST);
1332 } else if (childLayoutParams.width == LayoutParams.MATCH_PARENT) {
1333 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
1334 getMeasuredWidth(), MeasureSpec.EXACTLY);
1335 } else {
1336 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
1337 childLayoutParams.width, MeasureSpec.EXACTLY);
1338 }
1339 if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) {
1340 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
1341 getMeasuredHeight(), MeasureSpec.AT_MOST);
1342 } else if (childLayoutParams.height == LayoutParams.MATCH_PARENT ) {
1343 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
1344 getMeasuredHeight(), MeasureSpec.EXACTLY);
1345 } else {
1346 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
1347 childLayoutParams.height, MeasureSpec.EXACTLY);
1348 }
1349 childView.measure(widthMeasureSpec, heightMeasureSpec);
1350 startMargin += childView.getMeasuredWidth();
1351 }
1352 }
1353
1354 assert urlContainerChildIndex != -1;
1355 int urlContainerMarginEnd = 0;
1356 for (int i = urlContainerChildIndex + 1; i < getChildCount(); i++) {
1357 View childView = getChildAt(i);
1358 if (childView.getVisibility() != GONE) {
1359 LayoutParams childLayoutParams = (LayoutParams) childView.getLay outParams();
1360 urlContainerMarginEnd = Math.max(urlContainerMarginEnd,
1361 childLayoutParams.width
1362 + ApiCompatibilityUtils.getMarginStart(childLayo utParams)
1363 + ApiCompatibilityUtils.getMarginEnd(childLayout Params));
1364 }
1365 }
1366 LayoutParams urlLayoutParams = (LayoutParams) mUrlContainer.getLayoutPar ams();
1367 if (ApiCompatibilityUtils.getMarginEnd(urlLayoutParams) != urlContainerM arginEnd) {
1368 ApiCompatibilityUtils.setMarginEnd(urlLayoutParams, urlContainerMarg inEnd);
1369 mUrlContainer.setLayoutParams(urlLayoutParams);
1370 }
1371 }
1372
1373 /**
1374 * @return Whether the delete button should be shown.
1375 */
1376 protected boolean shouldShowDeleteButton() {
1377 // Show the delete button at the endon the right when the bar has focus and has some text.
1378 return mUrlBar.hasFocus() && !TextUtils.isEmpty(mUrlBar.getText());
1379 }
1380
1381 /**
1382 * Updates the display of the delete URL content button.
1383 */
1384 protected void updateDeleteButtonVisibility() {
1385 }
1386
1387 /**
1388 * @return The suggestion list popup containing the omnibox results (or
1389 * null if it has not yet been created).
1390 */
1391 @VisibleForTesting
1392 public OmniboxSuggestionsList getSuggestionList() {
1393 return mSuggestionList;
1394 }
1395
1396 /**
1397 * Initiates the mSuggestionListPopup. Done on demand to not slow down
1398 * the initial inflation of the location bar.
1399 */
1400 private void initSuggestionList() {
1401 // Only called from onSuggestionsReceived(), which is a callback from a listener set up by
1402 // onNativeLibraryReady(), so this assert is safe.
1403 assert mNativeInitialized : "Trying to initialize suggestions list befor e native init";
1404 if (mSuggestionList != null) return;
1405
1406 OnLayoutChangeListener suggestionListResizer = new OnLayoutChangeListene r() {
1407 @Override
1408 public void onLayoutChange(View v, int left, int top, int right, int bottom,
1409 int oldLeft, int oldTop, int oldRight, int oldBottom) {
1410 // On ICS, this update does not take affect unless it is posted to the end of the
1411 // current message queue.
1412 post(new Runnable() {
1413 @Override
1414 public void run() {
1415 if (mSuggestionList.isShown()) mSuggestionList.updateLay outParams();
1416 }
1417 });
1418 }
1419 };
1420 getRootView().findViewById(R.id.control_container)
1421 .addOnLayoutChangeListener(suggestionListResizer);
1422
1423 mSuggestionList = new OmniboxSuggestionsList(getContext());
1424 mOmniboxResultsContainer.addView(mSuggestionList);
1425 mSuggestionList.setAdapter(mSuggestionListAdapter);
1426 mSuggestionList.setClipToPadding(false);
1427 mSuggestionListAdapter.setSuggestionDelegate(new OmniboxSuggestionDelega te() {
1428 @Override
1429 public void onSelection(OmniboxSuggestion suggestion, int position) {
1430 mSuggestionSelectionInProgress = true;
1431 String suggestionMatchUrl = updateSuggestionUrlIfNeeded(suggesti on, position);
1432 loadUrlFromOmniboxMatch(suggestionMatchUrl, suggestion.getTransi tion(), position,
1433 suggestion.getType());
1434 hideSuggestions();
1435 UiUtils.hideKeyboard(mUrlBar);
1436 }
1437
1438 @Override
1439 public void onRefineSuggestion(OmniboxSuggestion suggestion) {
1440 stopAutocomplete(false);
1441 mUrlBar.setUrl(suggestion.getFillIntoEdit(), null);
1442 mUrlBar.setSelection(mUrlBar.getText().length());
1443 RecordUserAction.record("MobileOmniboxRefineSuggestion");
1444 }
1445
1446 @Override
1447 public void onSetUrlToSuggestion(OmniboxSuggestion suggestion) {
1448 if (mIgnoreOmniboxItemSelection) return;
1449 setUrlBarText(null, null, suggestion.getFillIntoEdit());
1450 mUrlBar.setSelection(mUrlBar.getText().length());
1451 mIgnoreOmniboxItemSelection = true;
1452 }
1453
1454 @Override
1455 public void onDeleteSuggestion(int position) {
1456 if (mAutocomplete != null) mAutocomplete.deleteSuggestion(positi on);
1457 }
1458
1459 @Override
1460 public void onGestureDown() {
1461 stopAutocomplete(false);
1462 }
1463
1464 @Override
1465 public void onShowModal() {
1466 mSuggestionModalShown = true;
1467 }
1468
1469 @Override
1470 public void onHideModal() {
1471 mSuggestionModalShown = false;
1472 }
1473
1474 @Override
1475 public void onTextWidthsUpdated(float requiredWidth, float matchCont entsWidth) {
1476 mSuggestionList.updateMaxTextWidths(requiredWidth, matchContents Width);
1477 }
1478
1479 @Override
1480 public float getMaxRequiredWidth() {
1481 return mSuggestionList.getMaxRequiredWidth();
1482 }
1483
1484 @Override
1485 public float getMaxMatchContentsWidth() {
1486 return mSuggestionList.getMaxMatchContentsWidth();
1487 }
1488 });
1489 }
1490
1491 /**
1492 * @return The view that the suggestion popup should be anchored below.
1493 */
1494 protected View getSuggestionPopupAnchorView() {
1495 return this;
1496 }
1497
1498 /**
1499 * @return The background for the omnibox suggestions popup.
1500 */
1501 protected Drawable getSuggestionPopupBackground() {
1502 if (mToolbarDataProvider.isIncognito()) {
1503 return new ColorDrawable(OMNIBOX_INCOGNITO_RESULTS_BG_COLOR);
1504 } else {
1505 return new ColorDrawable(OMNIBOX_RESULTS_BG_COLOR);
1506 }
1507 }
1508
1509 /**
1510 * Handles showing/hiding the suggestions list.
1511 * @param visible Whether the suggestions list should be visible.
1512 */
1513 protected void setSuggestionsListVisibility(final boolean visible) {
1514 mSuggestionsShown = visible;
1515 if (mSuggestionList != null) {
1516 final boolean isShowing = mSuggestionList.isShown();
1517 if (visible && !isShowing) {
1518 mSuggestionList.show();
1519 } else if (!visible && isShowing) {
1520 mSuggestionList.setVisibility(GONE);
1521 }
1522 }
1523 updateOmniboxResultsContainer();
1524 }
1525
1526 /**
1527 * Updates the URL we will navigate to from suggestion, if needed. This will update the search
1528 * URL to be of the corpus type if query in the omnibox is displayed and upd ate aqs= parameter
1529 * on regular web search URLs.
1530 *
1531 * @param suggestion The chosen omnibox suggestion.
1532 * @param selectedIndex The index of the chosen omnibox suggestion.
1533 * @return The url to navigate to.
1534 */
1535 private String updateSuggestionUrlIfNeeded(OmniboxSuggestion suggestion, int selectedIndex) {
1536 // Only called once we have suggestions, and don't have a listener thoug h which we can
1537 // receive suggestions until the native side is ready, so this is safe
1538 assert mNativeInitialized
1539 : "updateSuggestionUrlIfNeeded called before native initializati on";
1540
1541 String updatedUrl = null;
1542 // Only replace URL queries for corpus search refinements, this does not work well
1543 // for regular web searches.
1544 // TODO(mariakhomenko): improve efficiency by just checking whether corp us exists.
1545 if (mQueryInTheOmnibox && !suggestion.isUrlSuggestion()
1546 && !TextUtils.isEmpty(mToolbarDataProvider.getCorpusChipText())) {
1547 String query = suggestion.getFillIntoEdit();
1548 Tab currentTab = getCurrentTab();
1549 if (currentTab != null && !TextUtils.isEmpty(currentTab.getUrl())
1550 && !TextUtils.isEmpty(query)) {
1551 updatedUrl = TemplateUrlService.getInstance().replaceSearchTerms InUrl(
1552 query, currentTab.getUrl());
1553 }
1554 } else if (suggestion.getType() != Type.VOICE_SUGGEST) {
1555 // TODO(mariakhomenko): Ideally we want to update match destination URL with new aqs
1556 // for query in the omnibox and voice suggestions, but it's currentl y difficult to do.
1557 long elapsedTimeSinceInputChange = mNewOmniboxEditSessionTimestamp > 0
1558 ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTim estamp) : -1;
1559 updatedUrl = mAutocomplete.updateMatchDestinationUrlWithQueryFormula tionTime(
1560 selectedIndex, elapsedTimeSinceInputChange);
1561 }
1562
1563 return updatedUrl == null ? suggestion.getUrl() : updatedUrl;
1564 }
1565
1566 private void clearSuggestions(boolean notifyChange) {
1567 mSuggestionItems.clear();
1568 // Make sure to notify the adapter. If the ListView becomes out of sync
1569 // with its adapter and it has not been notified, it will throw an
1570 // exception when some UI events are propagated.
1571 if (notifyChange) mSuggestionListAdapter.notifyDataSetChanged();
1572 }
1573
1574 /**
1575 * Hides the omnibox suggestion popup.
1576 *
1577 * <p>
1578 * Signals the autocomplete controller to stop generating omnibox suggestion s.
1579 *
1580 * @see AutocompleteController#stop(boolean)
1581 */
1582 @Override
1583 public void hideSuggestions() {
1584 if (mAutocomplete == null) return;
1585
1586 recordSuggestionsDismissed();
1587
1588 stopAutocomplete(true);
1589
1590 setSuggestionsListVisibility(false);
1591 clearSuggestions(true);
1592 updateNavigationButton();
1593
1594 mSuggestionSelectionInProgress = false;
1595 }
1596
1597 /**
1598 * Records a UMA action indicating that the user dismissed the suggestion li st (e.g. pressed
1599 * the back button or the 'x' button in the Omnibox). If there was an answe r shown its type
1600 * is recorded.
1601 *
1602 * The action is not recorded if mSelectionInProgress is true. This allows us to avoid
1603 * recording the action in the case where the user is selecting a suggestion which is not
1604 * considered a dismissal.
1605 */
1606 private void recordSuggestionsDismissed() {
1607 if (mSuggestionSelectionInProgress || mSuggestionItems.size() == 0) retu rn;
1608
1609 int answerTypeShown = 0;
1610 for (int i = 0; i < mSuggestionItems.size(); i++) {
1611 OmniboxSuggestion suggestion = mSuggestionItems.get(i).getSuggestion ();
1612 if (suggestion.hasAnswer()) {
1613 try {
1614 answerTypeShown = Integer.parseInt(suggestion.getAnswerType( ));
1615 } catch (NumberFormatException e) {
1616 Log.e(getClass().getSimpleName(),
1617 "Answer type in dismissed suggestions is not an int: "
1618 + suggestion.getAnswerType());
1619 }
1620 break;
1621 }
1622 }
1623 RecordHistogram.recordSparseSlowlyHistogram(
1624 "Omnibox.SuggestionsDismissed.AnswerType", answerTypeShown);
1625 }
1626
1627 /**
1628 * Signals the autocomplete controller to stop generating omnibox suggestion s and cancels the
1629 * queued task to start the autocomplete controller, if any.
1630 *
1631 * @param clear Whether to clear the most recent autocomplete results.
1632 */
1633 private void stopAutocomplete(boolean clear) {
1634 if (mAutocomplete != null) mAutocomplete.stop(clear);
1635 cancelPendingAutocompleteStart();
1636 }
1637
1638 /**
1639 * Cancels the queued task to start the autocomplete controller, if any.
1640 */
1641 private void cancelPendingAutocompleteStart() {
1642 if (mRequestSuggestions != null) {
1643 // There is a request for suggestions either waiting for the native side
1644 // to start, or on the message queue. Remove it from wherever it is.
1645 if (!mDeferredNativeRunnables.remove(mRequestSuggestions)) {
1646 removeCallbacks(mRequestSuggestions);
1647 }
1648 mRequestSuggestions = null;
1649 }
1650 }
1651
1652 @Override
1653 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> containe r) {
1654 // Don't restore the state of the location bar, it can lead to all kind of bad states with
1655 // the popup.
1656 // When we restore tabs, we focus the selected tab so the URL of the pag e shows.
1657 }
1658
1659 /**
1660 * Performs a search query on the current {@link ChromeTab}. This calls
1661 * {@link TemplateUrlService#getUrlForSearchQuery(String)} to get a url base d on {@code query}
1662 * and loads that url in the current {@link ChromeTab}.
1663 * @param query The {@link String} that represents the text query that shoul d be searched for.
1664 */
1665 @VisibleForTesting
1666 public void performSearchQueryForTest(String query) {
1667 if (TextUtils.isEmpty(query)) return;
1668
1669 String queryUrl = TemplateUrlService.getInstance().getUrlForSearchQuery( query);
1670
1671 if (!TextUtils.isEmpty(queryUrl)) {
1672 loadUrl(queryUrl, PageTransition.GENERATED);
1673 } else {
1674 setSearchQuery(query);
1675 }
1676 }
1677
1678 /**
1679 * Sets the query string in the omnibox (ensuring the URL bar has focus and triggering
1680 * autocomplete for the specified query) as if the user typed it.
1681 *
1682 * @param query The query to be set in the omnibox.
1683 */
1684 public void setSearchQuery(final String query) {
1685 if (TextUtils.isEmpty(query)) return;
1686
1687 if (!mNativeInitialized) {
1688 mDeferredNativeRunnables.add(new Runnable() {
1689 @Override
1690 public void run() {
1691 setSearchQuery(query);
1692 }
1693 });
1694 return;
1695 }
1696
1697 setUrlBarText(null, null, query);
1698 mUrlBar.setSelection(0, mUrlBar.getText().length());
1699 mUrlBar.requestFocus();
1700 stopAutocomplete(false);
1701 if (getCurrentTab() != null) {
1702 mAutocomplete.start(
1703 getCurrentTab().getProfile(), getCurrentTab().getUrl(), quer y, false);
1704 }
1705 post(new Runnable() {
1706 @Override
1707 public void run() {
1708 UiUtils.showKeyboard(mUrlBar);
1709 }
1710 });
1711 }
1712
1713 /**
1714 * Whether {@code v} is a location icon which can be clicked to show the
1715 * origin info dialog.
1716 */
1717 private boolean isLocationIcon(View v) {
1718 return v == mSecurityButton || v == mNavigationButton;
1719 }
1720
1721 @Override
1722 public void onClick(View v) {
1723 if (v == mDeleteButton) {
1724 if (!TextUtils.isEmpty(mUrlBar.getQueryText())) {
1725 setUrlBarText(null, null, "");
1726 hideSuggestions();
1727 }
1728
1729 startZeroSuggest();
1730 return;
1731 } else if (!mUrlHasFocus && isLocationIcon(v)) {
1732 Tab currentTab = getCurrentTab();
1733 if (currentTab != null && currentTab.getWebContents() != null) {
1734 WebsiteSettingsPopup.show(getContext(), currentTab.getProfile(),
1735 currentTab.getWebContents());
1736 }
1737 } else if (v == mMicButton) {
1738 RecordUserAction.record("MobileOmniboxVoiceSearch");
1739 startVoiceRecognition();
1740 }
1741 }
1742
1743 /**
1744 * Whether we want to be showing inline autocomplete results. We don't want to show them as the
1745 * user deletes input. Also if there is a composition (e.g. while using the Japanese IME),
1746 * we must not autocomplete or we'll destroy the composition.
1747 * @return Whether we want to be showing inline autocomplete results.
1748 */
1749 private boolean shouldAutocomplete() {
1750 if (mLastUrlEditWasDelete) return false;
1751 Editable text = mUrlBar.getText();
1752
1753 return mUrlBar.isCursorAtEndOfTypedText()
1754 && BaseInputConnection.getComposingSpanEnd(text)
1755 == BaseInputConnection.getComposingSpanStart(text);
1756 }
1757
1758 @Override
1759 public void onSuggestionsReceived(List<OmniboxSuggestion> newSuggestions,
1760 String inlineAutocompleteText) {
1761 // This is a callback from a listener that is set up by onNativeLibraryR eady,
1762 // so can only be called once the native side is set up.
1763 assert mNativeInitialized : "Suggestions received before native side int ialialized";
1764
1765 if (getCurrentTab() == null) {
1766 // If the current tab is not available, drop the suggestions and hid e the autocomplete.
1767 hideSuggestions();
1768 return;
1769 }
1770
1771 String userText = mUrlBar.getTextWithoutAutocomplete();
1772 mUrlTextAfterSuggestionsReceived = userText + inlineAutocompleteText;
1773
1774 boolean itemsChanged = false;
1775 boolean itemCountChanged = false;
1776 // If the length of the incoming suggestions matches that of those curre ntly being shown,
1777 // replace them inline to allow transient entries to retain their proper highlighting.
1778 if (mSuggestionItems.size() == newSuggestions.size()) {
1779 for (int index = 0; index < newSuggestions.size(); index++) {
1780 OmniboxResultItem suggestionItem = mSuggestionItems.get(index);
1781 OmniboxSuggestion suggestion = suggestionItem.getSuggestion();
1782 OmniboxSuggestion newSuggestion = newSuggestions.get(index);
1783 // Determine whether the suggestions have changed. If not, save some time by not
1784 // redrawing the suggestions UI.
1785 if (suggestion.equals(newSuggestion)
1786 && suggestion.getType() != OmniboxSuggestion.Type.SEARCH _SUGGEST_TAIL) {
1787 if (suggestionItem.getMatchedQuery().equals(userText)) {
1788 continue;
1789 } else if (!suggestion.getDisplayText().startsWith(userText)
1790 && !suggestion.getUrl().contains(userText)) {
1791 continue;
1792 }
1793 }
1794 mSuggestionItems.set(index, new OmniboxResultItem(newSuggestion, userText));
1795 itemsChanged = true;
1796 }
1797 } else {
1798 itemsChanged = true;
1799 itemCountChanged = true;
1800 clearSuggestions(false);
1801 for (int i = 0; i < newSuggestions.size(); i++) {
1802 mSuggestionItems.add(new OmniboxResultItem(newSuggestions.get(i) , userText));
1803 }
1804 }
1805
1806 if (mSuggestionItems.isEmpty()) {
1807 if (mSuggestionsShown) hideSuggestions();
1808 return;
1809 }
1810
1811 if (shouldAutocomplete()) {
1812 mUrlBar.setAutocompleteText(userText, inlineAutocompleteText);
1813 }
1814
1815 // Show the suggestion list.
1816 initSuggestionList(); // It may not have been initialized yet.
1817 mSuggestionList.resetMaxTextWidths();
1818
1819 if (itemsChanged) mSuggestionListAdapter.notifySuggestionsChanged();
1820 if (mUrlBar.hasFocus()) {
1821 setSuggestionsListVisibility(true);
1822 if (itemCountChanged) {
1823 mSuggestionList.updateLayoutParams();
1824 }
1825 }
1826
1827 // Update the navigation button to show the default suggestion's icon.
1828 updateNavigationButton();
1829
1830 if (!CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_INSTANT)
1831 && PrivacyPreferencesManager.getInstance(getContext()).shouldPre render()) {
1832 mOmniboxPrerender.prerenderMaybe(
1833 userText,
1834 getOriginalUrl(),
1835 mAutocomplete.getCurrentNativeAutocompleteResult(),
1836 getCurrentTab().getProfile(),
1837 getCurrentTab());
1838 }
1839 }
1840
1841 @Override
1842 public void backKeyPressed() {
1843 hideSuggestions();
1844 UiUtils.hideKeyboard(mUrlBar);
1845 // Revert the URL to match the current page.
1846 setUrlToPageUrl();
1847 // Focus the page.
1848 Tab currentTab = getCurrentTab();
1849 if (currentTab != null) currentTab.requestFocus();
1850 }
1851
1852 /**
1853 * @return Returns the original url of the page.
1854 */
1855 public String getOriginalUrl() {
1856 return mOriginalUrl;
1857 }
1858
1859 /**
1860 * Given the URL display text, this will remove any path portion contained w ithin.
1861 * @param displayText The text to strip the path from.
1862 * @return A pair where the first item is the text without any path content (if the path was
1863 * successfully found), and the second item is the path content (or null if no path
1864 * was found or parsing the path failed).
1865 * @see ToolbarDataProvider#getText()
1866 */
1867 // TODO(tedchoc): Move this logic into the original display text calculation .
1868 @VisibleForTesting
1869 public static Pair<String, String> splitPathFromUrlDisplayText(String displa yText) {
1870 int pathSearchOffset = 0;
1871 Uri uri = Uri.parse(displayText);
1872 String scheme = uri.getScheme();
1873 if (!TextUtils.isEmpty(scheme)) {
1874 if (UNSUPPORTED_SCHEMES_TO_SPLIT.contains(scheme)) {
1875 return Pair.create(displayText, null);
1876 } else if (ACCEPTED_SCHEMES.contains(scheme)) {
1877 for (pathSearchOffset = scheme.length();
1878 pathSearchOffset < displayText.length();
1879 pathSearchOffset++) {
1880 char c = displayText.charAt(pathSearchOffset);
1881 if (c != ':' && c != '/') break;
1882 }
1883 }
1884 }
1885 int pathOffset = -1;
1886 if (pathSearchOffset < displayText.length()) {
1887 pathOffset = displayText.indexOf('/', pathSearchOffset);
1888 }
1889 if (pathOffset != -1) {
1890 String prePathText = displayText.substring(0, pathOffset);
1891 // If the '/' is the last character and the beginning of the path, t hen just drop
1892 // the path entirely.
1893 String pathText = pathOffset == displayText.length() - 1
1894 ? null : displayText.substring(pathOffset);
1895 return Pair.create(prePathText, pathText);
1896 }
1897 return Pair.create(displayText, null);
1898 }
1899
1900 /**
1901 * Sets the displayed URL to be the URL of the page currently showing.
1902 *
1903 * <p>The URL is converted to the most user friendly format (removing HTTP:/ / for example).
1904 *
1905 * <p>If the current tab is null, the URL text will be cleared.
1906 */
1907 @Override
1908 public void setUrlToPageUrl() {
1909 // If the URL is currently focused, do not replace the text they have en tered with the URL.
1910 // Once they stop editing the URL, the current tab's URL will automatica lly be filled in.
1911 if (mUrlBar.hasFocus()) return;
1912
1913 mQueryInTheOmnibox = false;
1914
1915 if (getCurrentTab() == null) {
1916 setUrlBarText(null, null, "");
1917 return;
1918 }
1919
1920 // Profile may be null if switching to a tab that has not yet been initi alized.
1921 Profile profile = getCurrentTab().getProfile();
1922 if (profile != null) mOmniboxPrerender.clear(profile);
1923
1924 String url = getCurrentTab().getUrl().trim();
1925 mOriginalUrl = url;
1926
1927 if (NativePageFactory.isNativePageUrl(url, getCurrentTab().isIncognito() )) {
1928 // Don't show anything for Chrome URLs.
1929 setUrlBarText("", null, null);
1930 return;
1931 }
1932
1933 // Background view has similar case as snapshot.
1934 BackgroundContentViewHelper backgroundViewHelper =
1935 getCurrentTab().getBackgroundContentViewHelper();
1936 boolean hasPendingBackgroundPage =
1937 backgroundViewHelper != null && backgroundViewHelper.hasPendingB ackgroundPage();
1938 boolean isTransitioningFromPreviewPageToOriginal =
1939 showingOriginalUrlForPreview() && !hasPendingBackgroundPage;
1940 mShowingOriginalUrlForPreview = hasPendingBackgroundPage;
1941
1942 boolean showingQuery = false;
1943 String displayText = mToolbarDataProvider.getText();
1944 int securityLevel = getSecurityLevel();
1945 if (securityLevel != ConnectionSecurityHelperSecurityLevel.SECURITY_ERRO R
1946 && !TextUtils.isEmpty(displayText)
1947 && mToolbarDataProvider.wouldReplaceURL()) {
1948 url = displayText.trim();
1949 showingQuery = true;
1950 mQueryInTheOmnibox = true;
1951 }
1952 String path = null;
1953 if (!showingQuery && FeatureUtilities.isDocumentMode(getContext())) {
1954 Pair<String, String> urlText = splitPathFromUrlDisplayText(displayTe xt);
1955 displayText = urlText.first;
1956 path = urlText.second;
1957 }
1958
1959 if (DomDistillerUrlUtils.isDistilledPage(url)) {
1960 if (isStoredArticle(url)) {
1961 DomDistillerService domDistillerService =
1962 DomDistillerServiceFactory.getForProfile(profile);
1963 String originalUrl = domDistillerService.getUrlForEntry(
1964 DomDistillerUrlUtils.getValueForKeyInUrl(url, "entry_id" ));
1965 displayText =
1966 DomDistillerTabUtils.getFormattedUrlFromOriginalDistille rUrl(originalUrl);
1967 } else if (DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url) != null) {
1968 String originalUrl = DomDistillerUrlUtils.getOriginalUrlFromDist illerUrl(url);
1969 displayText =
1970 DomDistillerTabUtils.getFormattedUrlFromOriginalDistille rUrl(originalUrl);
1971 }
1972 }
1973
1974 if (setUrlBarText(displayText, path, url) || isTransitioningFromPreviewP ageToOriginal) {
1975 mUrlBar.deEmphasizeUrl();
1976 emphasizeUrl();
1977 }
1978 if (showingQuery) {
1979 updateNavigationButton();
1980 }
1981 updateCustomSelectionActionModeCallback();
1982 }
1983
1984 /**
1985 * Changes the text on the url bar
1986 * @param displayText The text (URL or search terms) for user display.
1987 * @param trailingText The trailing text (path portion of the URL) to be dis played separately.
1988 * @param text The original text (URL or search terms) for copy/cut.
1989 * @return Whether the URL was changed as a result of this call.
1990 */
1991 private boolean setUrlBarText(String displayText, String trailingText, Strin g text) {
1992 mIgnoreURLBarModification = true;
1993 boolean urlChanged = mUrlContainer.setUrlText(displayText, trailingText, text);
1994 mIgnoreURLBarModification = false;
1995 return urlChanged;
1996 }
1997
1998 /**
1999 * Sets whether modifications to the URL bar should be ignored.
2000 */
2001 @Override
2002 public void setIgnoreURLBarModification(boolean value) {
2003 mIgnoreURLBarModification = value;
2004 }
2005
2006 private void loadUrlFromOmniboxMatch(String url, int transition, int matchPo sition,
2007 OmniboxSuggestion.Type type) {
2008 // loadUrl modifies AutocompleteController's state clearing the native
2009 // AutocompleteResults needed by onSuggestionsSelected. Therefore,
2010 // loadUrl should should be invoked last.
2011 Tab currentTab = getCurrentTab();
2012 String currentPageUrl = currentTab != null ? currentTab.getUrl() : "";
2013 WebContents webContents = currentTab != null ? currentTab.getWebContents () : null;
2014 long elapsedTimeSinceModified = mNewOmniboxEditSessionTimestamp > 0
2015 ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimesta mp) : -1;
2016 mAutocomplete.onSuggestionSelected(matchPosition, type, currentPageUrl,
2017 mQueryInTheOmnibox, mUrlFocusedFromFakebox, elapsedTimeSinceModi fied,
2018 webContents);
2019 loadUrl(url, transition);
2020 }
2021
2022 private void loadUrl(String url, int transition) {
2023 Tab currentTab = getCurrentTab();
2024
2025 // The code of the rest of this class ensures that this can't be called until the native
2026 // side is initialized
2027 assert mNativeInitialized : "Loading URL before native side initialized" ;
2028
2029 if (currentTab != null
2030 && (currentTab.isNativePage() || NewTabPage.isNTPUrl(currentTab. getUrl()))) {
2031 NewTabPageUma.recordOmniboxNavigation(url, transition);
2032 // Passing in an empty string should not do anything unless the user is at the NTP.
2033 // Since the NTP has no url, pressing enter while clicking on the UR L bar should refresh
2034 // the page as it does when you click and press enter on any other s ite.
2035 if (url.isEmpty()) url = currentTab.getUrl();
2036 }
2037
2038 // Loads the |url| in the current ContentView and gives focus to the Con tentView.
2039 if (currentTab != null && !url.isEmpty()) {
2040 LoadUrlParams loadUrlParams = new LoadUrlParams(url);
2041 loadUrlParams.setVerbatimHeaders(
2042 GeolocationHeader.getGeoHeader(getContext(), url, currentTab .isIncognito()));
2043 loadUrlParams.setTransitionType(transition | PageTransition.FROM_ADD RESS_BAR);
2044 currentTab.loadUrl(loadUrlParams);
2045
2046 setUrlToPageUrl();
2047 RecordUserAction.record("MobileOmniboxSearch");
2048 RecordUserAction.record("MobileTabClobbered");
2049 } else {
2050 setUrlToPageUrl();
2051 }
2052
2053 if (currentTab != null) currentTab.requestFocus();
2054
2055 // Prevent any upcoming omnibox suggestions from showing. We have to do this after we load
2056 // the URL as this will hide the suggestions and trigger a cancel of the prerendered page.
2057 stopAutocomplete(true);
2058 }
2059
2060 /**
2061 * Update the location bar visuals based on a loading state change.
2062 * @param updateUrl Whether to update the URL as a result of the this call.
2063 */
2064 @Override
2065 public void updateLoadingState(boolean updateUrl) {
2066 if (updateUrl) setUrlToPageUrl();
2067 updateNavigationButton();
2068 updateSecurityIcon(getSecurityLevel());
2069 }
2070
2071 /**
2072 * @return The ChromeTab currently showing.
2073 */
2074 @Override
2075 public ChromeTab getCurrentTab() {
2076 if (mToolbarDataProvider == null) return null;
2077 return ChromeTab.fromTab(mToolbarDataProvider.getTab());
2078 }
2079
2080 private ContentViewCore getContentViewCore() {
2081 Tab currentTab = getCurrentTab();
2082 return currentTab != null ? currentTab.getContentViewCore() : null;
2083 }
2084
2085 private void updateOmniboxResultsContainer() {
2086 if (mSuggestionsShown || mUrlHasFocus) {
2087 if (mOmniboxResultsContainer == null) {
2088 ViewStub overlayStub =
2089 (ViewStub) getRootView().findViewById(R.id.omnibox_resul ts_container_stub);
2090 mOmniboxResultsContainer = (ViewGroup) overlayStub.inflate();
2091 mOmniboxResultsContainer.setBackgroundColor(CONTENT_OVERLAY_COLO R);
2092 // Prevent touch events from propagating down to the chrome view .
2093 mOmniboxResultsContainer.setOnTouchListener(new OnTouchListener( ) {
2094 @Override
2095 @SuppressLint("ClickableViewAccessibility")
2096 public boolean onTouch(View v, MotionEvent event) {
2097 int action = event.getActionMasked();
2098 if (action == MotionEvent.ACTION_CANCEL
2099 || action == MotionEvent.ACTION_UP) {
2100 mUrlBar.clearFocus();
2101 updateOmniboxResultsContainerBackground(false);
2102 }
2103 return true;
2104 }
2105 });
2106 }
2107 updateOmniboxResultsContainerVisibility(true);
2108 } else if (mOmniboxResultsContainer != null) {
2109 updateOmniboxResultsContainerBackground(false);
2110 }
2111 }
2112
2113 private void updateOmniboxResultsContainerVisibility(boolean visible) {
2114 boolean currentlyVisible = mOmniboxResultsContainer.getVisibility() == V ISIBLE;
2115 if (currentlyVisible == visible) {
2116 // This early return is necessary. Otherwise, calling
2117 // updateOmniboxResultsContainerVisibility(true) twice in a row will update
2118 // mFocusedTabImportantForAccessibilityState incorrectly and cause
2119 // mFocusedTabView to be stuck in IMPORTANT_FOR_ACCESSIBILITY_NO_HID E_DESCENDANTS mode.
2120 // http://crbug.com/445560
2121 return;
2122 }
2123
2124 if (visible) {
2125 mOmniboxResultsContainer.setVisibility(VISIBLE);
2126
2127 if (getContentViewCore() != null) {
2128 mFocusedTabAccessibilityManager =
2129 getContentViewCore().getBrowserAccessibilityManager();
2130 if (mFocusedTabAccessibilityManager != null) {
2131 mFocusedTabAccessibilityManager.setVisible(false);
2132 }
2133 }
2134
2135 if (getCurrentTab() != null && getCurrentTab().getView() != null) {
2136 mFocusedTabView = getCurrentTab().getView();
2137 mFocusedTabImportantForAccessibilityState =
2138 mFocusedTabView.getImportantForAccessibility();
2139 mFocusedTabView.setImportantForAccessibility(
2140 IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
2141 }
2142 } else {
2143 mOmniboxResultsContainer.setVisibility(INVISIBLE);
2144
2145 if (mFocusedTabAccessibilityManager != null) {
2146 mFocusedTabAccessibilityManager.setVisible(true);
2147 mFocusedTabAccessibilityManager = null;
2148 }
2149
2150 if (mFocusedTabView != null) {
2151 mFocusedTabView.setImportantForAccessibility(
2152 mFocusedTabImportantForAccessibilityState);
2153 mFocusedTabView = null;
2154 }
2155 }
2156 }
2157
2158 /**
2159 * Set the background of the omnibox results container.
2160 * @param visible Whether the background should be made visible.
2161 */
2162 private void updateOmniboxResultsContainerBackground(boolean visible) {
2163 if (getToolbarDataProvider() == null) return;
2164
2165 NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
2166 boolean locationBarShownInNTP = ntp != null && ntp.isLocationBarShownInN TP();
2167 if (visible) {
2168 if (locationBarShownInNTP) {
2169 mOmniboxResultsContainer.getBackground().setAlpha(0);
2170 } else {
2171 fadeInOmniboxResultsContainerBackground();
2172 }
2173 } else {
2174 if (locationBarShownInNTP) {
2175 updateOmniboxResultsContainerVisibility(false);
2176 } else {
2177 fadeOutOmniboxResultsContainerBackground();
2178 }
2179 }
2180 }
2181
2182 /**
2183 * Trigger a fade in of the omnibox results background.
2184 */
2185 protected void fadeInOmniboxResultsContainerBackground() {
2186 if (mFadeInOmniboxBackgroundAnimator == null) {
2187 mFadeInOmniboxBackgroundAnimator = ObjectAnimator.ofInt(
2188 getRootView().findViewById(R.id.omnibox_results_container).g etBackground(),
2189 "alpha", 0, 255);
2190 mFadeInOmniboxBackgroundAnimator.setDuration(OMNIBOX_CONTAINER_BACKG ROUND_FADE_MS);
2191 mFadeInOmniboxBackgroundAnimator.setInterpolator(
2192 BakedBezierInterpolator.FADE_IN_CURVE);
2193 }
2194 runOmniboxResultsFadeAnimation(mFadeInOmniboxBackgroundAnimator);
2195 }
2196
2197 private void fadeOutOmniboxResultsContainerBackground() {
2198 if (mFadeOutOmniboxBackgroundAnimator == null) {
2199 mFadeOutOmniboxBackgroundAnimator = ObjectAnimator.ofInt(
2200 getRootView().findViewById(R.id.omnibox_results_container).g etBackground(),
2201 "alpha", 255, 0);
2202 mFadeOutOmniboxBackgroundAnimator.setDuration(OMNIBOX_CONTAINER_BACK GROUND_FADE_MS);
2203 mFadeOutOmniboxBackgroundAnimator.setInterpolator(
2204 BakedBezierInterpolator.FADE_OUT_CURVE);
2205 mFadeOutOmniboxBackgroundAnimator.addListener(new AnimatorListenerAd apter() {
2206 private boolean mIsCancelled;
2207
2208 @Override
2209 public void onAnimationStart(Animator animation) {
2210 mIsCancelled = false;
2211 }
2212
2213 @Override
2214 public void onAnimationCancel(Animator animation) {
2215 mIsCancelled = true;
2216 }
2217
2218 @Override
2219 public void onAnimationEnd(Animator animation) {
2220 if (mIsCancelled) return;
2221 updateOmniboxResultsContainerVisibility(false);
2222 }
2223 });
2224 }
2225 runOmniboxResultsFadeAnimation(mFadeOutOmniboxBackgroundAnimator);
2226 }
2227
2228 private void runOmniboxResultsFadeAnimation(Animator fadeAnimation) {
2229 if (mOmniboxBackgroundAnimator == fadeAnimation
2230 && mOmniboxBackgroundAnimator.isRunning()) {
2231 return;
2232 } else if (mOmniboxBackgroundAnimator != null) {
2233 mOmniboxBackgroundAnimator.cancel();
2234 }
2235 mOmniboxBackgroundAnimator = fadeAnimation;
2236 mOmniboxBackgroundAnimator.start();
2237 }
2238
2239 /**
2240 * @return Whether voice search is supported in the current browser configur ation.
2241 */
2242 protected boolean isVoiceSearchEnabled() {
2243 return mToolbarDataProvider != null && !mToolbarDataProvider.isIncognito ()
2244 && FeatureUtilities.isRecognitionIntentPresent(getContext(), tru e);
2245 }
2246
2247 @Override
2248 protected void onWindowVisibilityChanged(int visibility) {
2249 super.onWindowVisibilityChanged(visibility);
2250 if (visibility == View.VISIBLE) updateMicButtonState();
2251 }
2252
2253 /**
2254 * Call to notify the location bar that the state of the voice search microp hone button may
2255 * need to be updated.
2256 */
2257 @Override
2258 public void updateMicButtonState() {
2259 mMicButton.setVisibility(isVoiceSearchEnabled() ? View.VISIBLE : View.GO NE);
2260 }
2261
2262 /**
2263 * Call to force the UI to update the state of various buttons based on whet her or not the
2264 * current tab is incognito.
2265 */
2266 @Override
2267 public void updateVisualsForState() {
2268 if (updateUseDarkColors() || getToolbarDataProvider().isUsingBrandColor( )) {
2269 updateSecurityIcon(getSecurityLevel());
2270 }
2271 ColorStateList colorStateList = getResources().getColorStateList(mUseDar kColors
2272 ? R.color.dark_mode_tint : R.color.light_mode_tint);
2273 mMicButton.setTint(colorStateList);
2274 mDeleteButton.setTint(colorStateList);
2275
2276 setNavigationButtonType(mNavigationButtonType);
2277 mUrlContainer.setUseDarkTextColors(mUseDarkColors);
2278
2279 if (mSuggestionList != null) {
2280 mSuggestionList.setBackground(getSuggestionPopupBackground());
2281 }
2282 mSuggestionListAdapter.setUseDarkColors(mUseDarkColors);
2283 }
2284
2285 /**
2286 * Checks the current specs and updates {@link LocationBar#mUseDarkColors} i f necessary.
2287 * @return Whether {@link LocationBar#mUseDarkColors} has been updated.
2288 */
2289 private boolean updateUseDarkColors() {
2290 Tab tab = getCurrentTab();
2291 boolean brandColorNeedsLightText = false;
2292 if (getToolbarDataProvider().isUsingBrandColor() && !mUrlHasFocus) {
2293 int currentPrimaryColor = getToolbarDataProvider().getPrimaryColor() ;
2294 brandColorNeedsLightText =
2295 BrandColorUtils.shouldUseLightDrawablesForToolbar(currentPri maryColor);
2296 }
2297
2298 boolean useDarkColors = tab == null || !(tab.isIncognito() || brandColor NeedsLightText);
2299 boolean hasChanged = useDarkColors != mUseDarkColors;
2300 mUseDarkColors = useDarkColors;
2301
2302 return hasChanged;
2303 }
2304
2305 /**
2306 * Triggers a voice recognition intent to allow the user to specify a search query.
2307 */
2308 @Override
2309 public void startVoiceRecognition() {
2310 Activity activity = mWindowAndroid.getActivity().get();
2311 if (activity == null) return;
2312
2313 Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
2314 intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
2315 RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
2316 intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
2317 activity.getComponentName().flattenToString());
2318 intent.putExtra(RecognizerIntent.EXTRA_WEB_SEARCH_ONLY, true);
2319
2320 if (mWindowAndroid.showCancelableIntent(intent, this, R.string.voice_sea rch_error) < 0) {
2321 // Requery whether or not the recognition intent can be handled.
2322 FeatureUtilities.isRecognitionIntentPresent(activity, false);
2323 updateMicButtonState();
2324 }
2325 }
2326
2327 // WindowAndroid.IntentCallback implementation:
2328 @Override
2329 public void onIntentCompleted(WindowAndroid window, int resultCode,
2330 ContentResolver contentResolver, Intent data) {
2331 if (resultCode != Activity.RESULT_OK) return;
2332 if (data.getExtras() == null) return;
2333
2334 VoiceResult topResult = mAutocomplete.onVoiceResults(data.getExtras());
2335 if (topResult == null) return;
2336
2337 String topResultQuery = topResult.getMatch();
2338 if (TextUtils.isEmpty(topResultQuery)) return;
2339
2340 if (topResult.getConfidence() < VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHO LD) {
2341 setSearchQuery(topResultQuery);
2342 return;
2343 }
2344
2345 String url = AutocompleteController.nativeQualifyPartialURLQuery(topResu ltQuery);
2346 if (url == null) {
2347 url = TemplateUrlService.getInstance().getUrlForVoiceSearchQuery(
2348 topResultQuery);
2349 }
2350 loadUrl(url, PageTransition.TYPED);
2351 }
2352
2353 /**
2354 * Tracks how the URL bar was focused (i.e. from the omnibox or the fakebox) and records a UMA
2355 * stat for this. Should be called whenever the URL bar gains or loses focus .
2356 * @param hasFocus Whether the URL bar now has focus.
2357 */
2358 private void updateFocusSource(boolean hasFocus) {
2359 if (!hasFocus) {
2360 mUrlFocusedFromFakebox = false;
2361 mHasRecordedUrlFocusSource = false;
2362 return;
2363 }
2364
2365 // Record UMA event for how the URL bar was focused.
2366 assert !mHasRecordedUrlFocusSource;
2367 if (mHasRecordedUrlFocusSource) return;
2368
2369 Tab currentTab = getCurrentTab();
2370 if (currentTab == null) return;
2371
2372 String url = currentTab.getUrl();
2373 if (mUrlFocusedFromFakebox) {
2374 RecordUserAction.record("MobileFocusedFakeboxOnNtp");
2375 } else {
2376 if (currentTab.isNativePage() && NewTabPage.isNTPUrl(url)) {
2377 RecordUserAction.record("MobileFocusedOmniboxOnNtp");
2378 } else {
2379 RecordUserAction.record("MobileFocusedOmniboxNotOnNtp");
2380 }
2381 }
2382 mHasRecordedUrlFocusSource = true;
2383 }
2384
2385 @Override
2386 public void onTabLoadingNTP(NewTabPage ntp) {
2387 ntp.setFakeboxDelegate(this);
2388 }
2389
2390 @Override
2391 public View getContainerView() {
2392 return this;
2393 }
2394 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698