blob: 5ffb7f048551ff905f7e44d458e205b7f3f3f9ef [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]09e9f692013-03-07 23:53:0410#include "chrome/browser/instant/search.h"
[email protected]7acfaf92012-07-11 15:51:5911#include "chrome/browser/profiles/profile.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:5934namespace chrome {
35
36////////////////////////////////////////////////////////////////////////////////
37// BrowserInstantController, public:
38
39BrowserInstantController::BrowserInstantController(Browser* browser)
[email protected]8a236702012-09-28 13:30:5740 : browser_(browser),
[email protected]e41982a72012-11-20 07:16:5141 instant_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
[email protected]f6a8dd632013-03-06 01:27:0442 chrome::search::IsInstantExtendedAPIEnabled()),
[email protected]a6827652012-11-20 23:41:0843 instant_unload_handler_(browser),
[email protected]e4a379c2013-02-15 19:27:1944 initialized_theme_info_(false) {
[email protected]5879cef2013-03-02 17:02:2545
[email protected]5fac3782013-03-06 09:32:3146 // In one mode of the InstantExtended experiments, the kInstantExtendedEnabled
47 // preference's default value is set to the existing value of kInstantEnabled.
48 // Because this requires reading the value of the kInstantEnabled value, we
49 // reset the default for kInstantExtendedEnabled here.
50 chrome::search::SetInstantExtendedPrefDefault(profile());
[email protected]5879cef2013-03-02 17:02:2551
[email protected]5fac3782013-03-06 09:32:3152 profile_pref_registrar_.Init(profile()->GetPrefs());
[email protected]0b3fa50c2012-11-21 13:57:4653 profile_pref_registrar_.Add(
[email protected]5fac3782013-03-06 09:32:3154 prefs::kInstantEnabled,
55 base::Bind(&BrowserInstantController::ResetInstant,
56 base::Unretained(this)));
57 profile_pref_registrar_.Add(
58 prefs::kInstantExtendedEnabled,
[email protected]0b3fa50c2012-11-21 13:57:4659 base::Bind(&BrowserInstantController::ResetInstant,
60 base::Unretained(this)));
[email protected]411c9c02013-02-07 04:55:5961 profile_pref_registrar_.Add(
62 prefs::kSearchSuggestEnabled,
63 base::Bind(&BrowserInstantController::ResetInstant,
64 base::Unretained(this)));
[email protected]5fac3782013-03-06 09:32:3165 ResetInstant(std::string());
[email protected]0b10c9ff2012-10-09 17:31:5566 browser_->search_model()->AddObserver(this);
[email protected]a6827652012-11-20 23:41:0867
68#if defined(ENABLE_THEMES)
69 // Listen for theme installation.
70 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
71 content::Source<ThemeService>(
[email protected]0c9406632013-02-08 01:13:3372 ThemeServiceFactory::GetForProfile(profile())));
[email protected]a6827652012-11-20 23:41:0873#endif // defined(ENABLE_THEMES)
[email protected]7acfaf92012-07-11 15:51:5974}
75
76BrowserInstantController::~BrowserInstantController() {
[email protected]0b10c9ff2012-10-09 17:31:5577 browser_->search_model()->RemoveObserver(this);
[email protected]7acfaf92012-07-11 15:51:5978}
79
[email protected]0c9406632013-02-08 01:13:3380bool BrowserInstantController::MaybeSwapInInstantNTPContents(
81 const GURL& url,
82 content::WebContents* source_contents,
83 content::WebContents** target_contents) {
84 if (url != GURL(chrome::kChromeUINewTabURL))
85 return false;
86
[email protected]26015ac2013-02-27 02:50:1387 GURL extension_url(url);
88 if (ExtensionWebUI::HandleChromeURLOverride(&extension_url, profile())) {
89 // If there is an extension overriding the NTP do not use the Instant NTP.
90 return false;
91 }
92
[email protected]0c9406632013-02-08 01:13:3393 scoped_ptr<content::WebContents> instant_ntp = instant_.ReleaseNTPContents();
94 if (!instant_ntp)
95 return false;
96
97 *target_contents = instant_ntp.get();
[email protected]0c9406632013-02-08 01:13:3398 if (source_contents) {
99 instant_ntp->GetController().CopyStateFromAndPrune(
100 &source_contents->GetController());
101 ReplaceWebContentsAt(
102 browser_->tab_strip_model()->GetIndexOfWebContents(source_contents),
103 instant_ntp.Pass());
104 } else {
[email protected]57b58ca12013-02-26 23:41:25105 instant_ntp->GetController().PruneAllButActive();
[email protected]0c9406632013-02-08 01:13:33106 // If |source_contents| is NULL, then the caller is responsible for
107 // inserting instant_ntp into the tabstrip and will take ownership.
108 ignore_result(instant_ntp.release());
109 }
110 return true;
111}
112
[email protected]7acfaf92012-07-11 15:51:59113bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition) {
[email protected]e41982a72012-11-20 07:16:51114 // Unsupported dispositions.
115 if (disposition == NEW_BACKGROUND_TAB || disposition == NEW_WINDOW)
[email protected]7acfaf92012-07-11 15:51:59116 return false;
[email protected]7acfaf92012-07-11 15:51:59117
[email protected]7acfaf92012-07-11 15:51:59118 // The omnibox currently doesn't use other dispositions, so we don't attempt
[email protected]c72226c82012-10-01 21:02:32119 // to handle them. If you hit this DCHECK file a bug and I'll (sky) add
[email protected]7acfaf92012-07-11 15:51:59120 // support for the new disposition.
[email protected]c72226c82012-10-01 21:02:32121 DCHECK(disposition == CURRENT_TAB ||
122 disposition == NEW_FOREGROUND_TAB) << disposition;
123
[email protected]221e9202012-12-08 00:59:09124 return instant_.CommitIfPossible(disposition == CURRENT_TAB ?
[email protected]c72226c82012-10-01 21:02:32125 INSTANT_COMMIT_PRESSED_ENTER : INSTANT_COMMIT_PRESSED_ALT_ENTER);
[email protected]7acfaf92012-07-11 15:51:59126}
127
[email protected]0c9406632013-02-08 01:13:33128Profile* BrowserInstantController::profile() const {
129 return browser_->profile();
130}
131
132void BrowserInstantController::CommitInstant(
[email protected]ddd28ae2013-03-04 21:11:54133 scoped_ptr<content::WebContents> overlay,
[email protected]0c9406632013-02-08 01:13:33134 bool in_new_tab) {
[email protected]ddd28ae2013-03-04 21:11:54135 if (profile()->GetExtensionService()->IsInstalledApp(overlay->GetURL())) {
[email protected]0c9406632013-02-08 01:13:33136 AppLauncherHandler::RecordAppLaunchType(
137 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT);
138 }
[email protected]c72226c82012-10-01 21:02:32139 if (in_new_tab) {
[email protected]ddd28ae2013-03-04 21:11:54140 // TabStripModel takes ownership of |overlay|.
141 browser_->tab_strip_model()->AddWebContents(overlay.release(), -1,
[email protected]e41982a72012-11-20 07:16:51142 instant_.last_transition_type(), TabStripModel::ADD_ACTIVE);
[email protected]c72226c82012-10-01 21:02:32143 } else {
[email protected]0c9406632013-02-08 01:13:33144 ReplaceWebContentsAt(
145 browser_->tab_strip_model()->active_index(),
[email protected]ddd28ae2013-03-04 21:11:54146 overlay.Pass());
[email protected]7acfaf92012-07-11 15:51:59147 }
148}
149
[email protected]0c9406632013-02-08 01:13:33150void BrowserInstantController::ReplaceWebContentsAt(
151 int index,
152 scoped_ptr<content::WebContents> new_contents) {
153 DCHECK_NE(TabStripModel::kNoTab, index);
[email protected]d572bfd2013-02-14 06:14:20154 scoped_ptr<content::WebContents> old_contents(browser_->tab_strip_model()->
155 ReplaceWebContentsAt(index, new_contents.release()));
156 instant_unload_handler_.RunUnloadListenersOrDestroy(old_contents.Pass(),
157 index);
[email protected]0c9406632013-02-08 01:13:33158}
159
[email protected]93b73832012-10-18 20:18:38160void BrowserInstantController::SetInstantSuggestion(
161 const InstantSuggestion& suggestion) {
[email protected]c18cb672012-12-05 04:42:12162 browser_->window()->GetLocationBar()->SetInstantSuggestion(suggestion);
[email protected]7acfaf92012-07-11 15:51:59163}
164
[email protected]727a6c42013-02-27 19:47:26165void BrowserInstantController::CommitSuggestedText(
166 bool skip_inline_autocomplete) {
167 browser_->window()->GetLocationBar()->GetLocationEntry()->model()->
168 CommitSuggestedText(skip_inline_autocomplete);
169}
170
[email protected]7acfaf92012-07-11 15:51:59171gfx::Rect BrowserInstantController::GetInstantBounds() {
172 return browser_->window()->GetInstantBounds();
173}
174
[email protected]ddd28ae2013-03-04 21:11:54175void BrowserInstantController::InstantOverlayFocused() {
[email protected]7acfaf92012-07-11 15:51:59176 // NOTE: This is only invoked on aura.
[email protected]ddd28ae2013-03-04 21:11:54177 browser_->window()->WebContentsFocused(instant_.GetOverlayContents());
[email protected]7acfaf92012-07-11 15:51:59178}
179
[email protected]10aec592013-03-06 20:19:00180void BrowserInstantController::FocusOmnibox(bool caret_visibility) {
[email protected]c18cb672012-12-05 04:42:12181 OmniboxView* omnibox_view = browser_->window()->GetLocationBar()->
182 GetLocationEntry();
183 omnibox_view->SetFocus();
[email protected]10aec592013-03-06 20:19:00184 omnibox_view->model()->SetCaretVisibility(caret_visibility);
[email protected]c18cb672012-12-05 04:42:12185}
186
[email protected]cd533bf2012-12-04 19:14:59187content::WebContents* BrowserInstantController::GetActiveWebContents() const {
188 return browser_->tab_strip_model()->GetActiveWebContents();
[email protected]7acfaf92012-07-11 15:51:59189}
190
[email protected]e41982a72012-11-20 07:16:51191void BrowserInstantController::ActiveTabChanged() {
192 instant_.ActiveTabChanged();
193}
194
[email protected]3d6a8952012-12-14 03:18:07195void BrowserInstantController::TabDeactivated(content::WebContents* contents) {
196 instant_.TabDeactivated(contents);
197}
198
[email protected]3870363e2013-03-06 20:11:23199void BrowserInstantController::UpdateThemeInfo() {
[email protected]e4a379c2013-02-15 19:27:19200 // Update theme background info.
[email protected]3870363e2013-03-06 20:11:23201 // Initialize |theme_info| if necessary.
202 if (!initialized_theme_info_)
[email protected]0c9406632013-02-08 01:13:33203 OnThemeChanged(ThemeServiceFactory::GetForProfile(profile()));
[email protected]a6827652012-11-20 23:41:08204 else
205 OnThemeChanged(NULL);
206}
207
[email protected]3c3acca02013-02-26 03:07:07208void BrowserInstantController::OpenURL(
[email protected]e3033eb2012-12-13 23:46:08209 const GURL& url,
[email protected]3c3acca02013-02-26 03:07:07210 content::PageTransition transition,
211 WindowOpenDisposition disposition) {
[email protected]e3033eb2012-12-13 23:46:08212 browser_->OpenURL(content::OpenURLParams(url,
213 content::Referrer(),
[email protected]3c3acca02013-02-26 03:07:07214 disposition,
[email protected]e3033eb2012-12-13 23:46:08215 transition,
216 false));
217}
218
[email protected]fcde79a2013-02-28 02:25:09219void BrowserInstantController::SetOmniboxBounds(const gfx::Rect& bounds) {
220 instant_.SetOmniboxBounds(bounds);
[email protected]ec4aad542012-12-14 01:11:04221}
222
[email protected]5fac3782013-03-06 09:32:31223void BrowserInstantController::ResetInstant(const std::string& pref_name) {
224 // Update the default value of the kInstantExtendedEnabled pref to match the
225 // value of the kInstantEnabled pref, if necessary.
226 if (pref_name == prefs::kInstantEnabled)
227 chrome::search::SetInstantExtendedPrefDefault(profile());
228
229 bool instant_pref_enabled = chrome::search::IsInstantPrefEnabled(profile());
[email protected]ddd28ae2013-03-04 21:11:54230 bool use_local_overlay_only = profile()->IsOffTheRecord() ||
[email protected]5fac3782013-03-06 09:32:31231 (!instant_pref_enabled &&
[email protected]0c9406632013-02-08 01:13:33232 !profile()->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled));
[email protected]5fac3782013-03-06 09:32:31233 instant_.SetInstantEnabled(instant_pref_enabled, use_local_overlay_only);
[email protected]749ce882012-11-16 04:18:01234}
235
[email protected]7acfaf92012-07-11 15:51:59236////////////////////////////////////////////////////////////////////////////////
[email protected]0b10c9ff2012-10-09 17:31:55237// BrowserInstantController, search::SearchModelObserver implementation:
238
239void BrowserInstantController::ModeChanged(const search::Mode& old_mode,
240 const search::Mode& new_mode) {
[email protected]c19ba1042013-03-11 17:17:13241 if (search::IsInstantExtendedAPIEnabled()) {
242 // Record some actions corresponding to the mode change. Note that to get
243 // the full story, it's necessary to look at other UMA actions as well,
244 // such as tab switches.
245 if (new_mode.is_search_results())
246 content::RecordAction(UserMetricsAction("InstantExtended.ShowSRP"));
247 else if (new_mode.is_ntp())
248 content::RecordAction(UserMetricsAction("InstantExtended.ShowNTP"));
249 }
250
[email protected]ddd28ae2013-03-04 21:11:54251 // If mode is now |NTP|, send theme-related information to Instant.
[email protected]a6827652012-11-20 23:41:08252 if (new_mode.is_ntp())
[email protected]3870363e2013-03-06 20:11:23253 UpdateThemeInfo();
[email protected]a6827652012-11-20 23:41:08254
[email protected]e41982a72012-11-20 07:16:51255 instant_.SearchModeChanged(old_mode, new_mode);
[email protected]7acfaf92012-07-11 15:51:59256}
257
[email protected]a6827652012-11-20 23:41:08258////////////////////////////////////////////////////////////////////////////////
259// BrowserInstantController, content::NotificationObserver implementation:
260
261void BrowserInstantController::Observe(
262 int type,
263 const content::NotificationSource& source,
264 const content::NotificationDetails& details) {
265#if defined(ENABLE_THEMES)
266 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
267 OnThemeChanged(content::Source<ThemeService>(source).ptr());
268#endif // defined(ENABLE_THEMES)
269}
270
271void BrowserInstantController::OnThemeChanged(ThemeService* theme_service) {
272 if (theme_service) { // Get theme information from theme service.
273 theme_info_ = ThemeBackgroundInfo();
274
275 // Set theme background color.
276 SkColor background_color =
[email protected]e119b802013-02-18 18:55:39277 theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
[email protected]a6827652012-11-20 23:41:08278 if (gfx::IsInvertedColorScheme())
279 background_color = color_utils::InvertColor(background_color);
280 theme_info_.color_r = SkColorGetR(background_color);
281 theme_info_.color_g = SkColorGetG(background_color);
282 theme_info_.color_b = SkColorGetB(background_color);
283 theme_info_.color_a = SkColorGetA(background_color);
284
285 if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
286 // Set theme id for theme background image url.
287 theme_info_.theme_id = theme_service->GetThemeID();
288
289 // Set theme background image horizontal alignment.
290 int alignment = 0;
[email protected]e119b802013-02-18 18:55:39291 theme_service->GetDisplayProperty(
292 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &alignment);
293 if (alignment & ThemeProperties::ALIGN_LEFT) {
[email protected]a6827652012-11-20 23:41:08294 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
[email protected]e119b802013-02-18 18:55:39295 } else if (alignment & ThemeProperties::ALIGN_RIGHT) {
[email protected]a6827652012-11-20 23:41:08296 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
297 } else { // ALIGN_CENTER
298 theme_info_.image_horizontal_alignment =
299 THEME_BKGRND_IMAGE_ALIGN_CENTER;
300 }
301
302 // Set theme background image vertical alignment.
[email protected]3870363e2013-03-06 20:11:23303 if (alignment & ThemeProperties::ALIGN_TOP)
[email protected]a6827652012-11-20 23:41:08304 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
[email protected]3870363e2013-03-06 20:11:23305 else if (alignment & ThemeProperties::ALIGN_BOTTOM)
[email protected]a6827652012-11-20 23:41:08306 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
[email protected]3870363e2013-03-06 20:11:23307 else // ALIGN_CENTER
[email protected]a6827652012-11-20 23:41:08308 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
309
310 // Set theme background image tiling.
311 int tiling = 0;
[email protected]e119b802013-02-18 18:55:39312 theme_service->GetDisplayProperty(ThemeProperties::NTP_BACKGROUND_TILING,
[email protected]a6827652012-11-20 23:41:08313 &tiling);
314 switch (tiling) {
[email protected]e119b802013-02-18 18:55:39315 case ThemeProperties::NO_REPEAT:
[email protected]a6827652012-11-20 23:41:08316 theme_info_.image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
317 break;
[email protected]e119b802013-02-18 18:55:39318 case ThemeProperties::REPEAT_X:
[email protected]a6827652012-11-20 23:41:08319 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
320 break;
[email protected]e119b802013-02-18 18:55:39321 case ThemeProperties::REPEAT_Y:
[email protected]a6827652012-11-20 23:41:08322 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
323 break;
[email protected]e119b802013-02-18 18:55:39324 case ThemeProperties::REPEAT:
[email protected]a6827652012-11-20 23:41:08325 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT;
326 break;
327 }
328
329 // Set theme background image height.
330 gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
331 IDR_THEME_NTP_BACKGROUND);
332 DCHECK(image);
333 theme_info_.image_height = image->height();
334 }
335
336 initialized_theme_info_ = true;
337 }
338
339 DCHECK(initialized_theme_info_);
340
[email protected]e4a379c2013-02-15 19:27:19341 if (browser_->search_model()->mode().is_ntp())
[email protected]a6827652012-11-20 23:41:08342 instant_.ThemeChanged(theme_info_);
[email protected]a6827652012-11-20 23:41:08343}
344
[email protected]7acfaf92012-07-11 15:51:59345} // namespace chrome