[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / chrome / browser / search / instant_service.cc
blob986808d7de5da3657b513c6d417a1481030020cd
1 // Copyright 2013 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.
5 #include "chrome/browser/search/instant_service.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/favicon/fallback_icon_service_factory.h"
9 #include "chrome/browser/favicon/large_icon_service_factory.h"
10 #include "chrome/browser/history/top_sites_factory.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/search/instant_io_context.h"
13 #include "chrome/browser/search/instant_service_observer.h"
14 #include "chrome/browser/search/most_visited_iframe_source.h"
15 #include "chrome/browser/search/search.h"
16 #include "chrome/browser/search/suggestions/suggestions_source.h"
17 #include "chrome/browser/search/thumbnail_source.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
20 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
21 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
22 #include "chrome/browser/ui/webui/fallback_icon_source.h"
23 #include "chrome/browser/ui/webui/favicon_source.h"
24 #include "chrome/browser/ui/webui/large_icon_source.h"
25 #include "chrome/browser/ui/webui/theme_source.h"
26 #include "chrome/common/render_messages.h"
27 #include "components/favicon/core/fallback_icon_service.h"
28 #include "components/favicon/core/large_icon_service.h"
29 #include "components/history/core/browser/top_sites.h"
30 #include "components/keyed_service/core/service_access_type.h"
31 #include "components/search_engines/template_url_service.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_types.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/url_data_source.h"
37 #include "grit/theme_resources.h"
38 #include "third_party/skia/include/core/SkColor.h"
39 #include "ui/gfx/color_utils.h"
40 #include "ui/gfx/image/image_skia.h"
41 #include "ui/gfx/sys_color_change_listener.h"
43 #if !defined(OS_ANDROID)
44 #include "chrome/browser/search/local_ntp_source.h"
45 #endif
47 #if defined(ENABLE_THEMES)
48 #include "chrome/browser/themes/theme_properties.h"
49 #include "chrome/browser/themes/theme_service.h"
50 #include "chrome/browser/themes/theme_service_factory.h"
51 #endif // defined(ENABLE_THEMES)
53 InstantService::InstantService(Profile* profile)
54 : profile_(profile),
55 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
56 omnibox_start_margin_(chrome::kDisableStartMargin),
57 weak_ptr_factory_(this) {
58 // The initialization below depends on a typical set of browser threads. Skip
59 // it if we are running in a unit test without the full suite.
60 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI))
61 return;
63 // This depends on the existence of the typical browser threads. Therefore it
64 // is only instantiated here (after the check for a UI thread above).
65 instant_io_context_ = new InstantIOContext();
67 previous_google_base_url_ =
68 GURL(UIThreadSearchTermsData(profile).GoogleBaseURLValue());
70 // TemplateURLService is NULL by default in tests.
71 if (template_url_service_) {
72 template_url_service_->AddObserver(this);
73 const TemplateURL* default_search_provider =
74 template_url_service_->GetDefaultSearchProvider();
75 if (default_search_provider) {
76 previous_default_search_provider_.reset(
77 new TemplateURLData(default_search_provider->data()));
81 ResetInstantSearchPrerenderer();
83 registrar_.Add(this,
84 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
85 content::NotificationService::AllSources());
86 registrar_.Add(this,
87 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
88 content::NotificationService::AllSources());
90 scoped_refptr<history::TopSites> top_sites =
91 TopSitesFactory::GetForProfile(profile_);
92 if (top_sites)
93 top_sites->AddObserver(this);
95 if (profile_ && profile_->GetResourceContext()) {
96 content::BrowserThread::PostTask(
97 content::BrowserThread::IO, FROM_HERE,
98 base::Bind(&InstantIOContext::SetUserDataOnIO,
99 profile->GetResourceContext(), instant_io_context_));
102 // Set up the data sources that Instant uses on the NTP.
103 #if defined(ENABLE_THEMES)
104 // Listen for theme installation.
105 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
106 content::Source<ThemeService>(
107 ThemeServiceFactory::GetForProfile(profile_)));
109 content::URLDataSource::Add(profile_, new ThemeSource(profile_));
110 #endif // defined(ENABLE_THEMES)
112 // TODO(aurimas) remove this #if once instant_service.cc is no longer compiled
113 // on Android.
114 #if !defined(OS_ANDROID)
115 content::URLDataSource::Add(profile_, new LocalNtpSource(profile_));
116 content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, false));
117 content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, true));
118 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
119 #endif // !defined(OS_ANDROID)
121 favicon::FallbackIconService* fallback_icon_service =
122 FallbackIconServiceFactory::GetForBrowserContext(profile_);
123 favicon::LargeIconService* large_icon_service =
124 LargeIconServiceFactory::GetForBrowserContext(profile_);
125 content::URLDataSource::Add(
126 profile_, new FallbackIconSource(fallback_icon_service));
127 content::URLDataSource::Add(
128 profile_, new FaviconSource(profile_, FaviconSource::FAVICON));
129 content::URLDataSource::Add(
130 profile_, new LargeIconSource(fallback_icon_service, large_icon_service));
131 content::URLDataSource::Add(profile_, new MostVisitedIframeSource());
132 content::URLDataSource::Add(
133 profile_, new suggestions::SuggestionsSource(profile_));
136 InstantService::~InstantService() {
137 if (template_url_service_)
138 template_url_service_->RemoveObserver(this);
141 void InstantService::AddInstantProcess(int process_id) {
142 process_ids_.insert(process_id);
144 if (instant_io_context_.get()) {
145 content::BrowserThread::PostTask(
146 content::BrowserThread::IO, FROM_HERE,
147 base::Bind(&InstantIOContext::AddInstantProcessOnIO,
148 instant_io_context_, process_id));
152 bool InstantService::IsInstantProcess(int process_id) const {
153 return process_ids_.find(process_id) != process_ids_.end();
156 void InstantService::AddObserver(InstantServiceObserver* observer) {
157 observers_.AddObserver(observer);
160 void InstantService::RemoveObserver(InstantServiceObserver* observer) {
161 observers_.RemoveObserver(observer);
164 void InstantService::DeleteMostVisitedItem(const GURL& url) {
165 scoped_refptr<history::TopSites> top_sites =
166 TopSitesFactory::GetForProfile(profile_);
167 if (!top_sites)
168 return;
170 top_sites->AddBlacklistedURL(url);
173 void InstantService::UndoMostVisitedDeletion(const GURL& url) {
174 scoped_refptr<history::TopSites> top_sites =
175 TopSitesFactory::GetForProfile(profile_);
176 if (!top_sites)
177 return;
179 top_sites->RemoveBlacklistedURL(url);
182 void InstantService::UndoAllMostVisitedDeletions() {
183 scoped_refptr<history::TopSites> top_sites =
184 TopSitesFactory::GetForProfile(profile_);
185 if (!top_sites)
186 return;
188 top_sites->ClearBlacklistedURLs();
191 void InstantService::UpdateThemeInfo() {
192 #if defined(ENABLE_THEMES)
193 // Update theme background info.
194 // Initialize |theme_info| if necessary.
195 if (!theme_info_)
196 OnThemeChanged(ThemeServiceFactory::GetForProfile(profile_));
197 else
198 OnThemeChanged(NULL);
199 #endif // defined(ENABLE_THEMES)
202 void InstantService::UpdateMostVisitedItemsInfo() {
203 NotifyAboutMostVisitedItems();
206 void InstantService::Shutdown() {
207 process_ids_.clear();
209 if (instant_io_context_.get()) {
210 content::BrowserThread::PostTask(
211 content::BrowserThread::IO, FROM_HERE,
212 base::Bind(&InstantIOContext::ClearInstantProcessesOnIO,
213 instant_io_context_));
216 scoped_refptr<history::TopSites> top_sites =
217 TopSitesFactory::GetForProfile(profile_);
218 if (top_sites)
219 top_sites->RemoveObserver(this);
221 instant_io_context_ = NULL;
224 void InstantService::Observe(int type,
225 const content::NotificationSource& source,
226 const content::NotificationDetails& details) {
227 switch (type) {
228 case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
229 SendSearchURLsToRenderer(
230 content::Source<content::RenderProcessHost>(source).ptr());
231 break;
232 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
233 OnRendererProcessTerminated(
234 content::Source<content::RenderProcessHost>(source)->GetID());
235 break;
236 #if defined(ENABLE_THEMES)
237 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
238 OnThemeChanged(content::Source<ThemeService>(source).ptr());
239 break;
241 #endif // defined(ENABLE_THEMES)
242 default:
243 NOTREACHED() << "Unexpected notification type in InstantService.";
247 void InstantService::SendSearchURLsToRenderer(content::RenderProcessHost* rph) {
248 rph->Send(new ChromeViewMsg_SetSearchURLs(
249 chrome::GetSearchURLs(profile_), chrome::GetNewTabPageURL(profile_)));
252 void InstantService::OnOmniboxStartMarginChanged(int start_margin) {
253 omnibox_start_margin_ = start_margin;
254 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
255 OmniboxStartMarginChanged(omnibox_start_margin_));
258 void InstantService::OnRendererProcessTerminated(int process_id) {
259 process_ids_.erase(process_id);
261 if (instant_io_context_.get()) {
262 content::BrowserThread::PostTask(
263 content::BrowserThread::IO, FROM_HERE,
264 base::Bind(&InstantIOContext::RemoveInstantProcessOnIO,
265 instant_io_context_, process_id));
269 void InstantService::OnMostVisitedItemsReceived(
270 const history::MostVisitedURLList& data) {
271 history::MostVisitedURLList reordered_data(data);
272 std::vector<InstantMostVisitedItem> new_most_visited_items;
273 for (size_t i = 0; i < reordered_data.size(); i++) {
274 const history::MostVisitedURL& url = reordered_data[i];
275 InstantMostVisitedItem item;
276 item.url = url.url;
277 item.title = url.title;
278 new_most_visited_items.push_back(item);
281 most_visited_items_ = new_most_visited_items;
282 NotifyAboutMostVisitedItems();
285 void InstantService::NotifyAboutMostVisitedItems() {
286 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
287 MostVisitedItemsChanged(most_visited_items_));
290 #if defined(ENABLE_THEMES)
292 namespace {
294 const int kSectionBorderAlphaTransparency = 80;
296 // Converts SkColor to RGBAColor
297 RGBAColor SkColorToRGBAColor(const SkColor& sKColor) {
298 RGBAColor color;
299 color.r = SkColorGetR(sKColor);
300 color.g = SkColorGetG(sKColor);
301 color.b = SkColorGetB(sKColor);
302 color.a = SkColorGetA(sKColor);
303 return color;
306 } // namespace
308 void InstantService::OnThemeChanged(ThemeService* theme_service) {
309 if (!theme_service) {
310 DCHECK(theme_info_.get());
311 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
312 ThemeInfoChanged(*theme_info_));
313 return;
316 // Get theme information from theme service.
317 theme_info_.reset(new ThemeBackgroundInfo());
319 // Get if the current theme is the default theme.
320 theme_info_->using_default_theme = theme_service->UsingDefaultTheme();
322 // Get theme colors.
323 SkColor background_color =
324 theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
325 SkColor text_color =
326 theme_service->GetColor(ThemeProperties::COLOR_NTP_TEXT);
327 SkColor link_color =
328 theme_service->GetColor(ThemeProperties::COLOR_NTP_LINK);
329 SkColor text_color_light =
330 theme_service->GetColor(ThemeProperties::COLOR_NTP_TEXT_LIGHT);
331 SkColor header_color =
332 theme_service->GetColor(ThemeProperties::COLOR_NTP_HEADER);
333 // Generate section border color from the header color.
334 SkColor section_border_color =
335 SkColorSetARGB(kSectionBorderAlphaTransparency,
336 SkColorGetR(header_color),
337 SkColorGetG(header_color),
338 SkColorGetB(header_color));
340 // Invert colors if needed.
341 if (gfx::IsInvertedColorScheme()) {
342 background_color = color_utils::InvertColor(background_color);
343 text_color = color_utils::InvertColor(text_color);
344 link_color = color_utils::InvertColor(link_color);
345 text_color_light = color_utils::InvertColor(text_color_light);
346 header_color = color_utils::InvertColor(header_color);
347 section_border_color = color_utils::InvertColor(section_border_color);
350 // Set colors.
351 theme_info_->background_color = SkColorToRGBAColor(background_color);
352 theme_info_->text_color = SkColorToRGBAColor(text_color);
353 theme_info_->link_color = SkColorToRGBAColor(link_color);
354 theme_info_->text_color_light = SkColorToRGBAColor(text_color_light);
355 theme_info_->header_color = SkColorToRGBAColor(header_color);
356 theme_info_->section_border_color = SkColorToRGBAColor(section_border_color);
358 int logo_alternate = theme_service->GetDisplayProperty(
359 ThemeProperties::NTP_LOGO_ALTERNATE);
360 theme_info_->logo_alternate = logo_alternate == 1;
362 if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
363 // Set theme id for theme background image url.
364 theme_info_->theme_id = theme_service->GetThemeID();
366 // Set theme background image horizontal alignment.
367 int alignment = theme_service->GetDisplayProperty(
368 ThemeProperties::NTP_BACKGROUND_ALIGNMENT);
369 if (alignment & ThemeProperties::ALIGN_LEFT)
370 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
371 else if (alignment & ThemeProperties::ALIGN_RIGHT)
372 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
373 else
374 theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
376 // Set theme background image vertical alignment.
377 if (alignment & ThemeProperties::ALIGN_TOP)
378 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
379 else if (alignment & ThemeProperties::ALIGN_BOTTOM)
380 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
381 else
382 theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
384 // Set theme backgorund image tiling.
385 int tiling = theme_service->GetDisplayProperty(
386 ThemeProperties::NTP_BACKGROUND_TILING);
387 switch (tiling) {
388 case ThemeProperties::NO_REPEAT:
389 theme_info_->image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
390 break;
391 case ThemeProperties::REPEAT_X:
392 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
393 break;
394 case ThemeProperties::REPEAT_Y:
395 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
396 break;
397 case ThemeProperties::REPEAT:
398 theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT;
399 break;
402 // Set theme background image height.
403 gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
404 IDR_THEME_NTP_BACKGROUND);
405 DCHECK(image);
406 theme_info_->image_height = image->height();
408 theme_info_->has_attribution =
409 theme_service->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
412 FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
413 ThemeInfoChanged(*theme_info_));
415 #endif // defined(ENABLE_THEMES)
417 void InstantService::OnTemplateURLServiceChanged() {
418 // Check whether the default search provider was changed.
419 const TemplateURL* template_url =
420 template_url_service_->GetDefaultSearchProvider();
421 bool default_search_provider_changed = !TemplateURL::MatchesData(
422 template_url, previous_default_search_provider_.get(),
423 UIThreadSearchTermsData(profile_));
424 if (default_search_provider_changed) {
425 previous_default_search_provider_.reset(
426 template_url ? new TemplateURLData(template_url->data()) : NULL);
429 // Note that, even if the TemplateURL for the Default Search Provider has not
430 // changed, the effective URLs might change if they reference the Google base
431 // URL. The TemplateURLService will notify us when the effective URL changes
432 // in this way but it's up to us to do the work to check both.
433 bool google_base_url_domain_changed = false;
434 GURL google_base_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue());
435 if (google_base_url != previous_google_base_url_) {
436 previous_google_base_url_ = google_base_url;
437 if (template_url && template_url->HasGoogleBaseURLs(
438 UIThreadSearchTermsData(profile_)))
439 google_base_url_domain_changed = true;
442 if (default_search_provider_changed || google_base_url_domain_changed) {
443 ResetInstantSearchPrerenderer();
444 FOR_EACH_OBSERVER(
445 InstantServiceObserver, observers_,
446 DefaultSearchProviderChanged(google_base_url_domain_changed));
450 void InstantService::TopSitesLoaded(history::TopSites* top_sites) {
453 void InstantService::TopSitesChanged(history::TopSites* top_sites) {
454 top_sites->GetMostVisitedURLs(
455 base::Bind(&InstantService::OnMostVisitedItemsReceived,
456 weak_ptr_factory_.GetWeakPtr()),
457 false);
460 void InstantService::ResetInstantSearchPrerenderer() {
461 if (!chrome::ShouldPrefetchSearchResults())
462 return;
464 GURL url(chrome::GetSearchResultPrefetchBaseURL(profile_));
465 instant_prerenderer_.reset(
466 url.is_valid() ? new InstantSearchPrerenderer(profile_, url) : NULL);