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/browser_instant_controller.h" 6 7 #include "base/bind.h" 8 #include "chrome/browser/infobars/infobar_service.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/search/instant_service.h" 11 #include "chrome/browser/search/instant_service_factory.h" 12 #include "chrome/browser/search/search.h" 13 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/browser_window.h" 15 #include "chrome/browser/ui/location_bar/location_bar.h" 16 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 17 #include "chrome/browser/ui/omnibox/omnibox_view.h" 18 #include "chrome/browser/ui/search/instant_search_prerenderer.h" 19 #include "chrome/browser/ui/search/search_model.h" 20 #include "chrome/browser/ui/search/search_tab_helper.h" 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" 22 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" 23 #include "chrome/common/url_constants.h" 24 #include "content/public/browser/render_process_host.h" 25 #include "content/public/browser/user_metrics.h" 26 #include "content/public/browser/web_contents.h" 27 28 29 // Helpers -------------------------------------------------------------------- 30 31 namespace { 32 33 InstantSearchPrerenderer* GetInstantSearchPrerenderer(Profile* profile) { 34 DCHECK(profile); 35 InstantService* instant_service = 36 InstantServiceFactory::GetForProfile(profile); 37 return instant_service ? instant_service->instant_search_prerenderer() : NULL; 38 } 39 40 } // namespace 41 42 43 // BrowserInstantController --------------------------------------------------- 44 45 BrowserInstantController::BrowserInstantController(Browser* browser) 46 : browser_(browser), 47 instant_(this) { 48 browser_->search_model()->AddObserver(this); 49 50 InstantService* instant_service = 51 InstantServiceFactory::GetForProfile(profile()); 52 instant_service->AddObserver(this); 53 } 54 55 BrowserInstantController::~BrowserInstantController() { 56 browser_->search_model()->RemoveObserver(this); 57 58 InstantService* instant_service = 59 InstantServiceFactory::GetForProfile(profile()); 60 instant_service->RemoveObserver(this); 61 } 62 63 bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition, 64 const GURL& url) { 65 // Unsupported dispositions. 66 if (disposition == NEW_BACKGROUND_TAB || disposition == NEW_WINDOW || 67 disposition == NEW_FOREGROUND_TAB) 68 return false; 69 70 // The omnibox currently doesn't use other dispositions, so we don't attempt 71 // to handle them. If you hit this DCHECK file a bug and I'll (sky) add 72 // support for the new disposition. 73 DCHECK(disposition == CURRENT_TAB) << disposition; 74 75 const base::string16& search_terms = 76 chrome::ExtractSearchTermsFromURL(profile(), url); 77 if (search_terms.empty()) 78 return false; 79 80 InstantSearchPrerenderer* prerenderer = 81 GetInstantSearchPrerenderer(profile()); 82 if (prerenderer) { 83 if (prerenderer->CanCommitQuery(GetActiveWebContents(), search_terms)) { 84 // Submit query to render the prefetched results. Browser will swap the 85 // prerendered contents with the active tab contents. 86 prerenderer->Commit(search_terms); 87 return false; 88 } else { 89 prerenderer->Cancel(); 90 } 91 } 92 93 // If we will not be replacing search terms from this URL, don't send to 94 // InstantController. 95 if (!chrome::IsQueryExtractionAllowedForURL(profile(), url)) 96 return false; 97 98 return instant_.SubmitQuery(search_terms); 99 } 100 101 Profile* BrowserInstantController::profile() const { 102 return browser_->profile(); 103 } 104 105 content::WebContents* BrowserInstantController::GetActiveWebContents() const { 106 return browser_->tab_strip_model()->GetActiveWebContents(); 107 } 108 109 void BrowserInstantController::ActiveTabChanged() { 110 instant_.ActiveTabChanged(); 111 } 112 113 void BrowserInstantController::TabDeactivated(content::WebContents* contents) { 114 instant_.TabDeactivated(contents); 115 116 InstantSearchPrerenderer* prerenderer = 117 GetInstantSearchPrerenderer(profile()); 118 if (prerenderer) 119 prerenderer->Cancel(); 120 } 121 122 void BrowserInstantController::ModelChanged( 123 const SearchModel::State& old_state, 124 const SearchModel::State& new_state) { 125 if (old_state.mode != new_state.mode) { 126 const SearchMode& new_mode = new_state.mode; 127 128 // Record some actions corresponding to the mode change. Note that to get 129 // the full story, it's necessary to look at other UMA actions as well, 130 // such as tab switches. 131 if (new_mode.is_search_results()) 132 content::RecordAction(base::UserMetricsAction("InstantExtended.ShowSRP")); 133 else if (new_mode.is_ntp()) 134 content::RecordAction(base::UserMetricsAction("InstantExtended.ShowNTP")); 135 136 instant_.SearchModeChanged(old_state.mode, new_mode); 137 } 138 139 if (old_state.instant_support != new_state.instant_support) 140 instant_.InstantSupportChanged(new_state.instant_support); 141 } 142 143 void BrowserInstantController::DefaultSearchProviderChanged() { 144 InstantService* instant_service = 145 InstantServiceFactory::GetForProfile(profile()); 146 if (!instant_service) 147 return; 148 149 TabStripModel* tab_model = browser_->tab_strip_model(); 150 int count = tab_model->count(); 151 for (int index = 0; index < count; ++index) { 152 content::WebContents* contents = tab_model->GetWebContentsAt(index); 153 if (!contents) 154 continue; 155 156 // Send new search URLs to the renderer. 157 content::RenderProcessHost* rph = contents->GetRenderProcessHost(); 158 instant_service->SendSearchURLsToRenderer(rph); 159 160 // Reload the contents to ensure that it gets assigned to a non-priviledged 161 // renderer. 162 if (!instant_service->IsInstantProcess(rph->GetID())) 163 continue; 164 165 contents->GetController().Reload(false); 166 167 // As the reload was not triggered by the user we don't want to close any 168 // infobars. We have to tell the InfoBarService after the reload, otherwise 169 // it would ignore this call when 170 // WebContentsObserver::DidStartNavigationToPendingEntry is invoked. 171 InfoBarService::FromWebContents(contents)->set_ignore_next_reload(); 172 } 173 } 174