1 // Copyright 2012 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 #include "chrome/browser/ui/search/search_tab_helper.h"
6
7 #include <set>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_util.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/history/most_visited_tiles_experiment.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search/instant_service.h"
17 #include "chrome/browser/search/instant_service_factory.h"
18 #include "chrome/browser/search/search.h"
19 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/browser/sync/profile_sync_service.h"
21 #include "chrome/browser/sync/profile_sync_service_factory.h"
22 #include "chrome/browser/ui/app_list/app_list_util.h"
23 #include "chrome/browser/ui/browser_navigator.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/omnibox/location_bar.h"
26 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
27 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
28 #include "chrome/browser/ui/omnibox/omnibox_view.h"
29 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
30 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
31 #include "chrome/browser/ui/search/search_tab_helper_delegate.h"
32 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
33 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
34 #include "chrome/common/url_constants.h"
35 #include "components/signin/core/browser/signin_manager.h"
36 #include "content/public/browser/navigation_controller.h"
37 #include "content/public/browser/navigation_details.h"
38 #include "content/public/browser/navigation_entry.h"
39 #include "content/public/browser/navigation_type.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/notification_source.h"
42 #include "content/public/browser/render_process_host.h"
43 #include "content/public/browser/user_metrics.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/common/page_transition_types.h"
46 #include "content/public/common/referrer.h"
47 #include "grit/generated_resources.h"
48 #include "net/base/net_errors.h"
49 #include "ui/base/l10n/l10n_util.h"
50 #include "url/gurl.h"
51
52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchTabHelper);
53
54 namespace {
55
56 // For reporting Cacheable NTP navigations.
57 enum CacheableNTPLoad {
58 CACHEABLE_NTP_LOAD_FAILED = 0,
59 CACHEABLE_NTP_LOAD_SUCCEEDED = 1,
60 CACHEABLE_NTP_LOAD_MAX = 2
61 };
62
RecordCacheableNTPLoadHistogram(bool succeeded)63 void RecordCacheableNTPLoadHistogram(bool succeeded) {
64 UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
65 succeeded ? CACHEABLE_NTP_LOAD_SUCCEEDED :
66 CACHEABLE_NTP_LOAD_FAILED,
67 CACHEABLE_NTP_LOAD_MAX);
68 }
69
IsCacheableNTP(const content::WebContents * contents)70 bool IsCacheableNTP(const content::WebContents* contents) {
71 const content::NavigationEntry* entry =
72 contents->GetController().GetLastCommittedEntry();
73 return chrome::NavEntryIsInstantNTP(contents, entry) &&
74 entry->GetURL() != GURL(chrome::kChromeSearchLocalNtpUrl);
75 }
76
IsNTP(const content::WebContents * contents)77 bool IsNTP(const content::WebContents* contents) {
78 // We can't use WebContents::GetURL() because that uses the active entry,
79 // whereas we want the visible entry.
80 const content::NavigationEntry* entry =
81 contents->GetController().GetVisibleEntry();
82 if (entry && entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL))
83 return true;
84
85 return chrome::IsInstantNTP(contents);
86 }
87
IsSearchResults(const content::WebContents * contents)88 bool IsSearchResults(const content::WebContents* contents) {
89 return !chrome::GetSearchTerms(contents).empty();
90 }
91
IsLocal(const content::WebContents * contents)92 bool IsLocal(const content::WebContents* contents) {
93 if (!contents)
94 return false;
95 const content::NavigationEntry* entry =
96 contents->GetController().GetVisibleEntry();
97 return entry && entry->GetURL() == GURL(chrome::kChromeSearchLocalNtpUrl);
98 }
99
100 // Returns true if |contents| are rendered inside an Instant process.
InInstantProcess(Profile * profile,const content::WebContents * contents)101 bool InInstantProcess(Profile* profile,
102 const content::WebContents* contents) {
103 if (!profile || !contents)
104 return false;
105
106 InstantService* instant_service =
107 InstantServiceFactory::GetForProfile(profile);
108 return instant_service &&
109 instant_service->IsInstantProcess(
110 contents->GetRenderProcessHost()->GetID());
111 }
112
113 // Called when an NTP finishes loading. If the load start time was noted,
114 // calculates and logs the total load time.
RecordNewTabLoadTime(content::WebContents * contents)115 void RecordNewTabLoadTime(content::WebContents* contents) {
116 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
117 if (core_tab_helper->new_tab_start_time().is_null())
118 return;
119
120 base::TimeDelta duration =
121 base::TimeTicks::Now() - core_tab_helper->new_tab_start_time();
122 UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration);
123 core_tab_helper->set_new_tab_start_time(base::TimeTicks());
124 }
125
126 // Returns true if the user is signed in and full history sync is enabled,
127 // and false otherwise.
IsHistorySyncEnabled(Profile * profile)128 bool IsHistorySyncEnabled(Profile* profile) {
129 ProfileSyncService* sync =
130 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
131 return sync &&
132 sync->sync_initialized() &&
133 sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
134 }
135
136 } // namespace
137
SearchTabHelper(content::WebContents * web_contents)138 SearchTabHelper::SearchTabHelper(content::WebContents* web_contents)
139 : WebContentsObserver(web_contents),
140 is_search_enabled_(chrome::IsInstantExtendedAPIEnabled()),
141 web_contents_(web_contents),
142 ipc_router_(web_contents, this,
143 make_scoped_ptr(new SearchIPCRouterPolicyImpl(web_contents))
144 .PassAs<SearchIPCRouter::Policy>()),
145 instant_service_(NULL),
146 delegate_(NULL) {
147 if (!is_search_enabled_)
148 return;
149
150 instant_service_ =
151 InstantServiceFactory::GetForProfile(
152 Profile::FromBrowserContext(web_contents_->GetBrowserContext()));
153 if (instant_service_)
154 instant_service_->AddObserver(this);
155 }
156
~SearchTabHelper()157 SearchTabHelper::~SearchTabHelper() {
158 if (instant_service_)
159 instant_service_->RemoveObserver(this);
160 }
161
InitForPreloadedNTP()162 void SearchTabHelper::InitForPreloadedNTP() {
163 UpdateMode(true, true);
164 }
165
OmniboxInputStateChanged()166 void SearchTabHelper::OmniboxInputStateChanged() {
167 if (!is_search_enabled_)
168 return;
169
170 UpdateMode(false, false);
171 }
172
OmniboxFocusChanged(OmniboxFocusState state,OmniboxFocusChangeReason reason)173 void SearchTabHelper::OmniboxFocusChanged(OmniboxFocusState state,
174 OmniboxFocusChangeReason reason) {
175 content::NotificationService::current()->Notify(
176 chrome::NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
177 content::Source<SearchTabHelper>(this),
178 content::NotificationService::NoDetails());
179
180 ipc_router_.OmniboxFocusChanged(state, reason);
181
182 // Don't send oninputstart/oninputend updates in response to focus changes
183 // if there's a navigation in progress. This prevents Chrome from sending
184 // a spurious oninputend when the user accepts a match in the omnibox.
185 if (web_contents_->GetController().GetPendingEntry() == NULL) {
186 ipc_router_.SetInputInProgress(IsInputInProgress());
187
188 InstantSearchPrerenderer* prerenderer =
189 InstantSearchPrerenderer::GetForProfile(profile());
190 if (!prerenderer || !chrome::ShouldPrerenderInstantUrlOnOmniboxFocus())
191 return;
192
193 if (state == OMNIBOX_FOCUS_NONE) {
194 prerenderer->Cancel();
195 return;
196 }
197
198 if (!IsSearchResultsPage()) {
199 prerenderer->Init(
200 web_contents_->GetController().GetSessionStorageNamespaceMap(),
201 web_contents_->GetContainerBounds().size());
202 }
203 }
204 }
205
NavigationEntryUpdated()206 void SearchTabHelper::NavigationEntryUpdated() {
207 if (!is_search_enabled_)
208 return;
209
210 UpdateMode(false, false);
211 }
212
InstantSupportChanged(bool instant_support)213 void SearchTabHelper::InstantSupportChanged(bool instant_support) {
214 if (!is_search_enabled_)
215 return;
216
217 InstantSupportState new_state = instant_support ? INSTANT_SUPPORT_YES :
218 INSTANT_SUPPORT_NO;
219
220 model_.SetInstantSupportState(new_state);
221
222 content::NavigationEntry* entry =
223 web_contents_->GetController().GetLastCommittedEntry();
224 if (entry) {
225 chrome::SetInstantSupportStateInNavigationEntry(new_state, entry);
226 if (delegate_ && !instant_support)
227 delegate_->OnWebContentsInstantSupportDisabled(web_contents_);
228 }
229 }
230
SupportsInstant() const231 bool SearchTabHelper::SupportsInstant() const {
232 return model_.instant_support() == INSTANT_SUPPORT_YES;
233 }
234
SetSuggestionToPrefetch(const InstantSuggestion & suggestion)235 void SearchTabHelper::SetSuggestionToPrefetch(
236 const InstantSuggestion& suggestion) {
237 ipc_router_.SetSuggestionToPrefetch(suggestion);
238 }
239
Submit(const base::string16 & text)240 void SearchTabHelper::Submit(const base::string16& text) {
241 ipc_router_.Submit(text);
242 }
243
OnTabActivated()244 void SearchTabHelper::OnTabActivated() {
245 ipc_router_.OnTabActivated();
246
247 OmniboxView* omnibox_view = GetOmniboxView();
248 if (chrome::ShouldPrerenderInstantUrlOnOmniboxFocus() && omnibox_view &&
249 omnibox_view->model()->has_focus()) {
250 InstantSearchPrerenderer* prerenderer =
251 InstantSearchPrerenderer::GetForProfile(profile());
252 if (prerenderer && !IsSearchResultsPage()) {
253 prerenderer->Init(
254 web_contents_->GetController().GetSessionStorageNamespaceMap(),
255 web_contents_->GetContainerBounds().size());
256 }
257 }
258 }
259
OnTabDeactivated()260 void SearchTabHelper::OnTabDeactivated() {
261 ipc_router_.OnTabDeactivated();
262 }
263
ToggleVoiceSearch()264 void SearchTabHelper::ToggleVoiceSearch() {
265 ipc_router_.ToggleVoiceSearch();
266 }
267
IsSearchResultsPage()268 bool SearchTabHelper::IsSearchResultsPage() {
269 return model_.mode().is_origin_search();
270 }
271
RenderViewCreated(content::RenderViewHost * render_view_host)272 void SearchTabHelper::RenderViewCreated(
273 content::RenderViewHost* render_view_host) {
274 ipc_router_.SetPromoInformation(IsAppLauncherEnabled());
275 }
276
DidStartNavigationToPendingEntry(const GURL & url,content::NavigationController::ReloadType)277 void SearchTabHelper::DidStartNavigationToPendingEntry(
278 const GURL& url,
279 content::NavigationController::ReloadType /* reload_type */) {
280 if (chrome::IsNTPURL(url, profile())) {
281 // Set the title on any pending entry corresponding to the NTP. This
282 // prevents any flickering of the tab title.
283 content::NavigationEntry* entry =
284 web_contents_->GetController().GetPendingEntry();
285 if (entry)
286 entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
287 }
288 }
289
DidNavigateMainFrame(const content::LoadCommittedDetails & details,const content::FrameNavigateParams & params)290 void SearchTabHelper::DidNavigateMainFrame(
291 const content::LoadCommittedDetails& details,
292 const content::FrameNavigateParams& params) {
293 if (IsCacheableNTP(web_contents_)) {
294 if (details.http_status_code == 204 || details.http_status_code >= 400) {
295 RedirectToLocalNTP();
296 RecordCacheableNTPLoadHistogram(false);
297 return;
298 }
299 RecordCacheableNTPLoadHistogram(true);
300 }
301
302 // Always set the title on the new tab page to be the one from our UI
303 // resources. Normally, we set the title when we begin a NTP load, but it can
304 // get reset in several places (like when you press Reload). This check
305 // ensures that the title is properly set to the string defined by the Chrome
306 // UI language (rather than the server language) in all cases.
307 //
308 // We only override the title when it's nonempty to allow the page to set the
309 // title if it really wants. An empty title means to use the default. There's
310 // also a race condition between this code and the page's SetTitle call which
311 // this rule avoids.
312 content::NavigationEntry* entry =
313 web_contents_->GetController().GetLastCommittedEntry();
314 if (entry && entry->GetTitle().empty() &&
315 (entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) ||
316 chrome::NavEntryIsInstantNTP(web_contents_, entry))) {
317 entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
318 }
319 }
320
DidFailProvisionalLoad(int64,const base::string16 &,bool is_main_frame,const GURL & validated_url,int error_code,const base::string16 &,content::RenderViewHost *)321 void SearchTabHelper::DidFailProvisionalLoad(
322 int64 /* frame_id */,
323 const base::string16& /* frame_unique_name */,
324 bool is_main_frame,
325 const GURL& validated_url,
326 int error_code,
327 const base::string16& /* error_description */,
328 content::RenderViewHost* /* render_view_host */) {
329 // If error_code is ERR_ABORTED means that the user has canceled this
330 // navigation so it shouldn't be redirected.
331 if (is_main_frame &&
332 error_code != net::ERR_ABORTED &&
333 validated_url != GURL(chrome::kChromeSearchLocalNtpUrl) &&
334 chrome::IsNTPURL(validated_url, profile())) {
335 RedirectToLocalNTP();
336 RecordCacheableNTPLoadHistogram(false);
337 }
338 }
339
DidFinishLoad(int64,const GURL &,bool is_main_frame,content::RenderViewHost *)340 void SearchTabHelper::DidFinishLoad(
341 int64 /* frame_id */,
342 const GURL& /* validated_url */,
343 bool is_main_frame,
344 content::RenderViewHost* /* render_view_host */) {
345 if (is_main_frame) {
346 if (chrome::IsInstantNTP(web_contents_))
347 RecordNewTabLoadTime(web_contents_);
348
349 DetermineIfPageSupportsInstant();
350 }
351 }
352
NavigationEntryCommitted(const content::LoadCommittedDetails & load_details)353 void SearchTabHelper::NavigationEntryCommitted(
354 const content::LoadCommittedDetails& load_details) {
355 if (!is_search_enabled_)
356 return;
357
358 if (!load_details.is_main_frame)
359 return;
360
361 if (chrome::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(),
362 profile())) {
363 InstantService* instant_service =
364 InstantServiceFactory::GetForProfile(profile());
365 ipc_router_.SetOmniboxStartMargin(instant_service->omnibox_start_margin());
366 ipc_router_.SetDisplayInstantResults();
367 }
368
369 UpdateMode(true, false);
370
371 content::NavigationEntry* entry =
372 web_contents_->GetController().GetVisibleEntry();
373 DCHECK(entry);
374
375 // Already determined the instant support state for this page, do not reset
376 // the instant support state.
377 //
378 // When we get a navigation entry committed event, there seem to be two ways
379 // to tell whether the navigation was "in-page". Ideally, when
380 // LoadCommittedDetails::is_in_page is true, we should have
381 // LoadCommittedDetails::type to be NAVIGATION_TYPE_IN_PAGE. Unfortunately,
382 // they are different in some cases. To workaround this bug, we are checking
383 // (is_in_page || type == NAVIGATION_TYPE_IN_PAGE). Please refer to
384 // crbug.com/251330 for more details.
385 if (load_details.is_in_page ||
386 load_details.type == content::NAVIGATION_TYPE_IN_PAGE) {
387 // When an "in-page" navigation happens, we will not receive a
388 // DidFinishLoad() event. Therefore, we will not determine the Instant
389 // support for the navigated page. So, copy over the Instant support from
390 // the previous entry. If the page does not support Instant, update the
391 // location bar from here to turn off search terms replacement.
392 chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
393 entry);
394 if (delegate_ && model_.instant_support() == INSTANT_SUPPORT_NO)
395 delegate_->OnWebContentsInstantSupportDisabled(web_contents_);
396 return;
397 }
398
399 model_.SetInstantSupportState(INSTANT_SUPPORT_UNKNOWN);
400 model_.SetVoiceSearchSupported(false);
401 chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
402 entry);
403
404 if (InInstantProcess(profile(), web_contents_))
405 ipc_router_.OnNavigationEntryCommitted();
406 }
407
OnInstantSupportDetermined(bool supports_instant)408 void SearchTabHelper::OnInstantSupportDetermined(bool supports_instant) {
409 InstantSupportChanged(supports_instant);
410 }
411
OnSetVoiceSearchSupport(bool supports_voice_search)412 void SearchTabHelper::OnSetVoiceSearchSupport(bool supports_voice_search) {
413 model_.SetVoiceSearchSupported(supports_voice_search);
414 }
415
ThemeInfoChanged(const ThemeBackgroundInfo & theme_info)416 void SearchTabHelper::ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) {
417 ipc_router_.SendThemeBackgroundInfo(theme_info);
418 }
419
MostVisitedItemsChanged(const std::vector<InstantMostVisitedItem> & items)420 void SearchTabHelper::MostVisitedItemsChanged(
421 const std::vector<InstantMostVisitedItem>& items) {
422 std::vector<InstantMostVisitedItem> items_copy(items);
423 MaybeRemoveMostVisitedItems(&items_copy);
424 ipc_router_.SendMostVisitedItems(items_copy);
425 }
426
OmniboxStartMarginChanged(int omnibox_start_margin)427 void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) {
428 ipc_router_.SetOmniboxStartMargin(omnibox_start_margin);
429 }
430
MaybeRemoveMostVisitedItems(std::vector<InstantMostVisitedItem> * items)431 void SearchTabHelper::MaybeRemoveMostVisitedItems(
432 std::vector<InstantMostVisitedItem>* items) {
433 if (!delegate_)
434 return;
435
436 if (!history::MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled())
437 return;
438
439 history::MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(
440 delegate_->GetOpenUrls(), items);
441 }
442
FocusOmnibox(OmniboxFocusState state)443 void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) {
444 // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
445 #if !defined(OS_ANDROID)
446 OmniboxView* omnibox = GetOmniboxView();
447 if (!omnibox)
448 return;
449
450 // Do not add a default case in the switch block for the following reasons:
451 // (1) Explicitly handle the new states. If new states are added in the
452 // OmniboxFocusState, the compiler will warn the developer to handle the new
453 // states.
454 // (2) An attacker may control the renderer and sends the browser process a
455 // malformed IPC. This function responds to the invalid |state| values by
456 // doing nothing instead of crashing the browser process (intentional no-op).
457 switch (state) {
458 case OMNIBOX_FOCUS_VISIBLE:
459 omnibox->SetFocus();
460 omnibox->model()->SetCaretVisibility(true);
461 break;
462 case OMNIBOX_FOCUS_INVISIBLE:
463 omnibox->SetFocus();
464 omnibox->model()->SetCaretVisibility(false);
465 // If the user clicked on the fakebox, any text already in the omnibox
466 // should get cleared when they start typing. Selecting all the existing
467 // text is a convenient way to accomplish this. It also gives a slight
468 // visual cue to users who really understand selection state about what
469 // will happen if they start typing.
470 omnibox->SelectAll(false);
471 omnibox->ShowImeIfNeeded();
472 break;
473 case OMNIBOX_FOCUS_NONE:
474 // Remove focus only if the popup is closed. This will prevent someone
475 // from changing the omnibox value and closing the popup without user
476 // interaction.
477 if (!omnibox->model()->popup_model()->IsOpen())
478 web_contents()->Focus();
479 break;
480 }
481 #endif
482 }
483
NavigateToURL(const GURL & url,WindowOpenDisposition disposition,bool is_most_visited_item_url)484 void SearchTabHelper::NavigateToURL(const GURL& url,
485 WindowOpenDisposition disposition,
486 bool is_most_visited_item_url) {
487 if (is_most_visited_item_url) {
488 content::RecordAction(
489 base::UserMetricsAction("InstantExtended.MostVisitedClicked"));
490 }
491
492 if (delegate_)
493 delegate_->NavigateOnThumbnailClick(url, disposition, web_contents_);
494 }
495
OnDeleteMostVisitedItem(const GURL & url)496 void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) {
497 DCHECK(!url.is_empty());
498 if (instant_service_)
499 instant_service_->DeleteMostVisitedItem(url);
500 }
501
OnUndoMostVisitedDeletion(const GURL & url)502 void SearchTabHelper::OnUndoMostVisitedDeletion(const GURL& url) {
503 DCHECK(!url.is_empty());
504 if (instant_service_)
505 instant_service_->UndoMostVisitedDeletion(url);
506 }
507
OnUndoAllMostVisitedDeletions()508 void SearchTabHelper::OnUndoAllMostVisitedDeletions() {
509 if (instant_service_)
510 instant_service_->UndoAllMostVisitedDeletions();
511 }
512
OnLogEvent(NTPLoggingEventType event)513 void SearchTabHelper::OnLogEvent(NTPLoggingEventType event) {
514 // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
515 #if !defined(OS_ANDROID)
516 NTPUserDataLogger::GetOrCreateFromWebContents(
517 web_contents())->LogEvent(event);
518 #endif
519 }
520
OnLogMostVisitedImpression(int position,const base::string16 & provider)521 void SearchTabHelper::OnLogMostVisitedImpression(
522 int position, const base::string16& provider) {
523 // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
524 #if !defined(OS_ANDROID)
525 NTPUserDataLogger::GetOrCreateFromWebContents(
526 web_contents())->LogMostVisitedImpression(position, provider);
527 #endif
528 }
529
OnLogMostVisitedNavigation(int position,const base::string16 & provider)530 void SearchTabHelper::OnLogMostVisitedNavigation(
531 int position, const base::string16& provider) {
532 // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
533 #if !defined(OS_ANDROID)
534 NTPUserDataLogger::GetOrCreateFromWebContents(
535 web_contents())->LogMostVisitedNavigation(position, provider);
536 #endif
537 }
538
PasteIntoOmnibox(const base::string16 & text)539 void SearchTabHelper::PasteIntoOmnibox(const base::string16& text) {
540 // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
541 #if !defined(OS_ANDROID)
542 OmniboxView* omnibox = GetOmniboxView();
543 if (!omnibox)
544 return;
545 // The first case is for right click to paste, where the text is retrieved
546 // from the clipboard already sanitized. The second case is needed to handle
547 // drag-and-drop value and it has to be sanitazed before setting it into the
548 // omnibox.
549 base::string16 text_to_paste = text.empty() ? omnibox->GetClipboardText() :
550 omnibox->SanitizeTextForPaste(text);
551
552 if (text_to_paste.empty())
553 return;
554
555 if (!omnibox->model()->has_focus())
556 omnibox->SetFocus();
557
558 omnibox->OnBeforePossibleChange();
559 omnibox->model()->OnPaste();
560 omnibox->SetUserText(text_to_paste);
561 omnibox->OnAfterPossibleChange();
562 #endif
563 }
564
OnChromeIdentityCheck(const base::string16 & identity)565 void SearchTabHelper::OnChromeIdentityCheck(const base::string16& identity) {
566 SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile());
567 if (manager) {
568 const base::string16 username =
569 base::UTF8ToUTF16(manager->GetAuthenticatedUsername());
570 // The identity check only passes if the user is syncing their history.
571 // TODO(beaudoin): Change this function name and related APIs now that it's
572 // checking both the identity and the user's sync state.
573 bool matches = IsHistorySyncEnabled(profile()) && identity == username;
574 ipc_router_.SendChromeIdentityCheckResult(identity, matches);
575 }
576 }
577
UpdateMode(bool update_origin,bool is_preloaded_ntp)578 void SearchTabHelper::UpdateMode(bool update_origin, bool is_preloaded_ntp) {
579 SearchMode::Type type = SearchMode::MODE_DEFAULT;
580 SearchMode::Origin origin = SearchMode::ORIGIN_DEFAULT;
581 if (IsNTP(web_contents_) || is_preloaded_ntp) {
582 type = SearchMode::MODE_NTP;
583 origin = SearchMode::ORIGIN_NTP;
584 } else if (IsSearchResults(web_contents_)) {
585 type = SearchMode::MODE_SEARCH_RESULTS;
586 origin = SearchMode::ORIGIN_SEARCH;
587 }
588 if (!update_origin)
589 origin = model_.mode().origin;
590
591 OmniboxView* omnibox = GetOmniboxView();
592 if (omnibox && omnibox->model()->user_input_in_progress())
593 type = SearchMode::MODE_SEARCH_SUGGESTIONS;
594
595 SearchMode old_mode(model_.mode());
596 model_.SetMode(SearchMode(type, origin));
597 if (old_mode.is_ntp() != model_.mode().is_ntp()) {
598 ipc_router_.SetInputInProgress(IsInputInProgress());
599 }
600 }
601
DetermineIfPageSupportsInstant()602 void SearchTabHelper::DetermineIfPageSupportsInstant() {
603 if (!InInstantProcess(profile(), web_contents_)) {
604 // The page is not in the Instant process. This page does not support
605 // instant. If we send an IPC message to a page that is not in the Instant
606 // process, it will never receive it and will never respond. Therefore,
607 // return immediately.
608 InstantSupportChanged(false);
609 } else if (IsLocal(web_contents_)) {
610 // Local pages always support Instant.
611 InstantSupportChanged(true);
612 } else {
613 ipc_router_.DetermineIfPageSupportsInstant();
614 }
615 }
616
profile() const617 Profile* SearchTabHelper::profile() const {
618 return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
619 }
620
RedirectToLocalNTP()621 void SearchTabHelper::RedirectToLocalNTP() {
622 // Extra parentheses to declare a variable.
623 content::NavigationController::LoadURLParams load_params(
624 (GURL(chrome::kChromeSearchLocalNtpUrl)));
625 load_params.referrer = content::Referrer();
626 load_params.transition_type = content::PAGE_TRANSITION_SERVER_REDIRECT;
627 // Don't push a history entry.
628 load_params.should_replace_current_entry = true;
629 web_contents_->GetController().LoadURLWithParams(load_params);
630 }
631
IsInputInProgress() const632 bool SearchTabHelper::IsInputInProgress() const {
633 OmniboxView* omnibox = GetOmniboxView();
634 return !model_.mode().is_ntp() && omnibox &&
635 omnibox->model()->focus_state() == OMNIBOX_FOCUS_VISIBLE;
636 }
637
GetOmniboxView() const638 OmniboxView* SearchTabHelper::GetOmniboxView() const {
639 return delegate_ ? delegate_->GetOmniboxView() : NULL;
640 }
641