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