blob: 1117ae14add108b84a2ec95eac83ba5d7a7d6b8d [file] [log] [blame]
[email protected]e41982a72012-11-20 07:16:511// Copyright 2012 The Chromium Authors. All rights reserved.
[email protected]7acfaf92012-07-11 15:51:592// 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
[email protected]3853a4c2013-02-11 17:15:577#include "base/prefs/pref_service.h"
[email protected]7acfaf92012-07-11 15:51:598#include "chrome/browser/extensions/extension_service.h"
[email protected]26015ac2013-02-27 02:50:139#include "chrome/browser/extensions/extension_web_ui.h"
[email protected]7acfaf92012-07-11 15:51:5910#include "chrome/browser/profiles/profile.h"
[email protected]a7b8e43d2013-03-18 18:52:4311#include "chrome/browser/search/search.h"
[email protected]e119b802013-02-18 18:55:3912#include "chrome/browser/themes/theme_properties.h"
[email protected]a6827652012-11-20 23:41:0813#include "chrome/browser/themes/theme_service.h"
14#include "chrome/browser/themes/theme_service_factory.h"
[email protected]7acfaf92012-07-11 15:51:5915#include "chrome/browser/ui/browser.h"
[email protected]7acfaf92012-07-11 15:51:5916#include "chrome/browser/ui/browser_window.h"
17#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]c18cb672012-12-05 04:42:1218#include "chrome/browser/ui/omnibox/omnibox_view.h"
[email protected]9d3d11702012-11-08 01:01:1219#include "chrome/browser/ui/search/search_tab_helper.h"
[email protected]e41982a72012-11-20 07:16:5120#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]7acfaf92012-07-11 15:51:5921#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
22#include "chrome/common/chrome_notification_types.h"
23#include "chrome/common/pref_names.h"
[email protected]0c9406632013-02-08 01:13:3324#include "chrome/common/url_constants.h"
[email protected]75fee372013-03-06 00:42:4425#include "components/user_prefs/pref_registry_syncable.h"
[email protected]7acfaf92012-07-11 15:51:5926#include "content/public/browser/notification_service.h"
[email protected]233f0f962013-02-27 21:14:1927#include "content/public/browser/user_metrics.h"
[email protected]a6827652012-11-20 23:41:0828#include "grit/theme_resources.h"
29#include "ui/gfx/color_utils.h"
30#include "ui/gfx/sys_color_change_listener.h"
31
[email protected]233f0f962013-02-27 21:14:1932using content::UserMetricsAction;
33
[email protected]7acfaf92012-07-11 15:51:5934////////////////////////////////////////////////////////////////////////////////
35// BrowserInstantController, public:
36
37BrowserInstantController::BrowserInstantController(Browser* browser)
[email protected]8a236702012-09-28 13:30:5738 : browser_(browser),
[email protected]e41982a72012-11-20 07:16:5139 instant_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
[email protected]165fe422013-03-27 06:34:0340 chrome::IsInstantExtendedAPIEnabled()),
[email protected]a6827652012-11-20 23:41:0841 instant_unload_handler_(browser),
[email protected]e4a379c2013-02-15 19:27:1942 initialized_theme_info_(false) {
[email protected]5879cef2013-03-02 17:02:2543
[email protected]5fac3782013-03-06 09:32:3144 // In one mode of the InstantExtended experiments, the kInstantExtendedEnabled
45 // preference's default value is set to the existing value of kInstantEnabled.
46 // Because this requires reading the value of the kInstantEnabled value, we
47 // reset the default for kInstantExtendedEnabled here.
[email protected]165fe422013-03-27 06:34:0348 chrome::SetInstantExtendedPrefDefault(profile());
[email protected]5879cef2013-03-02 17:02:2549
[email protected]5fac3782013-03-06 09:32:3150 profile_pref_registrar_.Init(profile()->GetPrefs());
[email protected]0b3fa502012-11-21 13:57:4651 profile_pref_registrar_.Add(
[email protected]5fac3782013-03-06 09:32:3152 prefs::kInstantEnabled,
53 base::Bind(&BrowserInstantController::ResetInstant,
54 base::Unretained(this)));
55 profile_pref_registrar_.Add(
56 prefs::kInstantExtendedEnabled,
[email protected]0b3fa502012-11-21 13:57:4657 base::Bind(&BrowserInstantController::ResetInstant,
58 base::Unretained(this)));
[email protected]411c9c02013-02-07 04:55:5959 profile_pref_registrar_.Add(
60 prefs::kSearchSuggestEnabled,
61 base::Bind(&BrowserInstantController::ResetInstant,
62 base::Unretained(this)));
[email protected]5fac3782013-03-06 09:32:3163 ResetInstant(std::string());
[email protected]0b10c9ff2012-10-09 17:31:5564 browser_->search_model()->AddObserver(this);
[email protected]a6827652012-11-20 23:41:0865
66#if defined(ENABLE_THEMES)
67 // Listen for theme installation.
68 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
69 content::Source<ThemeService>(
[email protected]0c9406632013-02-08 01:13:3370 ThemeServiceFactory::GetForProfile(profile())));
[email protected]a6827652012-11-20 23:41:0871#endif // defined(ENABLE_THEMES)
[email protected]7acfaf92012-07-11 15:51:5972}
73
74BrowserInstantController::~BrowserInstantController() {
[email protected]0b10c9ff2012-10-09 17:31:5575 browser_->search_model()->RemoveObserver(this);
[email protected]7acfaf92012-07-11 15:51:5976}
77
[email protected]0c9406632013-02-08 01:13:3378bool BrowserInstantController::MaybeSwapInInstantNTPContents(
79 const GURL& url,
80 content::WebContents* source_contents,
81 content::WebContents** target_contents) {
82 if (url != GURL(chrome::kChromeUINewTabURL))
83 return false;
84
[email protected]26015ac2013-02-27 02:50:1385 GURL extension_url(url);
86 if (ExtensionWebUI::HandleChromeURLOverride(&extension_url, profile())) {
87 // If there is an extension overriding the NTP do not use the Instant NTP.
88 return false;
89 }
90
[email protected]0c9406632013-02-08 01:13:3391 scoped_ptr<content::WebContents> instant_ntp = instant_.ReleaseNTPContents();
92 if (!instant_ntp)
93 return false;
94
95 *target_contents = instant_ntp.get();
[email protected]0c9406632013-02-08 01:13:3396 if (source_contents) {
97 instant_ntp->GetController().CopyStateFromAndPrune(
98 &source_contents->GetController());
99 ReplaceWebContentsAt(
100 browser_->tab_strip_model()->GetIndexOfWebContents(source_contents),
101 instant_ntp.Pass());
102 } else {
[email protected]57b58ca12013-02-26 23:41:25103 instant_ntp->GetController().PruneAllButActive();
[email protected]0c9406632013-02-08 01:13:33104 // If |source_contents| is NULL, then the caller is responsible for
105 // inserting instant_ntp into the tabstrip and will take ownership.
106 ignore_result(instant_ntp.release());
107 }
[email protected]0c9406632013-02-08 01:13:33108 return true;
109}
110
[email protected]7acfaf92012-07-11 15:51:59111bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition) {
[email protected]e41982a72012-11-20 07:16:51112 // Unsupported dispositions.
113 if (disposition == NEW_BACKGROUND_TAB || disposition == NEW_WINDOW)
[email protected]7acfaf92012-07-11 15:51:59114 return false;
[email protected]7acfaf92012-07-11 15:51:59115
[email protected]7acfaf92012-07-11 15:51:59116 // The omnibox currently doesn't use other dispositions, so we don't attempt
[email protected]c72226c82012-10-01 21:02:32117 // to handle them. If you hit this DCHECK file a bug and I'll (sky) add
[email protected]7acfaf92012-07-11 15:51:59118 // support for the new disposition.
[email protected]c72226c82012-10-01 21:02:32119 DCHECK(disposition == CURRENT_TAB ||
120 disposition == NEW_FOREGROUND_TAB) << disposition;
121
[email protected]221e9202012-12-08 00:59:09122 return instant_.CommitIfPossible(disposition == CURRENT_TAB ?
[email protected]c72226c82012-10-01 21:02:32123 INSTANT_COMMIT_PRESSED_ENTER : INSTANT_COMMIT_PRESSED_ALT_ENTER);
[email protected]7acfaf92012-07-11 15:51:59124}
125
[email protected]0c9406632013-02-08 01:13:33126Profile* BrowserInstantController::profile() const {
127 return browser_->profile();
128}
129
130void BrowserInstantController::CommitInstant(
[email protected]ddd28ae2013-03-04 21:11:54131 scoped_ptr<content::WebContents> overlay,
[email protected]0c9406632013-02-08 01:13:33132 bool in_new_tab) {
[email protected]79f17ef462013-03-24 00:28:18133 const extensions::Extension* extension =
134 profile()->GetExtensionService()->GetInstalledApp(overlay->GetURL());
135 if (extension) {
[email protected]0c9406632013-02-08 01:13:33136 AppLauncherHandler::RecordAppLaunchType(
[email protected]79f17ef462013-03-24 00:28:18137 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT,
138 extension->GetType());
[email protected]0c9406632013-02-08 01:13:33139 }
[email protected]c72226c82012-10-01 21:02:32140 if (in_new_tab) {
[email protected]ddd28ae2013-03-04 21:11:54141 // TabStripModel takes ownership of |overlay|.
142 browser_->tab_strip_model()->AddWebContents(overlay.release(), -1,
[email protected]e41982a72012-11-20 07:16:51143 instant_.last_transition_type(), TabStripModel::ADD_ACTIVE);
[email protected]c72226c82012-10-01 21:02:32144 } else {
[email protected]0c9406632013-02-08 01:13:33145 ReplaceWebContentsAt(
146 browser_->tab_strip_model()->active_index(),
[email protected]ddd28ae2013-03-04 21:11:54147 overlay.Pass());
[email protected]7acfaf92012-07-11 15:51:59148 }
149}
150
[email protected]0c9406632013-02-08 01:13:33151void BrowserInstantController::ReplaceWebContentsAt(
152 int index,
153 scoped_ptr<content::WebContents> new_contents) {
154 DCHECK_NE(TabStripModel::kNoTab, index);
[email protected]d572bfd2013-02-14 06:14:20155 scoped_ptr<content::WebContents> old_contents(browser_->tab_strip_model()->
156 ReplaceWebContentsAt(index, new_contents.release()));
157 instant_unload_handler_.RunUnloadListenersOrDestroy(old_contents.Pass(),
158 index);
[email protected]0c9406632013-02-08 01:13:33159}
160
[email protected]93b73832012-10-18 20:18:38161void BrowserInstantController::SetInstantSuggestion(
162 const InstantSuggestion& suggestion) {
[email protected]c18cb672012-12-05 04:42:12163 browser_->window()->GetLocationBar()->SetInstantSuggestion(suggestion);
[email protected]7acfaf92012-07-11 15:51:59164}
165
[email protected]727a6c42013-02-27 19:47:26166void BrowserInstantController::CommitSuggestedText(
167 bool skip_inline_autocomplete) {
168 browser_->window()->GetLocationBar()->GetLocationEntry()->model()->
169 CommitSuggestedText(skip_inline_autocomplete);
170}
171
[email protected]7acfaf92012-07-11 15:51:59172gfx::Rect BrowserInstantController::GetInstantBounds() {
173 return browser_->window()->GetInstantBounds();
174}
175
[email protected]ddd28ae2013-03-04 21:11:54176void BrowserInstantController::InstantOverlayFocused() {
[email protected]7acfaf92012-07-11 15:51:59177 // NOTE: This is only invoked on aura.
[email protected]ddd28ae2013-03-04 21:11:54178 browser_->window()->WebContentsFocused(instant_.GetOverlayContents());
[email protected]7acfaf92012-07-11 15:51:59179}
180
[email protected]10aec592013-03-06 20:19:00181void BrowserInstantController::FocusOmnibox(bool caret_visibility) {
[email protected]c18cb672012-12-05 04:42:12182 OmniboxView* omnibox_view = browser_->window()->GetLocationBar()->
183 GetLocationEntry();
184 omnibox_view->SetFocus();
[email protected]10aec592013-03-06 20:19:00185 omnibox_view->model()->SetCaretVisibility(caret_visibility);
[email protected]c18cb672012-12-05 04:42:12186}
187
[email protected]cd533bf2012-12-04 19:14:59188content::WebContents* BrowserInstantController::GetActiveWebContents() const {
189 return browser_->tab_strip_model()->GetActiveWebContents();
[email protected]7acfaf92012-07-11 15:51:59190}
191
[email protected]e41982a72012-11-20 07:16:51192void BrowserInstantController::ActiveTabChanged() {
193 instant_.ActiveTabChanged();
194}
195
[email protected]3d6a8952012-12-14 03:18:07196void BrowserInstantController::TabDeactivated(content::WebContents* contents) {
197 instant_.TabDeactivated(contents);
198}
199
[email protected]3870363e2013-03-06 20:11:23200void BrowserInstantController::UpdateThemeInfo() {
[email protected]e4a379c2013-02-15 19:27:19201 // Update theme background info.
[email protected]3870363e2013-03-06 20:11:23202 // Initialize |theme_info| if necessary.
203 if (!initialized_theme_info_)
[email protected]0c9406632013-02-08 01:13:33204 OnThemeChanged(ThemeServiceFactory::GetForProfile(profile()));
[email protected]a6827652012-11-20 23:41:08205 else
206 OnThemeChanged(NULL);
207}
208
[email protected]3c3acca2013-02-26 03:07:07209void BrowserInstantController::OpenURL(
[email protected]e3033eb2012-12-13 23:46:08210 const GURL& url,
[email protected]3c3acca2013-02-26 03:07:07211 content::PageTransition transition,
212 WindowOpenDisposition disposition) {
[email protected]e3033eb2012-12-13 23:46:08213 browser_->OpenURL(content::OpenURLParams(url,
214 content::Referrer(),
[email protected]3c3acca2013-02-26 03:07:07215 disposition,
[email protected]e3033eb2012-12-13 23:46:08216 transition,
217 false));
218}
219
[email protected]fcde79a2013-02-28 02:25:09220void BrowserInstantController::SetOmniboxBounds(const gfx::Rect& bounds) {
221 instant_.SetOmniboxBounds(bounds);
[email protected]ec4aad542012-12-14 01:11:04222}
223
[email protected]5fac3782013-03-06 09:32:31224void BrowserInstantController::ResetInstant(const std::string& pref_name) {
225 // Update the default value of the kInstantExtendedEnabled pref to match the
226 // value of the kInstantEnabled pref, if necessary.
227 if (pref_name == prefs::kInstantEnabled)
[email protected]165fe422013-03-27 06:34:03228 chrome::SetInstantExtendedPrefDefault(profile());
[email protected]5fac3782013-03-06 09:32:31229
[email protected]165fe422013-03-27 06:34:03230 bool instant_pref_enabled = chrome::IsInstantPrefEnabled(profile());
[email protected]ddd28ae2013-03-04 21:11:54231 bool use_local_overlay_only = profile()->IsOffTheRecord() ||
[email protected]5fac3782013-03-06 09:32:31232 (!instant_pref_enabled &&
[email protected]0c9406632013-02-08 01:13:33233 !profile()->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled));
[email protected]5fac3782013-03-06 09:32:31234 instant_.SetInstantEnabled(instant_pref_enabled, use_local_overlay_only);
[email protected]749ce882012-11-16 04:18:01235}
236
[email protected]7acfaf92012-07-11 15:51:59237////////////////////////////////////////////////////////////////////////////////
[email protected]165fe422013-03-27 06:34:03238// BrowserInstantController, SearchModelObserver implementation:
[email protected]0b10c9ff2012-10-09 17:31:55239
[email protected]5ee671f2013-03-19 11:23:05240void BrowserInstantController::ModelChanged(
[email protected]165fe422013-03-27 06:34:03241 const SearchModel::State& old_state,
242 const SearchModel::State& new_state) {
[email protected]5ee671f2013-03-19 11:23:05243 if (old_state.mode == new_state.mode)
244 return;
245
[email protected]165fe422013-03-27 06:34:03246 const SearchMode& new_mode = new_state.mode;
[email protected]5ee671f2013-03-19 11:23:05247
[email protected]165fe422013-03-27 06:34:03248 if (chrome::IsInstantExtendedAPIEnabled()) {
[email protected]c19ba1042013-03-11 17:17:13249 // Record some actions corresponding to the mode change. Note that to get
250 // the full story, it's necessary to look at other UMA actions as well,
251 // such as tab switches.
252 if (new_mode.is_search_results())
253 content::RecordAction(UserMetricsAction("InstantExtended.ShowSRP"));
254 else if (new_mode.is_ntp())
255 content::RecordAction(UserMetricsAction("InstantExtended.ShowNTP"));
256 }
257
[email protected]ddd28ae2013-03-04 21:11:54258 // If mode is now |NTP|, send theme-related information to Instant.
[email protected]a6827652012-11-20 23:41:08259 if (new_mode.is_ntp())
[email protected]3870363e2013-03-06 20:11:23260 UpdateThemeInfo();
[email protected]a6827652012-11-20 23:41:08261
[email protected]5ee671f2013-03-19 11:23:05262 instant_.SearchModeChanged(old_state.mode, new_mode);
[email protected]7acfaf92012-07-11 15:51:59263}
264
[email protected]a6827652012-11-20 23:41:08265////////////////////////////////////////////////////////////////////////////////
266// BrowserInstantController, content::NotificationObserver implementation:
267
268void BrowserInstantController::Observe(
269 int type,
270 const content::NotificationSource& source,
271 const content::NotificationDetails& details) {
272#if defined(ENABLE_THEMES)
273 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
274 OnThemeChanged(content::Source<ThemeService>(source).ptr());
275#endif // defined(ENABLE_THEMES)
276}
277
278void BrowserInstantController::OnThemeChanged(ThemeService* theme_service) {
279 if (theme_service) { // Get theme information from theme service.
280 theme_info_ = ThemeBackgroundInfo();
281
282 // Set theme background color.
283 SkColor background_color =
[email protected]e119b802013-02-18 18:55:39284 theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
[email protected]a6827652012-11-20 23:41:08285 if (gfx::IsInvertedColorScheme())
286 background_color = color_utils::InvertColor(background_color);
287 theme_info_.color_r = SkColorGetR(background_color);
288 theme_info_.color_g = SkColorGetG(background_color);
289 theme_info_.color_b = SkColorGetB(background_color);
290 theme_info_.color_a = SkColorGetA(background_color);
291
292 if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
293 // Set theme id for theme background image url.
294 theme_info_.theme_id = theme_service->GetThemeID();
295
296 // Set theme background image horizontal alignment.
297 int alignment = 0;
[email protected]e119b802013-02-18 18:55:39298 theme_service->GetDisplayProperty(
299 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &alignment);
300 if (alignment & ThemeProperties::ALIGN_LEFT) {
[email protected]a6827652012-11-20 23:41:08301 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
[email protected]e119b802013-02-18 18:55:39302 } else if (alignment & ThemeProperties::ALIGN_RIGHT) {
[email protected]a6827652012-11-20 23:41:08303 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
304 } else { // ALIGN_CENTER
305 theme_info_.image_horizontal_alignment =
306 THEME_BKGRND_IMAGE_ALIGN_CENTER;
307 }
308
309 // Set theme background image vertical alignment.
[email protected]3870363e2013-03-06 20:11:23310 if (alignment & ThemeProperties::ALIGN_TOP)
[email protected]a6827652012-11-20 23:41:08311 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
[email protected]3870363e2013-03-06 20:11:23312 else if (alignment & ThemeProperties::ALIGN_BOTTOM)
[email protected]a6827652012-11-20 23:41:08313 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
[email protected]3870363e2013-03-06 20:11:23314 else // ALIGN_CENTER
[email protected]a6827652012-11-20 23:41:08315 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
[email protected]a6827652012-11-20 23:41:08316
317 // Set theme background image tiling.
318 int tiling = 0;
[email protected]e119b802013-02-18 18:55:39319 theme_service->GetDisplayProperty(ThemeProperties::NTP_BACKGROUND_TILING,
[email protected]a6827652012-11-20 23:41:08320 &tiling);
321 switch (tiling) {
[email protected]e119b802013-02-18 18:55:39322 case ThemeProperties::NO_REPEAT:
[email protected]a6827652012-11-20 23:41:08323 theme_info_.image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
324 break;
[email protected]e119b802013-02-18 18:55:39325 case ThemeProperties::REPEAT_X:
[email protected]a6827652012-11-20 23:41:08326 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
327 break;
[email protected]e119b802013-02-18 18:55:39328 case ThemeProperties::REPEAT_Y:
[email protected]a6827652012-11-20 23:41:08329 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
330 break;
[email protected]e119b802013-02-18 18:55:39331 case ThemeProperties::REPEAT:
[email protected]a6827652012-11-20 23:41:08332 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT;
333 break;
334 }
335
336 // Set theme background image height.
337 gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
338 IDR_THEME_NTP_BACKGROUND);
339 DCHECK(image);
340 theme_info_.image_height = image->height();
[email protected]5189fa12013-03-20 23:00:05341
342 theme_info_.has_attribution =
343 theme_service->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
[email protected]a6827652012-11-20 23:41:08344 }
345
346 initialized_theme_info_ = true;
347 }
348
349 DCHECK(initialized_theme_info_);
350
[email protected]e4a379c2013-02-15 19:27:19351 if (browser_->search_model()->mode().is_ntp())
[email protected]a6827652012-11-20 23:41:08352 instant_.ThemeChanged(theme_info_);
[email protected]a6827652012-11-20 23:41:08353}