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