Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / notifications / desktop_notification_service.cc
bloba5dfa7f936886a7b3db89f2c9d2bf323e70bf9b2
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/extensions/extension_system.h"
19 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
20 #include "chrome/browser/infobars/infobar.h"
21 #include "chrome/browser/infobars/infobar_service.h"
22 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
23 #include "chrome/browser/notifications/notification.h"
24 #include "chrome/browser/notifications/notification_object_proxy.h"
25 #include "chrome/browser/notifications/notification_ui_manager.h"
26 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
27 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/common/content_settings.h"
31 #include "chrome/common/content_settings_pattern.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.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_view_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/common/show_desktop_notification_params.h"
40 #include "extensions/browser/event_router.h"
41 #include "extensions/browser/info_map.h"
42 #include "extensions/common/constants.h"
43 #include "extensions/common/extension.h"
44 #include "extensions/common/extension_set.h"
45 #include "grit/browser_resources.h"
46 #include "grit/chromium_strings.h"
47 #include "grit/generated_resources.h"
48 #include "grit/theme_resources.h"
49 #include "net/base/escape.h"
50 #include "ui/base/l10n/l10n_util.h"
51 #include "ui/base/resource/resource_bundle.h"
52 #include "ui/base/webui/web_ui_util.h"
53 #include "ui/message_center/message_center_util.h"
54 #include "ui/message_center/notifier_settings.h"
56 using content::BrowserThread;
57 using content::RenderViewHost;
58 using content::WebContents;
59 using message_center::NotifierId;
60 using blink::WebTextDirection;
63 // NotificationPermissionInfoBarDelegate --------------------------------------
65 // The delegate for the infobar shown when an origin requests notification
66 // permissions.
67 class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
68 public:
69 // Creates a notification permission infobar and delegate and adds the infobar
70 // to |infobar_service|.
71 static void Create(InfoBarService* infobar_service,
72 DesktopNotificationService* notification_service,
73 const GURL& origin,
74 const base::string16& display_name,
75 int process_id,
76 int route_id,
77 int callback_context);
79 private:
80 NotificationPermissionInfoBarDelegate(
81 DesktopNotificationService* notification_service,
82 const GURL& origin,
83 const base::string16& display_name,
84 int process_id,
85 int route_id,
86 int callback_context);
87 virtual ~NotificationPermissionInfoBarDelegate();
89 // ConfirmInfoBarDelegate:
90 virtual int GetIconID() const OVERRIDE;
91 virtual Type GetInfoBarType() const OVERRIDE;
92 virtual base::string16 GetMessageText() const OVERRIDE;
93 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
94 virtual bool Accept() OVERRIDE;
95 virtual bool Cancel() OVERRIDE;
97 // The origin we are asking for permissions on.
98 GURL origin_;
100 // The display name for the origin to be displayed. Will be different from
101 // origin_ for extensions.
102 base::string16 display_name_;
104 // The notification service to be used.
105 DesktopNotificationService* notification_service_;
107 // The callback information that tells us how to respond to javascript via
108 // the correct RenderView.
109 int process_id_;
110 int route_id_;
111 int callback_context_;
113 // Whether the user clicked one of the buttons.
114 bool action_taken_;
116 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
119 // static
120 void NotificationPermissionInfoBarDelegate::Create(
121 InfoBarService* infobar_service,
122 DesktopNotificationService* notification_service,
123 const GURL& origin,
124 const base::string16& display_name,
125 int process_id,
126 int route_id,
127 int callback_context) {
128 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
129 scoped_ptr<ConfirmInfoBarDelegate>(
130 new NotificationPermissionInfoBarDelegate(
131 notification_service, origin, display_name, process_id, route_id,
132 callback_context))));
135 NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate(
136 DesktopNotificationService* notification_service,
137 const GURL& origin,
138 const base::string16& display_name,
139 int process_id,
140 int route_id,
141 int callback_context)
142 : ConfirmInfoBarDelegate(),
143 origin_(origin),
144 display_name_(display_name),
145 notification_service_(notification_service),
146 process_id_(process_id),
147 route_id_(route_id),
148 callback_context_(callback_context),
149 action_taken_(false) {
152 NotificationPermissionInfoBarDelegate::
153 ~NotificationPermissionInfoBarDelegate() {
154 if (!action_taken_)
155 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
157 RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
158 if (host)
159 host->DesktopNotificationPermissionRequestDone(callback_context_);
162 int NotificationPermissionInfoBarDelegate::GetIconID() const {
163 return IDR_INFOBAR_DESKTOP_NOTIFICATIONS;
166 InfoBarDelegate::Type
167 NotificationPermissionInfoBarDelegate::GetInfoBarType() const {
168 return PAGE_ACTION_TYPE;
171 base::string16 NotificationPermissionInfoBarDelegate::GetMessageText() const {
172 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
173 display_name_);
176 base::string16 NotificationPermissionInfoBarDelegate::GetButtonLabel(
177 InfoBarButton button) const {
178 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
179 IDS_NOTIFICATION_PERMISSION_YES : IDS_NOTIFICATION_PERMISSION_NO);
182 bool NotificationPermissionInfoBarDelegate::Accept() {
183 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
184 notification_service_->GrantPermission(origin_);
185 action_taken_ = true;
186 return true;
189 bool NotificationPermissionInfoBarDelegate::Cancel() {
190 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
191 notification_service_->DenyPermission(origin_);
192 action_taken_ = true;
193 return true;
197 // DesktopNotificationService -------------------------------------------------
199 // static
200 void DesktopNotificationService::RegisterProfilePrefs(
201 user_prefs::PrefRegistrySyncable* registry) {
202 registry->RegisterListPref(
203 prefs::kMessageCenterDisabledExtensionIds,
204 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
205 registry->RegisterListPref(
206 prefs::kMessageCenterDisabledSystemComponentIds,
207 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
208 registry->RegisterListPref(
209 prefs::kMessageCenterEnabledSyncNotifierIds,
210 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
211 WelcomeNotification::RegisterProfilePrefs(registry);
214 // static
215 base::string16 DesktopNotificationService::CreateDataUrl(
216 const GURL& icon_url,
217 const base::string16& title,
218 const base::string16& body,
219 WebTextDirection dir) {
220 int resource;
221 std::vector<std::string> subst;
222 if (icon_url.is_valid()) {
223 resource = IDR_NOTIFICATION_ICON_HTML;
224 subst.push_back(icon_url.spec());
225 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title)));
226 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body)));
227 // icon float position
228 subst.push_back(dir == blink::WebTextDirectionRightToLeft ?
229 "right" : "left");
230 } else if (title.empty() || body.empty()) {
231 resource = IDR_NOTIFICATION_1LINE_HTML;
232 base::string16 line = title.empty() ? body : title;
233 // Strings are div names in the template file.
234 base::string16 line_name =
235 title.empty() ? base::ASCIIToUTF16("description")
236 : base::ASCIIToUTF16("title");
237 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line_name)));
238 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(line)));
239 } else {
240 resource = IDR_NOTIFICATION_2LINE_HTML;
241 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(title)));
242 subst.push_back(net::EscapeForHTML(base::UTF16ToUTF8(body)));
244 // body text direction
245 subst.push_back(dir == blink::WebTextDirectionRightToLeft ?
246 "rtl" : "ltr");
248 return CreateDataUrl(resource, subst);
251 // static
252 base::string16 DesktopNotificationService::CreateDataUrl(
253 int resource, const std::vector<std::string>& subst) {
254 const base::StringPiece template_html(
255 ResourceBundle::GetSharedInstance().GetRawDataResource(
256 resource));
258 if (template_html.empty()) {
259 NOTREACHED() << "unable to load template. ID: " << resource;
260 return base::string16();
263 std::string data = ReplaceStringPlaceholders(template_html, subst, NULL);
264 return base::UTF8ToUTF16("data:text/html;charset=utf-8," +
265 net::EscapeQueryParamValue(data, false));
268 // static
269 std::string DesktopNotificationService::AddNotification(
270 const GURL& origin_url,
271 const base::string16& title,
272 const base::string16& message,
273 const GURL& icon_url,
274 const base::string16& replace_id,
275 NotificationDelegate* delegate,
276 Profile* profile) {
277 if (message_center::IsRichNotificationEnabled()) {
278 // For message center create a non-HTML notification with |icon_url|.
279 Notification notification(origin_url, icon_url, title, message,
280 blink::WebTextDirectionDefault,
281 base::string16(), replace_id, delegate);
282 g_browser_process->notification_ui_manager()->Add(notification, profile);
283 return notification.notification_id();
286 // Generate a data URL embedding the icon URL, title, and message.
287 GURL content_url(CreateDataUrl(
288 icon_url, title, message, blink::WebTextDirectionDefault));
289 Notification notification(
290 GURL(), content_url, base::string16(), replace_id, delegate);
291 g_browser_process->notification_ui_manager()->Add(notification, profile);
292 return notification.notification_id();
295 // static
296 std::string DesktopNotificationService::AddIconNotification(
297 const GURL& origin_url,
298 const base::string16& title,
299 const base::string16& message,
300 const gfx::Image& icon,
301 const base::string16& replace_id,
302 NotificationDelegate* delegate,
303 Profile* profile) {
304 if (message_center::IsRichNotificationEnabled()) {
305 // For message center create a non-HTML notification with |icon|.
306 Notification notification(origin_url, icon, title, message,
307 blink::WebTextDirectionDefault,
308 base::string16(), replace_id, delegate);
309 g_browser_process->notification_ui_manager()->Add(notification, profile);
310 return notification.notification_id();
313 GURL icon_url;
314 if (!icon.IsEmpty())
315 icon_url = GURL(webui::GetBitmapDataUrl(*icon.ToSkBitmap()));
316 return AddNotification(
317 origin_url, title, message, icon_url, replace_id, delegate, profile);
320 // static
321 void DesktopNotificationService::RemoveNotification(
322 const std::string& notification_id) {
323 g_browser_process->notification_ui_manager()->CancelById(notification_id);
326 DesktopNotificationService::DesktopNotificationService(
327 Profile* profile,
328 NotificationUIManager* ui_manager)
329 : profile_(profile),
330 ui_manager_(ui_manager) {
331 OnStringListPrefChanged(
332 prefs::kMessageCenterDisabledExtensionIds, &disabled_extension_ids_);
333 OnStringListPrefChanged(
334 prefs::kMessageCenterDisabledSystemComponentIds,
335 &disabled_system_component_ids_);
336 OnStringListPrefChanged(
337 prefs::kMessageCenterEnabledSyncNotifierIds, &enabled_sync_notifier_ids_);
338 disabled_extension_id_pref_.Init(
339 prefs::kMessageCenterDisabledExtensionIds,
340 profile_->GetPrefs(),
341 base::Bind(
342 &DesktopNotificationService::OnStringListPrefChanged,
343 base::Unretained(this),
344 base::Unretained(prefs::kMessageCenterDisabledExtensionIds),
345 base::Unretained(&disabled_extension_ids_)));
346 disabled_system_component_id_pref_.Init(
347 prefs::kMessageCenterDisabledSystemComponentIds,
348 profile_->GetPrefs(),
349 base::Bind(
350 &DesktopNotificationService::OnStringListPrefChanged,
351 base::Unretained(this),
352 base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds),
353 base::Unretained(&disabled_system_component_ids_)));
354 enabled_sync_notifier_id_pref_.Init(
355 prefs::kMessageCenterEnabledSyncNotifierIds,
356 profile_->GetPrefs(),
357 base::Bind(
358 &DesktopNotificationService::OnStringListPrefChanged,
359 base::Unretained(this),
360 base::Unretained(prefs::kMessageCenterEnabledSyncNotifierIds),
361 base::Unretained(&enabled_sync_notifier_ids_)));
362 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
363 content::Source<Profile>(profile_));
366 DesktopNotificationService::~DesktopNotificationService() {
369 void DesktopNotificationService::GrantPermission(const GURL& origin) {
370 ContentSettingsPattern primary_pattern =
371 ContentSettingsPattern::FromURLNoWildcard(origin);
372 profile_->GetHostContentSettingsMap()->SetContentSetting(
373 primary_pattern,
374 ContentSettingsPattern::Wildcard(),
375 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
376 NO_RESOURCE_IDENTIFIER,
377 CONTENT_SETTING_ALLOW);
380 void DesktopNotificationService::DenyPermission(const GURL& origin) {
381 ContentSettingsPattern primary_pattern =
382 ContentSettingsPattern::FromURLNoWildcard(origin);
383 profile_->GetHostContentSettingsMap()->SetContentSetting(
384 primary_pattern,
385 ContentSettingsPattern::Wildcard(),
386 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
387 NO_RESOURCE_IDENTIFIER,
388 CONTENT_SETTING_BLOCK);
391 ContentSetting DesktopNotificationService::GetDefaultContentSetting(
392 std::string* provider_id) {
393 return profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
394 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, provider_id);
397 void DesktopNotificationService::SetDefaultContentSetting(
398 ContentSetting setting) {
399 profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
400 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
403 void DesktopNotificationService::ResetToDefaultContentSetting() {
404 profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
405 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_DEFAULT);
408 void DesktopNotificationService::GetNotificationsSettings(
409 ContentSettingsForOneType* settings) {
410 profile_->GetHostContentSettingsMap()->GetSettingsForOneType(
411 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
412 NO_RESOURCE_IDENTIFIER,
413 settings);
416 void DesktopNotificationService::ClearSetting(
417 const ContentSettingsPattern& pattern) {
418 profile_->GetHostContentSettingsMap()->SetContentSetting(
419 pattern,
420 ContentSettingsPattern::Wildcard(),
421 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
422 NO_RESOURCE_IDENTIFIER,
423 CONTENT_SETTING_DEFAULT);
426 void DesktopNotificationService::ResetAllOrigins() {
427 profile_->GetHostContentSettingsMap()->ClearSettingsForOneType(
428 CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
431 ContentSetting DesktopNotificationService::GetContentSetting(
432 const GURL& origin) {
433 return profile_->GetHostContentSettingsMap()->GetContentSetting(
434 origin,
435 origin,
436 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
437 NO_RESOURCE_IDENTIFIER);
440 void DesktopNotificationService::RequestPermission(
441 const GURL& origin, int process_id, int route_id, int callback_context,
442 WebContents* contents) {
443 // If |origin| hasn't been seen before and the default content setting for
444 // notifications is "ask", show an infobar.
445 // The cache can only answer queries on the IO thread once it's initialized,
446 // so don't ask the cache.
447 ContentSetting setting = GetContentSetting(origin);
448 if (setting == CONTENT_SETTING_ASK) {
449 // Show an info bar requesting permission.
450 InfoBarService* infobar_service =
451 InfoBarService::FromWebContents(contents);
452 // |infobar_service| may be NULL, e.g., if this request originated in a
453 // browser action popup, extension background page, or any HTML that runs
454 // outside of a tab.
455 if (infobar_service) {
456 NotificationPermissionInfoBarDelegate::Create(
457 infobar_service,
458 DesktopNotificationServiceFactory::GetForProfile(
459 Profile::FromBrowserContext(contents->GetBrowserContext())),
460 origin, DisplayNameForOriginInProcessId(origin, process_id),
461 process_id, route_id, callback_context);
462 return;
466 // Notify renderer immediately.
467 RenderViewHost* host = RenderViewHost::FromID(process_id, route_id);
468 if (host)
469 host->DesktopNotificationPermissionRequestDone(callback_context);
472 #if !defined(OS_WIN)
473 void DesktopNotificationService::ShowNotification(
474 const Notification& notification) {
475 GetUIManager()->Add(notification, profile_);
478 bool DesktopNotificationService::CancelDesktopNotification(
479 int process_id, int route_id, int notification_id) {
480 scoped_refptr<NotificationObjectProxy> proxy(
481 new NotificationObjectProxy(process_id, route_id, notification_id,
482 false));
483 return GetUIManager()->CancelById(proxy->id());
485 #endif // OS_WIN
487 bool DesktopNotificationService::ShowDesktopNotification(
488 const content::ShowDesktopNotificationHostMsgParams& params,
489 int process_id, int route_id, DesktopNotificationSource source) {
490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
491 const GURL& origin = params.origin;
492 NotificationObjectProxy* proxy =
493 new NotificationObjectProxy(process_id, route_id,
494 params.notification_id,
495 source == WorkerNotification);
497 base::string16 display_source =
498 DisplayNameForOriginInProcessId(origin, process_id);
499 Notification notification(origin, params.icon_url, params.title,
500 params.body, params.direction, display_source, params.replace_id,
501 proxy);
503 // The webkit notification doesn't timeout.
504 notification.set_never_timeout(true);
506 ShowNotification(notification);
507 return true;
510 base::string16 DesktopNotificationService::DisplayNameForOriginInProcessId(
511 const GURL& origin, int process_id) {
512 // If the source is an extension, lookup the display name.
513 // Message center prefers to use extension name if the notification
514 // is allowed by an extension.
515 if (NotificationUIManager::DelegatesToMessageCenter() ||
516 origin.SchemeIs(extensions::kExtensionScheme)) {
517 extensions::InfoMap* extension_info_map =
518 extensions::ExtensionSystem::Get(profile_)->info_map();
519 if (extension_info_map) {
520 extensions::ExtensionSet extensions;
521 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
522 origin, process_id, extensions::APIPermission::kNotification,
523 &extensions);
524 for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
525 iter != extensions.end(); ++iter) {
526 NotifierId notifier_id(NotifierId::APPLICATION, (*iter)->id());
527 if (IsNotifierEnabled(notifier_id))
528 return base::UTF8ToUTF16((*iter)->name());
532 return base::UTF8ToUTF16(origin.host());
535 void DesktopNotificationService::NotifySettingsChange() {
536 content::NotificationService::current()->Notify(
537 chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
538 content::Source<DesktopNotificationService>(this),
539 content::NotificationService::NoDetails());
542 NotificationUIManager* DesktopNotificationService::GetUIManager() {
543 // We defer setting ui_manager_ to the global singleton until we need it
544 // in order to avoid UI dependent construction during startup.
545 if (!ui_manager_)
546 ui_manager_ = g_browser_process->notification_ui_manager();
547 return ui_manager_;
550 bool DesktopNotificationService::IsNotifierEnabled(
551 const NotifierId& notifier_id) {
552 switch (notifier_id.type) {
553 case NotifierId::APPLICATION:
554 return disabled_extension_ids_.find(notifier_id.id) ==
555 disabled_extension_ids_.end();
556 case NotifierId::WEB_PAGE:
557 return GetContentSetting(notifier_id.url) == CONTENT_SETTING_ALLOW;
558 case NotifierId::SYSTEM_COMPONENT:
559 #if defined(OS_CHROMEOS)
560 return disabled_system_component_ids_.find(notifier_id.id) ==
561 disabled_system_component_ids_.end();
562 #else
563 // We do not disable system component notifications.
564 return true;
565 #endif
566 case NotifierId::SYNCED_NOTIFICATION_SERVICE:
567 return enabled_sync_notifier_ids_.find(notifier_id.id) !=
568 enabled_sync_notifier_ids_.end();
571 NOTREACHED();
572 return false;
575 void DesktopNotificationService::SetNotifierEnabled(
576 const NotifierId& notifier_id,
577 bool enabled) {
578 DCHECK_NE(NotifierId::WEB_PAGE, notifier_id.type);
580 bool add_new_item = false;
581 const char* pref_name = NULL;
582 scoped_ptr<base::StringValue> id;
583 switch (notifier_id.type) {
584 case NotifierId::APPLICATION:
585 pref_name = prefs::kMessageCenterDisabledExtensionIds;
586 add_new_item = !enabled;
587 id.reset(new base::StringValue(notifier_id.id));
588 FirePermissionLevelChangedEvent(notifier_id, enabled);
589 break;
590 case NotifierId::SYSTEM_COMPONENT:
591 #if defined(OS_CHROMEOS)
592 pref_name = prefs::kMessageCenterDisabledSystemComponentIds;
593 add_new_item = !enabled;
594 id.reset(new base::StringValue(notifier_id.id));
595 #else
596 return;
597 #endif
598 break;
599 case NotifierId::SYNCED_NOTIFICATION_SERVICE:
600 pref_name = prefs::kMessageCenterEnabledSyncNotifierIds;
601 // Adding a new item if |enabled| == true, since synced notification
602 // services are opt-in.
603 add_new_item = enabled;
604 id.reset(new base::StringValue(notifier_id.id));
605 break;
606 default:
607 NOTREACHED();
609 DCHECK(pref_name != NULL);
611 ListPrefUpdate update(profile_->GetPrefs(), pref_name);
612 base::ListValue* const list = update.Get();
613 if (add_new_item) {
614 // AppendIfNotPresent will delete |adding_value| when the same value
615 // already exists.
616 list->AppendIfNotPresent(id.release());
617 } else {
618 list->Remove(*id, NULL);
622 void DesktopNotificationService::ShowWelcomeNotificationIfNecessary(
623 const Notification& notification) {
624 if (!welcome_notification && message_center::IsRichNotificationEnabled()) {
625 welcome_notification.reset(
626 new WelcomeNotification(profile_, g_browser_process->message_center()));
629 if (welcome_notification)
630 welcome_notification->ShowWelcomeNotificationIfNecessary(notification);
633 void DesktopNotificationService::OnStringListPrefChanged(
634 const char* pref_name, std::set<std::string>* ids_field) {
635 ids_field->clear();
636 // Separate GetPrefs()->GetList() to analyze the crash. See crbug.com/322320
637 const PrefService* pref_service = profile_->GetPrefs();
638 CHECK(pref_service);
639 const base::ListValue* pref_list = pref_service->GetList(pref_name);
640 for (size_t i = 0; i < pref_list->GetSize(); ++i) {
641 std::string element;
642 if (pref_list->GetString(i, &element) && !element.empty())
643 ids_field->insert(element);
644 else
645 LOG(WARNING) << i << "-th element is not a string for " << pref_name;
649 void DesktopNotificationService::Observe(
650 int type,
651 const content::NotificationSource& source,
652 const content::NotificationDetails& details) {
653 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNINSTALLED, type);
655 extensions::Extension* extension =
656 content::Details<extensions::Extension>(details).ptr();
657 NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
658 if (IsNotifierEnabled(notifier_id))
659 return;
661 SetNotifierEnabled(notifier_id, true);
664 void DesktopNotificationService::FirePermissionLevelChangedEvent(
665 const NotifierId& notifier_id, bool enabled) {
666 DCHECK_EQ(NotifierId::APPLICATION, notifier_id.type);
667 extensions::api::notifications::PermissionLevel permission =
668 enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
669 : extensions::api::notifications::PERMISSION_LEVEL_DENIED;
670 scoped_ptr<base::ListValue> args(new base::ListValue());
671 args->Append(new base::StringValue(
672 extensions::api::notifications::ToString(permission)));
673 scoped_ptr<extensions::Event> event(new extensions::Event(
674 extensions::api::notifications::OnPermissionLevelChanged::kEventName,
675 args.Pass()));
676 extensions::ExtensionSystem::Get(profile_)->event_router()->
677 DispatchEventToExtension(notifier_id.id, event.Pass());
679 // Tell the IO thread that this extension's permission for notifications
680 // has changed.
681 extensions::InfoMap* extension_info_map =
682 extensions::ExtensionSystem::Get(profile_)->info_map();
683 BrowserThread::PostTask(
684 BrowserThread::IO, FROM_HERE,
685 base::Bind(&extensions::InfoMap::SetNotificationsDisabled,
686 extension_info_map, notifier_id.id, !enabled));