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"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/thread.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/content_settings/content_settings_details.h"
15 #include "chrome/browser/content_settings/content_settings_provider.h"
16 #include "chrome/browser/content_settings/host_content_settings_map.h"
17 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
18 #include "chrome/browser/infobars/infobar_service.h"
19 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
20 #include "chrome/browser/notifications/notification.h"
21 #include "chrome/browser/notifications/notification_object_proxy.h"
22 #include "chrome/browser/notifications/notification_ui_manager.h"
23 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
24 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
28 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
29 #include "chrome/common/content_settings.h"
30 #include "chrome/common/content_settings_pattern.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/common/url_constants.h"
33 #include "components/infobars/core/infobar.h"
34 #include "components/user_prefs/pref_registry_syncable.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/common/show_desktop_notification_params.h"
42 #include "grit/browser_resources.h"
43 #include "grit/chromium_strings.h"
44 #include "grit/generated_resources.h"
45 #include "grit/theme_resources.h"
46 #include "net/base/escape.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/resource/resource_bundle.h"
49 #include "ui/base/webui/web_ui_util.h"
50 #include "ui/message_center/notifier_settings.h"
52 #if defined(ENABLE_EXTENSIONS)
53 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
54 #include "chrome/browser/extensions/extension_service.h"
55 #include "extensions/browser/event_router.h"
56 #include "extensions/browser/extension_system.h"
57 #include "extensions/browser/info_map.h"
58 #include "extensions/common/constants.h"
59 #include "extensions/common/extension.h"
60 #include "extensions/common/extension_set.h"
63 using blink::WebTextDirection
;
64 using content::BrowserThread
;
65 using content::RenderViewHost
;
66 using content::WebContents
;
67 using message_center::NotifierId
;
71 const char kChromeNowExtensionID
[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
73 // NotificationPermissionRequest ---------------------------------------
75 class NotificationPermissionRequest
: public PermissionBubbleRequest
{
77 NotificationPermissionRequest(
78 DesktopNotificationService
* notification_service
,
80 base::string16 display_name
,
81 const base::Closure
& callback
);
82 virtual ~NotificationPermissionRequest();
84 // PermissionBubbleDelegate:
85 virtual int GetIconID() const OVERRIDE
;
86 virtual base::string16
GetMessageText() const OVERRIDE
;
87 virtual base::string16
GetMessageTextFragment() const OVERRIDE
;
88 virtual bool HasUserGesture() const OVERRIDE
;
89 virtual GURL
GetRequestingHostname() const OVERRIDE
;
90 virtual void PermissionGranted() OVERRIDE
;
91 virtual void PermissionDenied() OVERRIDE
;
92 virtual void Cancelled() OVERRIDE
;
93 virtual void RequestFinished() OVERRIDE
;
96 // The notification service to be used.
97 DesktopNotificationService
* notification_service_
;
99 // The origin we are asking for permissions on.
102 // The display name for the origin to be displayed. Will be different from
103 // origin_ for extensions.
104 base::string16 display_name_
;
106 // The callback information that tells us how to respond to javascript.
107 base::Closure callback_
;
109 // Whether the user clicked one of the buttons.
112 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionRequest
);
115 NotificationPermissionRequest::NotificationPermissionRequest(
116 DesktopNotificationService
* notification_service
,
118 base::string16 display_name
,
119 const base::Closure
& callback
)
120 : notification_service_(notification_service
),
122 display_name_(display_name
),
124 action_taken_(false) {}
126 NotificationPermissionRequest::~NotificationPermissionRequest() {}
128 int NotificationPermissionRequest::GetIconID() const {
129 return IDR_INFOBAR_DESKTOP_NOTIFICATIONS
;
132 base::string16
NotificationPermissionRequest::GetMessageText() const {
133 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS
,
138 NotificationPermissionRequest::GetMessageTextFragment() const {
139 return l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSIONS_FRAGMENT
);
142 bool NotificationPermissionRequest::HasUserGesture() const {
143 // Currently notification permission requests are only issued on
148 GURL
NotificationPermissionRequest::GetRequestingHostname() const {
152 void NotificationPermissionRequest::PermissionGranted() {
153 action_taken_
= true;
154 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
155 notification_service_
->GrantPermission(origin_
);
158 void NotificationPermissionRequest::PermissionDenied() {
159 action_taken_
= true;
160 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
161 notification_service_
->DenyPermission(origin_
);
164 void NotificationPermissionRequest::Cancelled() {
167 void NotificationPermissionRequest::RequestFinished() {
169 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
177 // NotificationPermissionInfoBarDelegate --------------------------------------
179 // The delegate for the infobar shown when an origin requests notification
181 class NotificationPermissionInfoBarDelegate
: public ConfirmInfoBarDelegate
{
183 // Creates a notification permission infobar and delegate and adds the infobar
184 // to |infobar_service|.
185 static void Create(InfoBarService
* infobar_service
,
186 DesktopNotificationService
* notification_service
,
188 const base::string16
& display_name
,
189 const base::Closure
& callback
);
192 NotificationPermissionInfoBarDelegate(
193 DesktopNotificationService
* notification_service
,
195 const base::string16
& display_name
,
196 const base::Closure
& callback
);
197 virtual ~NotificationPermissionInfoBarDelegate();
199 // ConfirmInfoBarDelegate:
200 virtual int GetIconID() const OVERRIDE
;
201 virtual Type
GetInfoBarType() const OVERRIDE
;
202 virtual base::string16
GetMessageText() const OVERRIDE
;
203 virtual base::string16
GetButtonLabel(InfoBarButton button
) const OVERRIDE
;
204 virtual bool Accept() OVERRIDE
;
205 virtual bool Cancel() OVERRIDE
;
207 // The origin we are asking for permissions on.
210 // The display name for the origin to be displayed. Will be different from
211 // origin_ for extensions.
212 base::string16 display_name_
;
214 // The notification service to be used.
215 DesktopNotificationService
* notification_service_
;
217 // The callback information that tells us how to respond to javascript.
218 base::Closure callback_
;
220 // Whether the user clicked one of the buttons.
223 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate
);
227 void NotificationPermissionInfoBarDelegate::Create(
228 InfoBarService
* infobar_service
,
229 DesktopNotificationService
* notification_service
,
231 const base::string16
& display_name
,
232 const base::Closure
& callback
) {
233 infobar_service
->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
234 scoped_ptr
<ConfirmInfoBarDelegate
>(
235 new NotificationPermissionInfoBarDelegate(
236 notification_service
, origin
, display_name
, callback
))));
239 NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate(
240 DesktopNotificationService
* notification_service
,
242 const base::string16
& display_name
,
243 const base::Closure
& callback
)
244 : ConfirmInfoBarDelegate(),
246 display_name_(display_name
),
247 notification_service_(notification_service
),
249 action_taken_(false) {
252 NotificationPermissionInfoBarDelegate::
253 ~NotificationPermissionInfoBarDelegate() {
255 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
260 int NotificationPermissionInfoBarDelegate::GetIconID() const {
261 return IDR_INFOBAR_DESKTOP_NOTIFICATIONS
;
264 infobars::InfoBarDelegate::Type
265 NotificationPermissionInfoBarDelegate::GetInfoBarType() const {
266 return PAGE_ACTION_TYPE
;
269 base::string16
NotificationPermissionInfoBarDelegate::GetMessageText() const {
270 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS
,
274 base::string16
NotificationPermissionInfoBarDelegate::GetButtonLabel(
275 InfoBarButton button
) const {
276 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
277 IDS_NOTIFICATION_PERMISSION_YES
: IDS_NOTIFICATION_PERMISSION_NO
);
280 bool NotificationPermissionInfoBarDelegate::Accept() {
281 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
282 notification_service_
->GrantPermission(origin_
);
283 action_taken_
= true;
287 bool NotificationPermissionInfoBarDelegate::Cancel() {
288 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
289 notification_service_
->DenyPermission(origin_
);
290 action_taken_
= true;
294 void CancelNotification(const std::string
& id
) {
295 g_browser_process
->notification_ui_manager()->CancelById(id
);
301 // DesktopNotificationService -------------------------------------------------
304 void DesktopNotificationService::RegisterProfilePrefs(
305 user_prefs::PrefRegistrySyncable
* registry
) {
306 registry
->RegisterListPref(
307 prefs::kMessageCenterDisabledExtensionIds
,
308 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
309 registry
->RegisterListPref(
310 prefs::kMessageCenterDisabledSystemComponentIds
,
311 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
312 registry
->RegisterListPref(
313 prefs::kMessageCenterEnabledSyncNotifierIds
,
314 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
315 ExtensionWelcomeNotification::RegisterProfilePrefs(registry
);
319 base::string16
DesktopNotificationService::CreateDataUrl(
320 const GURL
& icon_url
,
321 const base::string16
& title
,
322 const base::string16
& body
,
323 WebTextDirection dir
) {
325 std::vector
<std::string
> subst
;
326 if (icon_url
.is_valid()) {
327 resource
= IDR_NOTIFICATION_ICON_HTML
;
328 subst
.push_back(icon_url
.spec());
329 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title
)));
330 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body
)));
331 // icon float position
332 subst
.push_back(dir
== blink::WebTextDirectionRightToLeft
?
334 } else if (title
.empty() || body
.empty()) {
335 resource
= IDR_NOTIFICATION_1LINE_HTML
;
336 base::string16 line
= title
.empty() ? body
: title
;
337 // Strings are div names in the template file.
338 base::string16 line_name
=
339 title
.empty() ? base::ASCIIToUTF16("description")
340 : base::ASCIIToUTF16("title");
341 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line_name
)));
342 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line
)));
344 resource
= IDR_NOTIFICATION_2LINE_HTML
;
345 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title
)));
346 subst
.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body
)));
348 // body text direction
349 subst
.push_back(dir
== blink::WebTextDirectionRightToLeft
?
352 return CreateDataUrl(resource
, subst
);
356 base::string16
DesktopNotificationService::CreateDataUrl(
357 int resource
, const std::vector
<std::string
>& subst
) {
358 const base::StringPiece
template_html(
359 ResourceBundle::GetSharedInstance().GetRawDataResource(
362 if (template_html
.empty()) {
363 NOTREACHED() << "unable to load template. ID: " << resource
;
364 return base::string16();
367 std::string data
= ReplaceStringPlaceholders(template_html
, subst
, NULL
);
368 return base::UTF8ToUTF16("data:text/html;charset=utf-8," +
369 net::EscapeQueryParamValue(data
, false));
373 std::string
DesktopNotificationService::AddIconNotification(
374 const GURL
& origin_url
,
375 const base::string16
& title
,
376 const base::string16
& message
,
377 const gfx::Image
& icon
,
378 const base::string16
& replace_id
,
379 NotificationDelegate
* delegate
,
381 Notification
notification(origin_url
, icon
, title
, message
,
382 blink::WebTextDirectionDefault
,
383 base::string16(), replace_id
, delegate
);
384 g_browser_process
->notification_ui_manager()->Add(notification
, profile
);
385 return notification
.notification_id();
388 DesktopNotificationService::DesktopNotificationService(
390 NotificationUIManager
* ui_manager
)
392 ui_manager_(ui_manager
) {
393 OnStringListPrefChanged(
394 prefs::kMessageCenterDisabledExtensionIds
, &disabled_extension_ids_
);
395 OnStringListPrefChanged(
396 prefs::kMessageCenterDisabledSystemComponentIds
,
397 &disabled_system_component_ids_
);
398 OnStringListPrefChanged(
399 prefs::kMessageCenterEnabledSyncNotifierIds
, &enabled_sync_notifier_ids_
);
400 disabled_extension_id_pref_
.Init(
401 prefs::kMessageCenterDisabledExtensionIds
,
402 profile_
->GetPrefs(),
404 &DesktopNotificationService::OnStringListPrefChanged
,
405 base::Unretained(this),
406 base::Unretained(prefs::kMessageCenterDisabledExtensionIds
),
407 base::Unretained(&disabled_extension_ids_
)));
408 disabled_system_component_id_pref_
.Init(
409 prefs::kMessageCenterDisabledSystemComponentIds
,
410 profile_
->GetPrefs(),
412 &DesktopNotificationService::OnStringListPrefChanged
,
413 base::Unretained(this),
414 base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds
),
415 base::Unretained(&disabled_system_component_ids_
)));
416 enabled_sync_notifier_id_pref_
.Init(
417 prefs::kMessageCenterEnabledSyncNotifierIds
,
418 profile_
->GetPrefs(),
420 &DesktopNotificationService::OnStringListPrefChanged
,
421 base::Unretained(this),
422 base::Unretained(prefs::kMessageCenterEnabledSyncNotifierIds
),
423 base::Unretained(&enabled_sync_notifier_ids_
)));
424 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
425 content::Source
<Profile
>(profile_
));
428 DesktopNotificationService::~DesktopNotificationService() {
431 void DesktopNotificationService::GrantPermission(const GURL
& origin
) {
432 ContentSettingsPattern primary_pattern
=
433 ContentSettingsPattern::FromURLNoWildcard(origin
);
434 profile_
->GetHostContentSettingsMap()->SetContentSetting(
436 ContentSettingsPattern::Wildcard(),
437 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
,
438 NO_RESOURCE_IDENTIFIER
,
439 CONTENT_SETTING_ALLOW
);
442 void DesktopNotificationService::DenyPermission(const GURL
& origin
) {
443 ContentSettingsPattern primary_pattern
=
444 ContentSettingsPattern::FromURLNoWildcard(origin
);
445 profile_
->GetHostContentSettingsMap()->SetContentSetting(
447 ContentSettingsPattern::Wildcard(),
448 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
,
449 NO_RESOURCE_IDENTIFIER
,
450 CONTENT_SETTING_BLOCK
);
453 ContentSetting
DesktopNotificationService::GetDefaultContentSetting(
454 std::string
* provider_id
) {
455 return profile_
->GetHostContentSettingsMap()->GetDefaultContentSetting(
456 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
, provider_id
);
459 void DesktopNotificationService::SetDefaultContentSetting(
460 ContentSetting setting
) {
461 profile_
->GetHostContentSettingsMap()->SetDefaultContentSetting(
462 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
, setting
);
465 void DesktopNotificationService::ResetToDefaultContentSetting() {
466 profile_
->GetHostContentSettingsMap()->SetDefaultContentSetting(
467 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
, CONTENT_SETTING_DEFAULT
);
470 void DesktopNotificationService::GetNotificationsSettings(
471 ContentSettingsForOneType
* settings
) {
472 profile_
->GetHostContentSettingsMap()->GetSettingsForOneType(
473 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
,
474 NO_RESOURCE_IDENTIFIER
,
478 void DesktopNotificationService::ClearSetting(
479 const ContentSettingsPattern
& pattern
) {
480 profile_
->GetHostContentSettingsMap()->SetContentSetting(
482 ContentSettingsPattern::Wildcard(),
483 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
,
484 NO_RESOURCE_IDENTIFIER
,
485 CONTENT_SETTING_DEFAULT
);
488 void DesktopNotificationService::ResetAllOrigins() {
489 profile_
->GetHostContentSettingsMap()->ClearSettingsForOneType(
490 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
);
493 ContentSetting
DesktopNotificationService::GetContentSetting(
494 const GURL
& origin
) {
495 return profile_
->GetHostContentSettingsMap()->GetContentSetting(
498 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
,
499 NO_RESOURCE_IDENTIFIER
);
502 void DesktopNotificationService::RequestPermission(
504 content::RenderFrameHost
* render_frame_host
,
505 const base::Closure
& callback
) {
506 // If |origin| hasn't been seen before and the default content setting for
507 // notifications is "ask", show an infobar.
508 // The cache can only answer queries on the IO thread once it's initialized,
509 // so don't ask the cache.
510 WebContents
* web_contents
= WebContents::FromRenderFrameHost(
512 ContentSetting setting
= GetContentSetting(origin
);
513 if (setting
== CONTENT_SETTING_ASK
) {
514 if (PermissionBubbleManager::Enabled()) {
515 PermissionBubbleManager
* bubble_manager
=
516 PermissionBubbleManager::FromWebContents(web_contents
);
517 bubble_manager
->AddRequest(new NotificationPermissionRequest(
520 DisplayNameForOriginInProcessId(
521 origin
, render_frame_host
->GetProcess()->GetID()),
526 // Show an info bar requesting permission.
527 InfoBarService
* infobar_service
=
528 InfoBarService::FromWebContents(web_contents
);
529 // |infobar_service| may be NULL, e.g., if this request originated in a
530 // browser action popup, extension background page, or any HTML that runs
532 if (infobar_service
) {
533 NotificationPermissionInfoBarDelegate::Create(
534 infobar_service
, this, origin
,
535 DisplayNameForOriginInProcessId(
536 origin
, render_frame_host
->GetProcess()->GetID()),
542 // Notify renderer immediately.
546 void DesktopNotificationService::ShowDesktopNotification(
547 const content::ShowDesktopNotificationHostMsgParams
& params
,
548 content::RenderFrameHost
* render_frame_host
,
549 content::DesktopNotificationDelegate
* delegate
,
550 base::Closure
* cancel_callback
) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
552 const GURL
& origin
= params
.origin
;
553 NotificationObjectProxy
* proxy
=
554 new NotificationObjectProxy(render_frame_host
, delegate
);
556 base::string16 display_source
= DisplayNameForOriginInProcessId(
557 origin
, render_frame_host
->GetProcess()->GetID());
558 Notification
notification(origin
, params
.icon_url
, params
.title
,
559 params
.body
, params
.direction
, display_source
, params
.replace_id
,
562 // The webkit notification doesn't timeout.
563 notification
.set_never_timeout(true);
565 GetUIManager()->Add(notification
, profile_
);
567 *cancel_callback
= base::Bind(&CancelNotification
, proxy
->id());
570 base::string16
DesktopNotificationService::DisplayNameForOriginInProcessId(
571 const GURL
& origin
, int process_id
) {
572 #if defined(ENABLE_EXTENSIONS)
573 // If the source is an extension, lookup the display name.
574 if (origin
.SchemeIs(extensions::kExtensionScheme
)) {
575 extensions::InfoMap
* extension_info_map
=
576 extensions::ExtensionSystem::Get(profile_
)->info_map();
577 if (extension_info_map
) {
578 extensions::ExtensionSet extensions
;
579 extension_info_map
->GetExtensionsWithAPIPermissionForSecurityOrigin(
580 origin
, process_id
, extensions::APIPermission::kNotification
,
582 for (extensions::ExtensionSet::const_iterator iter
= extensions
.begin();
583 iter
!= extensions
.end(); ++iter
) {
584 NotifierId
notifier_id(NotifierId::APPLICATION
, (*iter
)->id());
585 if (IsNotifierEnabled(notifier_id
))
586 return base::UTF8ToUTF16((*iter
)->name());
592 return base::UTF8ToUTF16(origin
.host());
595 void DesktopNotificationService::NotifySettingsChange() {
596 content::NotificationService::current()->Notify(
597 chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED
,
598 content::Source
<DesktopNotificationService
>(this),
599 content::NotificationService::NoDetails());
602 NotificationUIManager
* DesktopNotificationService::GetUIManager() {
603 // We defer setting ui_manager_ to the global singleton until we need it
604 // in order to avoid UI dependent construction during startup.
606 ui_manager_
= g_browser_process
->notification_ui_manager();
610 bool DesktopNotificationService::IsNotifierEnabled(
611 const NotifierId
& notifier_id
) {
612 switch (notifier_id
.type
) {
613 case NotifierId::APPLICATION
:
614 return disabled_extension_ids_
.find(notifier_id
.id
) ==
615 disabled_extension_ids_
.end();
616 case NotifierId::WEB_PAGE
:
617 return GetContentSetting(notifier_id
.url
) == CONTENT_SETTING_ALLOW
;
618 case NotifierId::SYSTEM_COMPONENT
:
619 #if defined(OS_CHROMEOS)
620 return disabled_system_component_ids_
.find(notifier_id
.id
) ==
621 disabled_system_component_ids_
.end();
623 // We do not disable system component notifications.
626 case NotifierId::SYNCED_NOTIFICATION_SERVICE
:
627 return enabled_sync_notifier_ids_
.find(notifier_id
.id
) !=
628 enabled_sync_notifier_ids_
.end();
635 void DesktopNotificationService::SetNotifierEnabled(
636 const NotifierId
& notifier_id
,
638 DCHECK_NE(NotifierId::WEB_PAGE
, notifier_id
.type
);
640 bool add_new_item
= false;
641 const char* pref_name
= NULL
;
642 scoped_ptr
<base::StringValue
> id
;
643 switch (notifier_id
.type
) {
644 case NotifierId::APPLICATION
:
645 pref_name
= prefs::kMessageCenterDisabledExtensionIds
;
646 add_new_item
= !enabled
;
647 id
.reset(new base::StringValue(notifier_id
.id
));
648 FirePermissionLevelChangedEvent(notifier_id
, enabled
);
650 case NotifierId::SYSTEM_COMPONENT
:
651 #if defined(OS_CHROMEOS)
652 pref_name
= prefs::kMessageCenterDisabledSystemComponentIds
;
653 add_new_item
= !enabled
;
654 id
.reset(new base::StringValue(notifier_id
.id
));
659 case NotifierId::SYNCED_NOTIFICATION_SERVICE
:
660 pref_name
= prefs::kMessageCenterEnabledSyncNotifierIds
;
661 // Adding a new item if |enabled| == true, since synced notification
662 // services are opt-in.
663 add_new_item
= enabled
;
664 id
.reset(new base::StringValue(notifier_id
.id
));
669 DCHECK(pref_name
!= NULL
);
671 ListPrefUpdate
update(profile_
->GetPrefs(), pref_name
);
672 base::ListValue
* const list
= update
.Get();
674 // AppendIfNotPresent will delete |adding_value| when the same value
676 list
->AppendIfNotPresent(id
.release());
678 list
->Remove(*id
, NULL
);
682 void DesktopNotificationService::ShowWelcomeNotificationIfNecessary(
683 const Notification
& notification
) {
684 if (!chrome_now_welcome_notification_
) {
685 chrome_now_welcome_notification_
=
686 ExtensionWelcomeNotification::Create(kChromeNowExtensionID
, profile_
);
689 if (chrome_now_welcome_notification_
) {
690 chrome_now_welcome_notification_
->ShowWelcomeNotificationIfNecessary(
695 void DesktopNotificationService::OnStringListPrefChanged(
696 const char* pref_name
, std::set
<std::string
>* ids_field
) {
698 // Separate GetPrefs()->GetList() to analyze the crash. See crbug.com/322320
699 const PrefService
* pref_service
= profile_
->GetPrefs();
701 const base::ListValue
* pref_list
= pref_service
->GetList(pref_name
);
702 for (size_t i
= 0; i
< pref_list
->GetSize(); ++i
) {
704 if (pref_list
->GetString(i
, &element
) && !element
.empty())
705 ids_field
->insert(element
);
707 LOG(WARNING
) << i
<< "-th element is not a string for " << pref_name
;
711 void DesktopNotificationService::Observe(
713 const content::NotificationSource
& source
,
714 const content::NotificationDetails
& details
) {
715 #if defined(ENABLE_EXTENSIONS)
716 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNINSTALLED
, type
);
718 extensions::Extension
* extension
=
719 content::Details
<extensions::Extension
>(details
).ptr();
720 NotifierId
notifier_id(NotifierId::APPLICATION
, extension
->id());
721 if (IsNotifierEnabled(notifier_id
))
724 // The settings for ephemeral apps will be persisted across cache evictions.
725 if (extension
->is_ephemeral())
728 SetNotifierEnabled(notifier_id
, true);
732 void DesktopNotificationService::FirePermissionLevelChangedEvent(
733 const NotifierId
& notifier_id
, bool enabled
) {
734 #if defined(ENABLE_EXTENSIONS)
735 DCHECK_EQ(NotifierId::APPLICATION
, notifier_id
.type
);
736 extensions::api::notifications::PermissionLevel permission
=
737 enabled
? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
738 : extensions::api::notifications::PERMISSION_LEVEL_DENIED
;
739 scoped_ptr
<base::ListValue
> args(new base::ListValue());
740 args
->Append(new base::StringValue(
741 extensions::api::notifications::ToString(permission
)));
742 scoped_ptr
<extensions::Event
> event(new extensions::Event(
743 extensions::api::notifications::OnPermissionLevelChanged::kEventName
,
745 extensions::EventRouter::Get(profile_
)
746 ->DispatchEventToExtension(notifier_id
.id
, event
.Pass());
748 // Tell the IO thread that this extension's permission for notifications
750 extensions::InfoMap
* extension_info_map
=
751 extensions::ExtensionSystem::Get(profile_
)->info_map();
752 BrowserThread::PostTask(
753 BrowserThread::IO
, FROM_HERE
,
754 base::Bind(&extensions::InfoMap::SetNotificationsDisabled
,
755 extension_info_map
, notifier_id
.id
, !enabled
));