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