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