Home | History | Annotate | Download | only in search
      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 
     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 
     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 
     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 
     88 bool IsSearchResults(const content::WebContents* contents) {
     89   return !chrome::GetSearchTerms(contents).empty();
     90 }
     91 
     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.
    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.
    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.
    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 
    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 
    157 SearchTabHelper::~SearchTabHelper() {
    158   if (instant_service_)
    159     instant_service_->RemoveObserver(this);
    160 }
    161 
    162 void SearchTabHelper::InitForPreloadedNTP() {
    163   UpdateMode(true, true);
    164 }
    165 
    166 void SearchTabHelper::OmniboxInputStateChanged() {
    167   if (!is_search_enabled_)
    168     return;
    169 
    170   UpdateMode(false, false);
    171 }
    172 
    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 
    206 void SearchTabHelper::NavigationEntryUpdated() {
    207   if (!is_search_enabled_)
    208     return;
    209 
    210   UpdateMode(false, false);
    211 }
    212 
    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 
    231 bool SearchTabHelper::SupportsInstant() const {
    232   return model_.instant_support() == INSTANT_SUPPORT_YES;
    233 }
    234 
    235 void SearchTabHelper::SetSuggestionToPrefetch(
    236     const InstantSuggestion& suggestion) {
    237   ipc_router_.SetSuggestionToPrefetch(suggestion);
    238 }
    239 
    240 void SearchTabHelper::Submit(const base::string16& text) {
    241   ipc_router_.Submit(text);
    242 }
    243 
    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 
    260 void SearchTabHelper::OnTabDeactivated() {
    261   ipc_router_.OnTabDeactivated();
    262 }
    263 
    264 void SearchTabHelper::ToggleVoiceSearch() {
    265   ipc_router_.ToggleVoiceSearch();
    266 }
    267 
    268 bool SearchTabHelper::IsSearchResultsPage() {
    269   return model_.mode().is_origin_search();
    270 }
    271 
    272 void SearchTabHelper::RenderViewCreated(
    273     content::RenderViewHost* render_view_host) {
    274   ipc_router_.SetPromoInformation(IsAppLauncherEnabled());
    275 }
    276 
    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 
    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 
    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 
    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 
    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 
    408 void SearchTabHelper::OnInstantSupportDetermined(bool supports_instant) {
    409   InstantSupportChanged(supports_instant);
    410 }
    411 
    412 void SearchTabHelper::OnSetVoiceSearchSupport(bool supports_voice_search) {
    413   model_.SetVoiceSearchSupported(supports_voice_search);
    414 }
    415 
    416 void SearchTabHelper::ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) {
    417   ipc_router_.SendThemeBackgroundInfo(theme_info);
    418 }
    419 
    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 
    427 void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) {
    428   ipc_router_.SetOmniboxStartMargin(omnibox_start_margin);
    429 }
    430 
    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 
    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 
    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 
    496 void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) {
    497   DCHECK(!url.is_empty());
    498   if (instant_service_)
    499     instant_service_->DeleteMostVisitedItem(url);
    500 }
    501 
    502 void SearchTabHelper::OnUndoMostVisitedDeletion(const GURL& url) {
    503   DCHECK(!url.is_empty());
    504   if (instant_service_)
    505     instant_service_->UndoMostVisitedDeletion(url);
    506 }
    507 
    508 void SearchTabHelper::OnUndoAllMostVisitedDeletions() {
    509   if (instant_service_)
    510     instant_service_->UndoAllMostVisitedDeletions();
    511 }
    512 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    617 Profile* SearchTabHelper::profile() const {
    618   return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
    619 }
    620 
    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 
    632 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 
    638 OmniboxView* SearchTabHelper::GetOmniboxView() const {
    639   return delegate_ ? delegate_->GetOmniboxView() : NULL;
    640 }
    641