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