blob: 30df1b691786bb9aa128219657bc555356cf5a32 [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]7acfaf92012-07-11 15:51:597#include "chrome/browser/extensions/extension_service.h"
[email protected]fb8fdf12012-08-21 16:28:208#include "chrome/browser/prefs/pref_service.h"
[email protected]7acfaf92012-07-11 15:51:599#include "chrome/browser/profiles/profile.h"
[email protected]a6827652012-11-20 23:41:0810#include "chrome/browser/themes/theme_service.h"
11#include "chrome/browser/themes/theme_service_factory.h"
[email protected]7acfaf92012-07-11 15:51:5912#include "chrome/browser/ui/browser.h"
[email protected]7acfaf92012-07-11 15:51:5913#include "chrome/browser/ui/browser_window.h"
14#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]c18cb672012-12-05 04:42:1215#include "chrome/browser/ui/omnibox/omnibox_view.h"
[email protected]e41982a72012-11-20 07:16:5116#include "chrome/browser/ui/search/search.h"
[email protected]9d3d11702012-11-08 01:01:1217#include "chrome/browser/ui/search/search_tab_helper.h"
[email protected]7acfaf92012-07-11 15:51:5918#include "chrome/browser/ui/tab_contents/tab_contents.h"
[email protected]e41982a72012-11-20 07:16:5119#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]7acfaf92012-07-11 15:51:5920#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
21#include "chrome/common/chrome_notification_types.h"
22#include "chrome/common/pref_names.h"
23#include "content/public/browser/notification_service.h"
[email protected]a6827652012-11-20 23:41:0824#include "grit/theme_resources.h"
25#include "ui/gfx/color_utils.h"
26#include "ui/gfx/sys_color_change_listener.h"
27
[email protected]c2164b22012-12-09 09:14:2228namespace {
29const char* GetInstantPrefName(Profile* profile) {
30 return chrome::search::IsInstantExtendedAPIEnabled(profile) ?
31 prefs::kInstantExtendedEnabled : prefs::kInstantEnabled;
32}
33}
[email protected]7acfaf92012-07-11 15:51:5934
[email protected]7acfaf92012-07-11 15:51:5935namespace chrome {
36
37////////////////////////////////////////////////////////////////////////////////
38// BrowserInstantController, public:
39
40BrowserInstantController::BrowserInstantController(Browser* browser)
[email protected]8a236702012-09-28 13:30:5741 : browser_(browser),
[email protected]e41982a72012-11-20 07:16:5142 instant_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
43 chrome::search::IsInstantExtendedAPIEnabled(browser->profile())),
[email protected]a6827652012-11-20 23:41:0844 instant_unload_handler_(browser),
45 initialized_theme_info_(false),
46 theme_area_height_(0) {
[email protected]7acfaf92012-07-11 15:51:5947 profile_pref_registrar_.Init(browser_->profile()->GetPrefs());
[email protected]0b3fa502012-11-21 13:57:4648 profile_pref_registrar_.Add(
[email protected]c2164b22012-12-09 09:14:2249 GetInstantPrefName(browser_->profile()),
[email protected]0b3fa502012-11-21 13:57:4650 base::Bind(&BrowserInstantController::ResetInstant,
51 base::Unretained(this)));
52 ResetInstant();
[email protected]0b10c9ff2012-10-09 17:31:5553 browser_->search_model()->AddObserver(this);
[email protected]a6827652012-11-20 23:41:0854
55#if defined(ENABLE_THEMES)
56 // Listen for theme installation.
57 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
58 content::Source<ThemeService>(
59 ThemeServiceFactory::GetForProfile(browser_->profile())));
60#endif // defined(ENABLE_THEMES)
[email protected]7acfaf92012-07-11 15:51:5961}
62
63BrowserInstantController::~BrowserInstantController() {
[email protected]0b10c9ff2012-10-09 17:31:5564 browser_->search_model()->RemoveObserver(this);
[email protected]7acfaf92012-07-11 15:51:5965}
66
[email protected]e41982a72012-11-20 07:16:5167bool BrowserInstantController::IsInstantEnabled(Profile* profile) {
68 return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
[email protected]c2164b22012-12-09 09:14:2269 profile->GetPrefs()->GetBoolean(GetInstantPrefName(profile));
[email protected]e41982a72012-11-20 07:16:5170}
71
72void BrowserInstantController::RegisterUserPrefs(PrefService* prefs) {
73 prefs->RegisterBooleanPref(prefs::kInstantConfirmDialogShown, false,
74 PrefService::SYNCABLE_PREF);
[email protected]c2164b22012-12-09 09:14:2275 prefs->RegisterBooleanPref(prefs::kInstantExtendedEnabled, true,
76 PrefService::SYNCABLE_PREF);
[email protected]e41982a72012-11-20 07:16:5177 prefs->RegisterBooleanPref(prefs::kInstantEnabled, false,
78 PrefService::SYNCABLE_PREF);
79}
80
[email protected]7acfaf92012-07-11 15:51:5981bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition) {
[email protected]e41982a72012-11-20 07:16:5182 // Unsupported dispositions.
83 if (disposition == NEW_BACKGROUND_TAB || disposition == NEW_WINDOW)
[email protected]7acfaf92012-07-11 15:51:5984 return false;
[email protected]7acfaf92012-07-11 15:51:5985
[email protected]7acfaf92012-07-11 15:51:5986 // The omnibox currently doesn't use other dispositions, so we don't attempt
[email protected]c72226c82012-10-01 21:02:3287 // to handle them. If you hit this DCHECK file a bug and I'll (sky) add
[email protected]7acfaf92012-07-11 15:51:5988 // support for the new disposition.
[email protected]c72226c82012-10-01 21:02:3289 DCHECK(disposition == CURRENT_TAB ||
90 disposition == NEW_FOREGROUND_TAB) << disposition;
91
[email protected]221e9202012-12-08 00:59:0992 return instant_.CommitIfPossible(disposition == CURRENT_TAB ?
[email protected]c72226c82012-10-01 21:02:3293 INSTANT_COMMIT_PRESSED_ENTER : INSTANT_COMMIT_PRESSED_ALT_ENTER);
[email protected]7acfaf92012-07-11 15:51:5994}
95
[email protected]cd533bf2012-12-04 19:14:5996void BrowserInstantController::CommitInstant(content::WebContents* preview,
[email protected]c72226c82012-10-01 21:02:3297 bool in_new_tab) {
98 if (in_new_tab) {
99 // TabStripModel takes ownership of |preview|.
[email protected]cd533bf2012-12-04 19:14:59100 browser_->tab_strip_model()->AddWebContents(preview, -1,
[email protected]e41982a72012-11-20 07:16:51101 instant_.last_transition_type(), TabStripModel::ADD_ACTIVE);
[email protected]c72226c82012-10-01 21:02:32102 } else {
[email protected]59fa29fb2012-12-07 22:13:42103 int index = browser_->tab_strip_model()->active_index();
[email protected]c72226c82012-10-01 21:02:32104 DCHECK_NE(TabStripModel::kNoTab, index);
[email protected]59fa29fb2012-12-07 22:13:42105 content::WebContents* active_tab =
106 browser_->tab_strip_model()->GetWebContentsAt(index);
[email protected]c72226c82012-10-01 21:02:32107 // TabStripModel takes ownership of |preview|.
[email protected]59fa29fb2012-12-07 22:13:42108 browser_->tab_strip_model()->ReplaceWebContentsAt(index, preview);
[email protected]c72226c82012-10-01 21:02:32109 // InstantUnloadHandler takes ownership of |active_tab|.
110 instant_unload_handler_.RunUnloadListenersOrDestroy(active_tab, index);
[email protected]7acfaf92012-07-11 15:51:59111
[email protected]cd533bf2012-12-04 19:14:59112 GURL url = preview->GetURL();
[email protected]c72226c82012-10-01 21:02:32113 DCHECK(browser_->profile()->GetExtensionService());
114 if (browser_->profile()->GetExtensionService()->IsInstalledApp(url)) {
115 AppLauncherHandler::RecordAppLaunchType(
116 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT);
117 }
[email protected]7acfaf92012-07-11 15:51:59118 }
119}
120
[email protected]93b73832012-10-18 20:18:38121void BrowserInstantController::SetInstantSuggestion(
122 const InstantSuggestion& suggestion) {
[email protected]c18cb672012-12-05 04:42:12123 browser_->window()->GetLocationBar()->SetInstantSuggestion(suggestion);
[email protected]7acfaf92012-07-11 15:51:59124}
125
126gfx::Rect BrowserInstantController::GetInstantBounds() {
127 return browser_->window()->GetInstantBounds();
128}
129
130void BrowserInstantController::InstantPreviewFocused() {
131 // NOTE: This is only invoked on aura.
[email protected]cd533bf2012-12-04 19:14:59132 browser_->window()->WebContentsFocused(instant_.GetPreviewContents());
[email protected]7acfaf92012-07-11 15:51:59133}
134
[email protected]c18cb672012-12-05 04:42:12135void BrowserInstantController::FocusOmniboxInvisibly() {
136 OmniboxView* omnibox_view = browser_->window()->GetLocationBar()->
137 GetLocationEntry();
138 omnibox_view->SetFocus();
139 omnibox_view->model()->SetCaretVisibility(false);
140}
141
[email protected]cd533bf2012-12-04 19:14:59142content::WebContents* BrowserInstantController::GetActiveWebContents() const {
143 return browser_->tab_strip_model()->GetActiveWebContents();
[email protected]7acfaf92012-07-11 15:51:59144}
145
[email protected]e41982a72012-11-20 07:16:51146void BrowserInstantController::ActiveTabChanged() {
147 instant_.ActiveTabChanged();
148}
149
[email protected]3d6a8952012-12-14 03:18:07150void BrowserInstantController::TabDeactivated(content::WebContents* contents) {
151 instant_.TabDeactivated(contents);
152}
153
[email protected]a6827652012-11-20 23:41:08154void BrowserInstantController::SetContentHeight(int height) {
155 OnThemeAreaHeightChanged(height);
156}
157
158void BrowserInstantController::UpdateThemeInfoForPreview() {
159 // Update theme background info and theme area height.
160 // Initialize |theme_info| if necessary.
161 // |OnThemeChanged| also updates theme area height if necessary.
162 if (!initialized_theme_info_)
163 OnThemeChanged(ThemeServiceFactory::GetForProfile(browser_->profile()));
164 else
165 OnThemeChanged(NULL);
166}
167
[email protected]e3033eb2012-12-13 23:46:08168void BrowserInstantController::OpenURLInCurrentTab(
169 const GURL& url,
170 content::PageTransition transition) {
171 browser_->OpenURL(content::OpenURLParams(url,
172 content::Referrer(),
173 CURRENT_TAB,
174 transition,
175 false));
176}
177
[email protected]ec4aad542012-12-14 01:11:04178void BrowserInstantController::SetMarginSize(int start, int end) {
179 instant_.SetMarginSize(start, end);
180}
181
[email protected]0b3fa502012-11-21 13:57:46182void BrowserInstantController::ResetInstant() {
[email protected]e41982a72012-11-20 07:16:51183 instant_.SetInstantEnabled(IsInstantEnabled(browser_->profile()));
[email protected]749ce882012-11-16 04:18:01184}
185
[email protected]7acfaf92012-07-11 15:51:59186////////////////////////////////////////////////////////////////////////////////
[email protected]0b10c9ff2012-10-09 17:31:55187// BrowserInstantController, search::SearchModelObserver implementation:
188
189void BrowserInstantController::ModeChanged(const search::Mode& old_mode,
190 const search::Mode& new_mode) {
[email protected]a6827652012-11-20 23:41:08191 // If mode is now |NTP|, send theme-related information to instant.
192 if (new_mode.is_ntp())
193 UpdateThemeInfoForPreview();
194
[email protected]e41982a72012-11-20 07:16:51195 instant_.SearchModeChanged(old_mode, new_mode);
[email protected]7acfaf92012-07-11 15:51:59196}
197
[email protected]a6827652012-11-20 23:41:08198////////////////////////////////////////////////////////////////////////////////
199// BrowserInstantController, content::NotificationObserver implementation:
200
201void BrowserInstantController::Observe(
202 int type,
203 const content::NotificationSource& source,
204 const content::NotificationDetails& details) {
205#if defined(ENABLE_THEMES)
206 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
207 OnThemeChanged(content::Source<ThemeService>(source).ptr());
208#endif // defined(ENABLE_THEMES)
209}
210
211void BrowserInstantController::OnThemeChanged(ThemeService* theme_service) {
212 if (theme_service) { // Get theme information from theme service.
213 theme_info_ = ThemeBackgroundInfo();
214
215 // Set theme background color.
216 SkColor background_color =
217 theme_service->GetColor(ThemeService::COLOR_NTP_BACKGROUND);
218 if (gfx::IsInvertedColorScheme())
219 background_color = color_utils::InvertColor(background_color);
220 theme_info_.color_r = SkColorGetR(background_color);
221 theme_info_.color_g = SkColorGetG(background_color);
222 theme_info_.color_b = SkColorGetB(background_color);
223 theme_info_.color_a = SkColorGetA(background_color);
224
225 if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
226 // Set theme id for theme background image url.
227 theme_info_.theme_id = theme_service->GetThemeID();
228
229 // Set theme background image horizontal alignment.
230 int alignment = 0;
231 theme_service->GetDisplayProperty(ThemeService::NTP_BACKGROUND_ALIGNMENT,
232 &alignment);
233 if (alignment & ThemeService::ALIGN_LEFT) {
234 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
235 } else if (alignment & ThemeService::ALIGN_RIGHT) {
236 theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
237 } else { // ALIGN_CENTER
238 theme_info_.image_horizontal_alignment =
239 THEME_BKGRND_IMAGE_ALIGN_CENTER;
240 }
241
242 // Set theme background image vertical alignment.
243 if (alignment & ThemeService::ALIGN_TOP)
244 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
245 else if (alignment & ThemeService::ALIGN_BOTTOM)
246 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
247 else // ALIGN_CENTER
248 theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
249
250 // Set theme background image tiling.
251 int tiling = 0;
252 theme_service->GetDisplayProperty(ThemeService::NTP_BACKGROUND_TILING,
253 &tiling);
254 switch (tiling) {
255 case ThemeService::NO_REPEAT:
256 theme_info_.image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
257 break;
258 case ThemeService::REPEAT_X:
259 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
260 break;
261 case ThemeService::REPEAT_Y:
262 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
263 break;
264 case ThemeService::REPEAT:
265 theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT;
266 break;
267 }
268
269 // Set theme background image height.
270 gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
271 IDR_THEME_NTP_BACKGROUND);
272 DCHECK(image);
273 theme_info_.image_height = image->height();
274 }
275
276 initialized_theme_info_ = true;
277 }
278
279 DCHECK(initialized_theme_info_);
280
281 if (browser_->search_model()->mode().is_ntp()) {
282 instant_.ThemeChanged(theme_info_);
283
284 // Theme area height is only sent to preview for non-top-aligned images;
285 // new theme may have a different alignment that requires preview to know
286 // theme area height.
287 OnThemeAreaHeightChanged(theme_area_height_);
288 }
289}
290
291void BrowserInstantController::OnThemeAreaHeightChanged(int height) {
292 theme_area_height_ = height;
293
294 // Notify preview only if mode is |NTP| and theme background image is not top-
295 // aligned; top-aligned images don't need theme area height to determine which
296 // part of the image overlay should draw, 'cos the origin is top-left.
297 if (!browser_->search_model()->mode().is_ntp() ||
298 theme_info_.theme_id.empty() ||
299 theme_info_.image_vertical_alignment == THEME_BKGRND_IMAGE_ALIGN_TOP) {
300 return;
301 }
302 instant_.ThemeAreaHeightChanged(theme_area_height_);
303}
304
[email protected]7acfaf92012-07-11 15:51:59305} // namespace chrome