1 // Copyright (c) 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.
5 #include "chrome/browser/notifications/desktop_notification_service.h"
7 #include "base/metrics/histogram.h"
8 #include "base/prefs/scoped_user_pref_update.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/threading/thread.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/content_settings/content_settings_details.h"
14 #include "chrome/browser/content_settings/content_settings_provider.h"
15 #include "chrome/browser/content_settings/host_content_settings_map.h"
16 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
19 #include "chrome/browser/infobars/infobar.h"
20 #include "chrome/browser/infobars/infobar_service.h"
21 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
22 #include "chrome/browser/notifications/notification.h"
23 #include "chrome/browser/notifications/notification_object_proxy.h"
24 #include "chrome/browser/notifications/notification_ui_manager.h"
25 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
26 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
30 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
31 #include "chrome/common/content_settings.h"
32 #include "chrome/common/content_settings_pattern.h"
33 #include "chrome/common/pref_names.h"
34 #include "chrome/common/url_constants.h"
35 #include "components/user_prefs/pref_registry_syncable.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/common/show_desktop_notification_params.h"
41 #include "extensions/browser/event_router.h"
42 #include "extensions/browser/extension_system.h"
43 #include "extensions/browser/info_map.h"
44 #include "extensions/common/constants.h"
45 #include "extensions/common/extension.h"
46 #include "extensions/common/extension_set.h"
47 #include "grit/browser_resources.h"
48 #include "grit/chromium_strings.h"
49 #include "grit/generated_resources.h"
50 #include "grit/theme_resources.h"
51 #include "net/base/escape.h"
52 #include "ui/base/l10n/l10n_util.h"
53 #include "ui/base/resource/resource_bundle.h"
54 #include "ui/base/webui/web_ui_util.h"
55 #include "ui/message_center/message_center_util.h"
56 #include "ui/message_center/notifier_settings.h"
58 using content::BrowserThread;
59 using content::RenderViewHost;
60 using content::WebContents;
61 using message_center::NotifierId;
62 using blink::WebTextDirection;
64 const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
66 // NotificationPermissionRequest ---------------------------------------
68 class NotificationPermissionRequest : public PermissionBubbleRequest {
70 NotificationPermissionRequest(
71 DesktopNotificationService* notification_service,
73 base::string16 display_name,
76 int callback_context);
77 virtual ~NotificationPermissionRequest();
79 // PermissionBubbleDelegate:
80 virtual base::string16 GetMessageText() const OVERRIDE;
81 virtual base::string16 GetMessageTextFragment() const OVERRIDE;
82 virtual base::string16 GetAlternateAcceptButtonText() const OVERRIDE;
83 virtual base::string16 GetAlternateDenyButtonText() const OVERRIDE;
84 virtual void PermissionGranted() OVERRIDE;
85 virtual void PermissionDenied() OVERRIDE;
86 virtual void Cancelled() OVERRIDE;
87 virtual void RequestFinished() OVERRIDE;
90 // The notification service to be used.
91 DesktopNotificationService* notification_service_;
93 // The origin we are asking for permissions on.
96 // The display name for the origin to be displayed. Will be different from
97 // origin_ for extensions.
98 base::string16 display_name_;
100 // The callback information that tells us how to respond to javascript via
101 // the correct RenderView.
104 int callback_context_;
106 // Whether the user clicked one of the buttons.
109 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionRequest);
112 NotificationPermissionRequest::NotificationPermissionRequest(
113 DesktopNotificationService* notification_service,
115 base::string16 display_name,
118 int callback_context)
119 : notification_service_(notification_service),
121 display_name_(display_name),
122 process_id_(process_id),
124 callback_context_(callback_context),
125 action_taken_(false) {}
127 NotificationPermissionRequest::~NotificationPermissionRequest() {}
129 base::string16 NotificationPermissionRequest::GetMessageText() const {
130 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
135 NotificationPermissionRequest::GetMessageTextFragment() const {
136 return l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSIONS_FRAGMENT);
140 NotificationPermissionRequest::GetAlternateAcceptButtonText() const {
141 return l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSION_YES);
145 NotificationPermissionRequest::GetAlternateDenyButtonText() const {
146 return l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSION_NO);
149 void NotificationPermissionRequest::PermissionGranted() {
150 action_taken_ = true;
151 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
152 notification_service_->GrantPermission(origin_);
155 void NotificationPermissionRequest::PermissionDenied() {
156 action_taken_ = true;
157 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
158 notification_service_->DenyPermission(origin_);
161 void NotificationPermissionRequest::Cancelled() {
164 void NotificationPermissionRequest::RequestFinished() {
166 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
168 RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
170 host->DesktopNotificationPermissionRequestDone(callback_context_);
176 // NotificationPermissionInfoBarDelegate --------------------------------------
178 // The delegate for the infobar shown when an origin requests notification
180 class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
182 // Creates a notification permission infobar and delegate and adds the infobar
183 // to |infobar_service|.
184 static void Create(InfoBarService* infobar_service,
185 DesktopNotificationService* notification_service,
187 const base::string16& display_name,
190 int callback_context);
193 NotificationPermissionInfoBarDelegate(
194 DesktopNotificationService* notification_service,
196 const base::string16& display_name,
199 int callback_context);
200 virtual ~NotificationPermissionInfoBarDelegate();
202 // ConfirmInfoBarDelegate:
203 virtual int GetIconID() const OVERRIDE;
204 virtual Type GetInfoBarType() const OVERRIDE;
205 virtual base::string16 GetMessageText() const OVERRIDE;
206 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
207 virtual bool Accept() OVERRIDE;
208 virtual bool Cancel() OVERRIDE;
210 // The origin we are asking for permissions on.
213 // The display name for the origin to be displayed. Will be different from
214 // origin_ for extensions.
215 base::string16 display_name_;
217 // The notification service to be used.
218 DesktopNotificationService* notification_service_;
220 // The callback information that tells us how to respond to javascript via
221 // the correct RenderView.
224 int callback_context_;
226 // Whether the user clicked one of the buttons.
229 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
233 void NotificationPermissionInfoBarDelegate::Create(
234 InfoBarService* infobar_service,
235 DesktopNotificationService* notification_service,
237 const base::string16& display_name,
240 int callback_context) {
241 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
242 scoped_ptr<ConfirmInfoBarDelegate>(
243 new NotificationPermissionInfoBarDelegate(
244 notification_service, origin, display_name, process_id, route_id,
245 callback_context))));
248 NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate(
249 DesktopNotificationService* notification_service,
251 const base::string16& display_name,
254 int callback_context)
255 : ConfirmInfoBarDelegate(),
257 display_name_(display_name),
258 notification_service_(notification_service),
259 process_id_(process_id),
261 callback_context_(callback_context),
262 action_taken_(false) {
265 NotificationPermissionInfoBarDelegate::
266 ~NotificationPermissionInfoBarDelegate() {
268 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
270 RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
272 host->DesktopNotificationPermissionRequestDone(callback_context_);
275 int NotificationPermissionInfoBarDelegate::GetIconID() const {
276 return IDR_INFOBAR_DESKTOP_NOTIFICATIONS;
279 InfoBarDelegate::Type
280 NotificationPermissionInfoBarDelegate::GetInfoBarType() const {
281 return PAGE_ACTION_TYPE;
284 base::string16 NotificationPermissionInfoBarDelegate::GetMessageText() const {
285 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
289 base::string16 NotificationPermissionInfoBarDelegate::GetButtonLabel(
290 InfoBarButton button) const {
291 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
292 IDS_NOTIFICATION_PERMISSION_YES : IDS_NOTIFICATION_PERMISSION_NO);
295 bool NotificationPermissionInfoBarDelegate::Accept() {
296 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
297 notification_service_->GrantPermission(origin_);
298 action_taken_ = true;
302 bool NotificationPermissionInfoBarDelegate::Cancel() {
303 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
304 notification_service_->DenyPermission(origin_);
305 action_taken_ = true;
310 // DesktopNotificationService -------------------------------------------------
313 void DesktopNotificationService::RegisterProfilePrefs(
314 user_prefs::PrefRegistrySyncable* registry) {
315 registry->RegisterListPref(
316 prefs::kMessageCenterDisabledExtensionIds,
317 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
318 registry->RegisterListPref(
319 prefs::kMessageCenterDisabledSystemComponentIds,
320 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
321 registry->RegisterListPref(
322 prefs::kMessageCenterEnabledSyncNotifierIds,
323 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
324 ExtensionWelcomeNotification::RegisterProfilePrefs(registry);
328 base::string16 DesktopNotificationService::CreateDataUrl(
329 const GURL& icon_url,
330 const base::string16& title,
331 const base::string16& body,
332 WebTextDirection dir) {
334 std::vector<std::string> subst;
335 if (icon_url.is_valid()) {
336 resource = IDR_NOTIFICATION_ICON_HTML;
337 subst.push_back(icon_url.spec());
338 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title)));
339 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body)));
340 // icon float position
341 subst.push_back(dir == blink::WebTextDirectionRightToLeft ?
343 } else if (title.empty() || body.empty()) {
344 resource = IDR_NOTIFICATION_1LINE_HTML;
345 base::string16 line = title.empty() ? body : title;
346 // Strings are div names in the template file.
347 base::string16 line_name =
348 title.empty() ? base::ASCIIToUTF16("description")
349 : base::ASCIIToUTF16("title");
350 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line_name)));
351 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line)));
353 resource = IDR_NOTIFICATION_2LINE_HTML;
354 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title)));
355 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body)));
357 // body text direction
358 subst.push_back(dir == blink::WebTextDirectionRightToLeft ?
361 return CreateDataUrl(resource, subst);
365 base::string16 DesktopNotificationService::CreateDataUrl(
366 int resource, const std::vector<std::string>& subst) {
367 const base::StringPiece template_html(
368 ResourceBundle::GetSharedInstance().GetRawDataResource(
371 if (template_html.empty()) {
372 NOTREACHED() << "unable to load template. ID: " << resource;
373 return base::string16();
376 std::string data = ReplaceStringPlaceholders(template_html, subst, NULL);
377 return base::UTF8ToUTF16("data:text/html;charset=utf-8," +
378 net::EscapeQueryParamValue(data, false));
382 std::string DesktopNotificationService::AddNotification(
383 const GURL& origin_url,
384 const base::string16& title,
385 const base::string16& message,
386 const GURL& icon_url,
387 const base::string16& replace_id,
388 NotificationDelegate* delegate,
390 if (message_center::IsRichNotificationEnabled()) {
391 // For message center create a non-HTML notification with |icon_url|.
392 Notification notification(origin_url, icon_url, title, message,
393 blink::WebTextDirectionDefault,
394 base::string16(), replace_id, delegate);
395 g_browser_process->notification_ui_manager()->Add(notification, profile);
396 return notification.notification_id();
399 // Generate a data URL embedding the icon URL, title, and message.
400 GURL content_url(CreateDataUrl(
401 icon_url, title, message, blink::WebTextDirectionDefault));
402 Notification notification(
403 GURL(), content_url, base::string16(), replace_id, delegate);
404 g_browser_process->notification_ui_manager()->Add(notification, profile);
405 return notification.notification_id();
409 std::string DesktopNotificationService::AddIconNotification(
410 const GURL& origin_url,
411 const base::string16& title,
412 const base::string16& message,
413 const gfx::Image& icon,
414 const base::string16& replace_id,
415 NotificationDelegate* delegate,
417 if (message_center::IsRichNotificationEnabled()) {
418 // For message center create a non-HTML notification with |icon|.
419 Notification notification(origin_url, icon, title, message,
420 blink::WebTextDirectionDefault,
421 base::string16(), replace_id, delegate);
422 g_browser_process->notification_ui_manager()->Add(notification, profile);
423 return notification.notification_id();
428 icon_url = GURL(webui::GetBitmapDataUrl(*icon.ToSkBitmap()));
429 return AddNotification(
430 origin_url, title, message, icon_url, replace_id, delegate, profile);
434 void DesktopNotificationService::RemoveNotification(
435 const std::string& notification_id) {
436 g_browser_process->notification_ui_manager()->CancelById(notification_id);
439 DesktopNotificationService::DesktopNotificationService(
441 NotificationUIManager* ui_manager)
443 ui_manager_(ui_manager) {
444 OnStringListPrefChanged(
445 prefs::kMessageCenterDisabledExtensionIds, &disabled_extension_ids_);
446 OnStringListPrefChanged(
447 prefs::kMessageCenterDisabledSystemComponentIds,
448 &disabled_system_component_ids_);
449 OnStringListPrefChanged(
450 prefs::kMessageCenterEnabledSyncNotifierIds, &enabled_sync_notifier_ids_);
451 disabled_extension_id_pref_.Init(
452 prefs::kMessageCenterDisabledExtensionIds,
453 profile_->GetPrefs(),
455 &DesktopNotificationService::OnStringListPrefChanged,
456 base::Unretained(this),
457 base::Unretained(prefs::kMessageCenterDisabledExtensionIds),
458 base::Unretained(&disabled_extension_ids_)));
459 disabled_system_component_id_pref_.Init(
460 prefs::kMessageCenterDisabledSystemComponentIds,
461 profile_->GetPrefs(),
463 &DesktopNotificationService::OnStringListPrefChanged,
464 base::Unretained(this),
465 base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds),
466 base::Unretained(&disabled_system_component_ids_)));
467 enabled_sync_notifier_id_pref_.Init(
468 prefs::kMessageCenterEnabledSyncNotifierIds,
469 profile_->GetPrefs(),
471 &DesktopNotificationService::OnStringListPrefChanged,
472 base::Unretained(this),
473 base::Unretained(prefs::kMessageCenterEnabledSyncNotifierIds),
474 base::Unretained(&enabled_sync_notifier_ids_)));
475 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
476 content::Source<Profile>(profile_));
479 DesktopNotificationService::~DesktopNotificationService() {
482 void DesktopNotificationService::GrantPermission(const GURL& origin) {
483 ContentSettingsPattern primary_pattern =
484 ContentSettingsPattern::FromURLNoWildcard(origin);
485 profile_->GetHostContentSettingsMap()->SetContentSetting(
487 ContentSettingsPattern::Wildcard(),
488 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
489 NO_RESOURCE_IDENTIFIER,
490 CONTENT_SETTING_ALLOW);
493 void DesktopNotificationService::DenyPermission(const GURL& origin) {
494 ContentSettingsPattern primary_pattern =
495 ContentSettingsPattern::FromURLNoWildcard(origin);
496 profile_->GetHostContentSettingsMap()->SetContentSetting(
498 ContentSettingsPattern::Wildcard(),
499 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
500 NO_RESOURCE_IDENTIFIER,
501 CONTENT_SETTING_BLOCK);
504 ContentSetting DesktopNotificationService::GetDefaultContentSetting(
505 std::string* provider_id) {
506 return profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
507 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, provider_id);
510 void DesktopNotificationService::SetDefaultContentSetting(
511 ContentSetting setting) {
512 profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
513 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
516 void DesktopNotificationService::ResetToDefaultContentSetting() {
517 profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
518 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_DEFAULT);
521 void DesktopNotificationService::GetNotificationsSettings(
522 ContentSettingsForOneType* settings) {
523 profile_->GetHostContentSettingsMap()->GetSettingsForOneType(
524 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
525 NO_RESOURCE_IDENTIFIER,
529 void DesktopNotificationService::ClearSetting(
530 const ContentSettingsPattern& pattern) {
531 profile_->GetHostContentSettingsMap()->SetContentSetting(
533 ContentSettingsPattern::Wildcard(),
534 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
535 NO_RESOURCE_IDENTIFIER,
536 CONTENT_SETTING_DEFAULT);
539 void DesktopNotificationService::ResetAllOrigins() {
540 profile_->GetHostContentSettingsMap()->ClearSettingsForOneType(
541 CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
544 ContentSetting DesktopNotificationService::GetContentSetting(
545 const GURL& origin) {
546 return profile_->GetHostContentSettingsMap()->GetContentSetting(
549 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
550 NO_RESOURCE_IDENTIFIER);
553 void DesktopNotificationService::RequestPermission(
554 const GURL& origin, int process_id, int route_id, int callback_context,
555 WebContents* contents) {
556 // If |origin| hasn't been seen before and the default content setting for
557 // notifications is "ask", show an infobar.
558 // The cache can only answer queries on the IO thread once it's initialized,
559 // so don't ask the cache.
560 ContentSetting setting = GetContentSetting(origin);
561 if (setting == CONTENT_SETTING_ASK) {
562 if (PermissionBubbleManager::Enabled()) {
563 PermissionBubbleManager* bubble_manager =
564 PermissionBubbleManager::FromWebContents(contents);
565 bubble_manager->AddRequest(new NotificationPermissionRequest(this,
566 origin, DisplayNameForOriginInProcessId(origin, process_id),
567 process_id, route_id, callback_context));
571 // Show an info bar requesting permission.
572 InfoBarService* infobar_service =
573 InfoBarService::FromWebContents(contents);
574 // |infobar_service| may be NULL, e.g., if this request originated in a
575 // browser action popup, extension background page, or any HTML that runs
577 if (infobar_service) {
578 NotificationPermissionInfoBarDelegate::Create(
579 infobar_service, this,
580 origin, DisplayNameForOriginInProcessId(origin, process_id),
581 process_id, route_id, callback_context);
586 // Notify renderer immediately.
587 RenderViewHost* host = RenderViewHost::FromID(process_id, route_id);
589 host->DesktopNotificationPermissionRequestDone(callback_context);
593 void DesktopNotificationService::ShowNotification(
594 const Notification& notification) {
595 GetUIManager()->Add(notification, profile_);
598 bool DesktopNotificationService::CancelDesktopNotification(
599 int process_id, int route_id, int notification_id) {
600 scoped_refptr<NotificationObjectProxy> proxy(
601 new NotificationObjectProxy(process_id, route_id, notification_id,
603 return GetUIManager()->CancelById(proxy->id());
607 bool DesktopNotificationService::ShowDesktopNotification(
608 const content::ShowDesktopNotificationHostMsgParams& params,
609 int process_id, int route_id, DesktopNotificationSource source) {
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
611 const GURL& origin = params.origin;
612 NotificationObjectProxy* proxy =
613 new NotificationObjectProxy(process_id, route_id,
614 params.notification_id,
615 source == WorkerNotification);
617 base::string16 display_source =
618 DisplayNameForOriginInProcessId(origin, process_id);
619 Notification notification(origin, params.icon_url, params.title,
620 params.body, params.direction, display_source, params.replace_id,
623 // The webkit notification doesn't timeout.
624 notification.set_never_timeout(true);
626 ShowNotification(notification);
630 base::string16 DesktopNotificationService::DisplayNameForOriginInProcessId(
631 const GURL& origin, int process_id) {
632 // If the source is an extension, lookup the display name.
633 // Message center prefers to use extension name if the notification
634 // is allowed by an extension.
635 if (NotificationUIManager::DelegatesToMessageCenter() ||
636 origin.SchemeIs(extensions::kExtensionScheme)) {
637 extensions::InfoMap* extension_info_map =
638 extensions::ExtensionSystem::Get(profile_)->info_map();
639 if (extension_info_map) {
640 extensions::ExtensionSet extensions;
641 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
642 origin, process_id, extensions::APIPermission::kNotification,
644 for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
645 iter != extensions.end(); ++iter) {
646 NotifierId notifier_id(NotifierId::APPLICATION, (*iter)->id());
647 if (IsNotifierEnabled(notifier_id))
648 return base::UTF8ToUTF16((*iter)->name());
652 return base::UTF8ToUTF16(origin.host());
655 void DesktopNotificationService::NotifySettingsChange() {
656 content::NotificationService::current()->Notify(
657 chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
658 content::Source<DesktopNotificationService>(this),
659 content::NotificationService::NoDetails());
662 NotificationUIManager* DesktopNotificationService::GetUIManager() {
663 // We defer setting ui_manager_ to the global singleton until we need it
664 // in order to avoid UI dependent construction during startup.
666 ui_manager_ = g_browser_process->notification_ui_manager();
670 bool DesktopNotificationService::IsNotifierEnabled(
671 const NotifierId& notifier_id) {
672 switch (notifier_id.type) {
673 case NotifierId::APPLICATION:
674 return disabled_extension_ids_.find(notifier_id.id) ==
675 disabled_extension_ids_.end();
676 case NotifierId::WEB_PAGE:
677 return GetContentSetting(notifier_id.url) == CONTENT_SETTING_ALLOW;
678 case NotifierId::SYSTEM_COMPONENT:
679 #if defined(OS_CHROMEOS)
680 return disabled_system_component_ids_.find(notifier_id.id) ==
681 disabled_system_component_ids_.end();
683 // We do not disable system component notifications.
686 case NotifierId::SYNCED_NOTIFICATION_SERVICE:
687 return enabled_sync_notifier_ids_.find(notifier_id.id) !=
688 enabled_sync_notifier_ids_.end();
695 void DesktopNotificationService::SetNotifierEnabled(
696 const NotifierId& notifier_id,
698 DCHECK_NE(NotifierId::WEB_PAGE, notifier_id.type);
700 bool add_new_item = false;
701 const char* pref_name = NULL;
702 scoped_ptr<base::StringValue> id;
703 switch (notifier_id.type) {
704 case NotifierId::APPLICATION:
705 pref_name = prefs::kMessageCenterDisabledExtensionIds;
706 add_new_item = !enabled;
707 id.reset(new base::StringValue(notifier_id.id));
708 FirePermissionLevelChangedEvent(notifier_id, enabled);
710 case NotifierId::SYSTEM_COMPONENT:
711 #if defined(OS_CHROMEOS)
712 pref_name = prefs::kMessageCenterDisabledSystemComponentIds;
713 add_new_item = !enabled;
714 id.reset(new base::StringValue(notifier_id.id));
719 case NotifierId::SYNCED_NOTIFICATION_SERVICE:
720 pref_name = prefs::kMessageCenterEnabledSyncNotifierIds;
721 // Adding a new item if |enabled| == true, since synced notification
722 // services are opt-in.
723 add_new_item = enabled;
724 id.reset(new base::StringValue(notifier_id.id));
729 DCHECK(pref_name != NULL);
731 ListPrefUpdate update(profile_->GetPrefs(), pref_name);
732 base::ListValue* const list = update.Get();
734 // AppendIfNotPresent will delete |adding_value| when the same value
736 list->AppendIfNotPresent(id.release());
738 list->Remove(*id, NULL);
742 void DesktopNotificationService::ShowWelcomeNotificationIfNecessary(
743 const Notification& notification) {
744 if (!chrome_now_welcome_notification_ &&
745 message_center::IsRichNotificationEnabled()) {
746 chrome_now_welcome_notification_ =
747 ExtensionWelcomeNotification::Create(kChromeNowExtensionID, profile_);
750 if (chrome_now_welcome_notification_) {
751 chrome_now_welcome_notification_->ShowWelcomeNotificationIfNecessary(
756 void DesktopNotificationService::OnStringListPrefChanged(
757 const char* pref_name, std::set<std::string>* ids_field) {
759 // Separate GetPrefs()->GetList() to analyze the crash. See crbug.com/322320
760 const PrefService* pref_service = profile_->GetPrefs();
762 const base::ListValue* pref_list = pref_service->GetList(pref_name);
763 for (size_t i = 0; i < pref_list->GetSize(); ++i) {
765 if (pref_list->GetString(i, &element) && !element.empty())
766 ids_field->insert(element);
768 LOG(WARNING) << i << "-th element is not a string for " << pref_name;
772 void DesktopNotificationService::Observe(
774 const content::NotificationSource& source,
775 const content::NotificationDetails& details) {
776 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNINSTALLED, type);
778 extensions::Extension* extension =
779 content::Details<extensions::Extension>(details).ptr();
780 NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
781 if (IsNotifierEnabled(notifier_id))
784 // The settings for ephemeral apps will be persisted across cache evictions.
785 if (extension->is_ephemeral())
788 SetNotifierEnabled(notifier_id, true);
791 void DesktopNotificationService::FirePermissionLevelChangedEvent(
792 const NotifierId& notifier_id, bool enabled) {
793 DCHECK_EQ(NotifierId::APPLICATION, notifier_id.type);
794 extensions::api::notifications::PermissionLevel permission =
795 enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
796 : extensions::api::notifications::PERMISSION_LEVEL_DENIED;
797 scoped_ptr<base::ListValue> args(new base::ListValue());
798 args->Append(new base::StringValue(
799 extensions::api::notifications::ToString(permission)));
800 scoped_ptr<extensions::Event> event(new extensions::Event(
801 extensions::api::notifications::OnPermissionLevelChanged::kEventName,
803 extensions::ExtensionSystem::Get(profile_)->event_router()->
804 DispatchEventToExtension(notifier_id.id, event.Pass());
806 // Tell the IO thread that this extension's permission for notifications
808 extensions::InfoMap* extension_info_map =
809 extensions::ExtensionSystem::Get(profile_)->info_map();
810 BrowserThread::PostTask(
811 BrowserThread::IO, FROM_HERE,
812 base::Bind(&extensions::InfoMap::SetNotificationsDisabled,
813 extension_info_map, notifier_id.id, !enabled));