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