desktop_notification_service.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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/prefs/scoped_user_pref_update.h" 24#include "chrome/browser/profiles/profile.h" 25#include "chrome/browser/ui/browser.h" 26#include "chrome/common/chrome_notification_types.h" 27#include "chrome/common/content_settings.h" 28#include "chrome/common/content_settings_pattern.h" 29#include "chrome/common/pref_names.h" 30#include "chrome/common/url_constants.h" 31#include "components/user_prefs/pref_registry_syncable.h" 32#include "content/public/browser/browser_thread.h" 33#include "content/public/browser/notification_service.h" 34#include "content/public/browser/render_view_host.h" 35#include "content/public/browser/web_contents.h" 36#include "content/public/common/show_desktop_notification_params.h" 37#include "extensions/common/constants.h" 38#include "grit/browser_resources.h" 39#include "grit/chromium_strings.h" 40#include "grit/generated_resources.h" 41#include "grit/theme_resources.h" 42#include "net/base/escape.h" 43#include "third_party/WebKit/public/web/WebSecurityOrigin.h" 44#include "ui/base/l10n/l10n_util.h" 45#include "ui/base/resource/resource_bundle.h" 46#include "ui/message_center/message_center_util.h" 47#include "ui/message_center/notifier_settings.h" 48#include "ui/webui/web_ui_util.h" 49 50using content::BrowserThread; 51using content::RenderViewHost; 52using content::WebContents; 53using WebKit::WebNotificationPresenter; 54using WebKit::WebTextDirection; 55using WebKit::WebSecurityOrigin; 56 57const ContentSetting kDefaultSetting = CONTENT_SETTING_ASK; 58 59namespace { 60 61void ToggleListPrefItem(PrefService* prefs, const char* key, 62 const std::string& item, bool flag) { 63 ListPrefUpdate update(prefs, key); 64 base::ListValue* const list = update.Get(); 65 if (flag) { 66 // AppendIfNotPresent will delete |adding_value| when the same value 67 // already exists. 68 base::StringValue* const adding_value = new base::StringValue(item); 69 list->AppendIfNotPresent(adding_value); 70 } else { 71 base::StringValue removed_value(item); 72 list->Remove(removed_value, NULL); 73 } 74} 75 76void CopySetFromPrefToMemory(PrefService* prefs, const char* key, 77 std::set<std::string>* dst) { 78 dst->clear(); 79 const base::ListValue* pref_list = prefs->GetList(key); 80 for (size_t i = 0; i < pref_list->GetSize(); ++i) { 81 std::string element; 82 if (!pref_list->GetString(i, &element) && element.empty()) { 83 LOG(WARNING) << i << "-th element is not a string for " 84 << key; 85 continue; 86 } 87 dst->insert(element); 88 } 89} 90 91} // namespace 92 93// NotificationPermissionInfoBarDelegate -------------------------------------- 94 95// The delegate for the infobar shown when an origin requests notification 96// permissions. 97class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate { 98 public: 99 // Creates a notification permission delegate and adds it to 100 // |infobar_service|. 101 static void Create(InfoBarService* infobar_service, 102 DesktopNotificationService* notification_service, 103 const GURL& origin, 104 const string16& display_name, 105 int process_id, 106 int route_id, 107 int callback_context); 108 109 private: 110 NotificationPermissionInfoBarDelegate( 111 InfoBarService* infobar_service, 112 DesktopNotificationService* notification_service, 113 const GURL& origin, 114 const string16& display_name, 115 int process_id, 116 int route_id, 117 int callback_context); 118 virtual ~NotificationPermissionInfoBarDelegate(); 119 120 // ConfirmInfoBarDelegate: 121 virtual int GetIconID() const OVERRIDE; 122 virtual Type GetInfoBarType() const OVERRIDE; 123 virtual string16 GetMessageText() const OVERRIDE; 124 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 125 virtual bool Accept() OVERRIDE; 126 virtual bool Cancel() OVERRIDE; 127 128 // The origin we are asking for permissions on. 129 GURL origin_; 130 131 // The display name for the origin to be displayed. Will be different from 132 // origin_ for extensions. 133 string16 display_name_; 134 135 // The notification service to be used. 136 DesktopNotificationService* notification_service_; 137 138 // The callback information that tells us how to respond to javascript via 139 // the correct RenderView. 140 int process_id_; 141 int route_id_; 142 int callback_context_; 143 144 // Whether the user clicked one of the buttons. 145 bool action_taken_; 146 147 DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate); 148}; 149 150// static 151void NotificationPermissionInfoBarDelegate::Create( 152 InfoBarService* infobar_service, 153 DesktopNotificationService* notification_service, 154 const GURL& origin, 155 const string16& display_name, 156 int process_id, 157 int route_id, 158 int callback_context) { 159 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 160 new NotificationPermissionInfoBarDelegate( 161 infobar_service, notification_service, origin, display_name, 162 process_id, route_id, callback_context))); 163} 164 165NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate( 166 InfoBarService* infobar_service, 167 DesktopNotificationService* notification_service, 168 const GURL& origin, 169 const string16& display_name, 170 int process_id, 171 int route_id, 172 int callback_context) 173 : ConfirmInfoBarDelegate(infobar_service), 174 origin_(origin), 175 display_name_(display_name), 176 notification_service_(notification_service), 177 process_id_(process_id), 178 route_id_(route_id), 179 callback_context_(callback_context), 180 action_taken_(false) { 181} 182 183NotificationPermissionInfoBarDelegate:: 184 ~NotificationPermissionInfoBarDelegate() { 185 if (!action_taken_) 186 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1); 187 188 RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_); 189 if (host) 190 host->DesktopNotificationPermissionRequestDone(callback_context_); 191} 192 193int NotificationPermissionInfoBarDelegate::GetIconID() const { 194 return IDR_INFOBAR_DESKTOP_NOTIFICATIONS; 195} 196 197InfoBarDelegate::Type 198 NotificationPermissionInfoBarDelegate::GetInfoBarType() const { 199 return PAGE_ACTION_TYPE; 200} 201 202string16 NotificationPermissionInfoBarDelegate::GetMessageText() const { 203 return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS, 204 display_name_); 205} 206 207string16 NotificationPermissionInfoBarDelegate::GetButtonLabel( 208 InfoBarButton button) const { 209 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 210 IDS_NOTIFICATION_PERMISSION_YES : IDS_NOTIFICATION_PERMISSION_NO); 211} 212 213bool NotificationPermissionInfoBarDelegate::Accept() { 214 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1); 215 notification_service_->GrantPermission(origin_); 216 action_taken_ = true; 217 return true; 218} 219 220bool NotificationPermissionInfoBarDelegate::Cancel() { 221 UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1); 222 notification_service_->DenyPermission(origin_); 223 action_taken_ = true; 224 return true; 225} 226 227 228// DesktopNotificationService ------------------------------------------------- 229 230// static 231void DesktopNotificationService::RegisterUserPrefs( 232 user_prefs::PrefRegistrySyncable* registry) { 233 registry->RegisterListPref(prefs::kMessageCenterDisabledExtensionIds, 234 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 235 registry->RegisterListPref(prefs::kMessageCenterDisabledSystemComponentIds, 236 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 237} 238 239// static 240string16 DesktopNotificationService::CreateDataUrl( 241 const GURL& icon_url, const string16& title, const string16& body, 242 WebTextDirection dir) { 243 int resource; 244 std::vector<std::string> subst; 245 if (icon_url.is_valid()) { 246 resource = IDR_NOTIFICATION_ICON_HTML; 247 subst.push_back(icon_url.spec()); 248 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(title))); 249 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(body))); 250 // icon float position 251 subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ? 252 "right" : "left"); 253 } else if (title.empty() || body.empty()) { 254 resource = IDR_NOTIFICATION_1LINE_HTML; 255 string16 line = title.empty() ? body : title; 256 // Strings are div names in the template file. 257 string16 line_name = title.empty() ? ASCIIToUTF16("description") 258 : ASCIIToUTF16("title"); 259 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(line_name))); 260 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(line))); 261 } else { 262 resource = IDR_NOTIFICATION_2LINE_HTML; 263 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(title))); 264 subst.push_back(net::EscapeForHTML(UTF16ToUTF8(body))); 265 } 266 // body text direction 267 subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ? 268 "rtl" : "ltr"); 269 270 return CreateDataUrl(resource, subst); 271} 272 273// static 274string16 DesktopNotificationService::CreateDataUrl( 275 int resource, const std::vector<std::string>& subst) { 276 const base::StringPiece template_html( 277 ResourceBundle::GetSharedInstance().GetRawDataResource( 278 resource)); 279 280 if (template_html.empty()) { 281 NOTREACHED() << "unable to load template. ID: " << resource; 282 return string16(); 283 } 284 285 std::string data = ReplaceStringPlaceholders(template_html, subst, NULL); 286 return UTF8ToUTF16("data:text/html;charset=utf-8," + 287 net::EscapeQueryParamValue(data, false)); 288} 289 290// static 291std::string DesktopNotificationService::AddNotification( 292 const GURL& origin_url, 293 const string16& title, 294 const string16& message, 295 const GURL& icon_url, 296 const string16& replace_id, 297 NotificationDelegate* delegate, 298 Profile* profile) { 299 if (message_center::IsRichNotificationEnabled()) { 300 // For message center create a non-HTML notification with |icon_url|. 301 Notification notification(origin_url, icon_url, title, message, 302 WebKit::WebTextDirectionDefault, 303 string16(), replace_id, delegate); 304 g_browser_process->notification_ui_manager()->Add(notification, profile); 305 return notification.notification_id(); 306 } 307 308 // Generate a data URL embedding the icon URL, title, and message. 309 GURL content_url(CreateDataUrl( 310 icon_url, title, message, WebKit::WebTextDirectionDefault)); 311 Notification notification( 312 GURL(), content_url, string16(), replace_id, delegate); 313 g_browser_process->notification_ui_manager()->Add(notification, profile); 314 return notification.notification_id(); 315} 316 317// static 318std::string DesktopNotificationService::AddIconNotification( 319 const GURL& origin_url, 320 const string16& title, 321 const string16& message, 322 const gfx::Image& icon, 323 const string16& replace_id, 324 NotificationDelegate* delegate, 325 Profile* profile) { 326 327 if (message_center::IsRichNotificationEnabled()) { 328 // For message center create a non-HTML notification with |icon|. 329 Notification notification(origin_url, icon, title, message, 330 WebKit::WebTextDirectionDefault, 331 string16(), replace_id, delegate); 332 g_browser_process->notification_ui_manager()->Add(notification, profile); 333 return notification.notification_id(); 334 } 335 336 GURL icon_url; 337 if (!icon.IsEmpty()) 338 icon_url = GURL(webui::GetBitmapDataUrl(*icon.ToSkBitmap())); 339 return AddNotification( 340 origin_url, title, message, icon_url, replace_id, delegate, profile); 341} 342 343// static 344void DesktopNotificationService::RemoveNotification( 345 const std::string& notification_id) { 346 g_browser_process->notification_ui_manager()->CancelById(notification_id); 347} 348 349DesktopNotificationService::DesktopNotificationService( 350 Profile* profile, 351 NotificationUIManager* ui_manager) 352 : profile_(profile), 353 ui_manager_(ui_manager) { 354 OnDisabledExtensionIdsChanged(); 355 OnDisabledSystemComponentIdsChanged(); 356 disabled_extension_id_pref_.Init( 357 prefs::kMessageCenterDisabledExtensionIds, 358 profile_->GetPrefs(), 359 base::Bind( 360 &DesktopNotificationService::OnDisabledExtensionIdsChanged, 361 base::Unretained(this))); 362 disabled_system_component_id_pref_.Init( 363 prefs::kMessageCenterDisabledSystemComponentIds, 364 profile_->GetPrefs(), 365 base::Bind( 366 &DesktopNotificationService::OnDisabledSystemComponentIdsChanged, 367 base::Unretained(this))); 368 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 369 content::Source<Profile>(profile_)); 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, 467 DisplayNameForOriginInProcessId(origin, process_id), 468 process_id, 469 route_id, 470 callback_context); 471 return; 472 } 473 } 474 475 // Notify renderer immediately. 476 RenderViewHost* host = RenderViewHost::FromID(process_id, route_id); 477 if (host) 478 host->DesktopNotificationPermissionRequestDone(callback_context); 479} 480 481#if !defined(OS_WIN) 482void DesktopNotificationService::ShowNotification( 483 const Notification& notification) { 484 GetUIManager()->Add(notification, profile_); 485} 486 487bool DesktopNotificationService::CancelDesktopNotification( 488 int process_id, int route_id, int notification_id) { 489 scoped_refptr<NotificationObjectProxy> proxy( 490 new NotificationObjectProxy(process_id, route_id, notification_id, 491 false)); 492 return GetUIManager()->CancelById(proxy->id()); 493} 494#endif // OS_WIN 495 496bool DesktopNotificationService::ShowDesktopNotification( 497 const content::ShowDesktopNotificationHostMsgParams& params, 498 int process_id, int route_id, DesktopNotificationSource source) { 499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 500 const GURL& origin = params.origin; 501 NotificationObjectProxy* proxy = 502 new NotificationObjectProxy(process_id, route_id, 503 params.notification_id, 504 source == WorkerNotification); 505 506 string16 display_source = DisplayNameForOriginInProcessId(origin, process_id); 507 if (params.is_html) { 508 ShowNotification(Notification(origin, params.contents_url, display_source, 509 params.replace_id, proxy)); 510 } else { 511 Notification notification(origin, params.icon_url, params.title, 512 params.body, params.direction, display_source, params.replace_id, 513 proxy); 514 // The webkit notification doesn't timeout. 515 notification.set_never_timeout(true); 516 ShowNotification(notification); 517 } 518 return true; 519} 520 521string16 DesktopNotificationService::DisplayNameForOriginInProcessId( 522 const GURL& origin, int process_id) { 523 // If the source is an extension, lookup the display name. 524 // Message center prefers to use extension name if the notification 525 // is allowed by an extension. 526 if (NotificationUIManager::DelegatesToMessageCenter() || 527 origin.SchemeIs(extensions::kExtensionScheme)) { 528 ExtensionInfoMap* extension_info_map = 529 extensions::ExtensionSystem::Get(profile_)->info_map(); 530 if (extension_info_map) { 531 ExtensionSet extensions; 532 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin( 533 origin, process_id, extensions::APIPermission::kNotification, 534 &extensions); 535 for (ExtensionSet::const_iterator iter = extensions.begin(); 536 iter != extensions.end(); ++iter) { 537 if (IsExtensionEnabled((*iter)->id())) 538 return UTF8ToUTF16((*iter)->name()); 539 } 540 } 541 } 542 return UTF8ToUTF16(origin.host()); 543} 544 545void DesktopNotificationService::NotifySettingsChange() { 546 content::NotificationService::current()->Notify( 547 chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, 548 content::Source<DesktopNotificationService>(this), 549 content::NotificationService::NoDetails()); 550} 551 552NotificationUIManager* DesktopNotificationService::GetUIManager() { 553 // We defer setting ui_manager_ to the global singleton until we need it 554 // in order to avoid UI dependent construction during startup. 555 if (!ui_manager_) 556 ui_manager_ = g_browser_process->notification_ui_manager(); 557 return ui_manager_; 558} 559 560bool DesktopNotificationService::IsExtensionEnabled(const std::string& id) { 561 return disabled_extension_ids_.find(id) == disabled_extension_ids_.end(); 562} 563 564void DesktopNotificationService::SetExtensionEnabled( 565 const std::string& id, bool enabled) { 566 // Do not touch |disabled_extension_ids_|. It will be updated at 567 // OnDisabledExtensionIdsChanged() which will be called when the pref changes. 568 ToggleListPrefItem( 569 profile_->GetPrefs(), 570 prefs::kMessageCenterDisabledExtensionIds, 571 id, 572 !enabled); 573} 574 575void DesktopNotificationService::OnDisabledExtensionIdsChanged() { 576 CopySetFromPrefToMemory(profile_->GetPrefs(), 577 prefs::kMessageCenterDisabledExtensionIds, 578 &disabled_extension_ids_); 579} 580 581bool DesktopNotificationService::IsSystemComponentEnabled( 582 message_center::Notifier::SystemComponentNotifierType type) { 583 return disabled_system_component_ids_.find(message_center::ToString(type)) == 584 disabled_system_component_ids_.end(); 585} 586 587void DesktopNotificationService::SetSystemComponentEnabled( 588 message_center::Notifier::SystemComponentNotifierType type, bool enabled) { 589 // Do not touch |disabled_extension_ids_|. It will be updated at 590 // OnDisabledExtensionIdsChanged() which will be called when the pref changes. 591 ToggleListPrefItem( 592 profile_->GetPrefs(), 593 prefs::kMessageCenterDisabledSystemComponentIds, 594 message_center::ToString(type), 595 !enabled); 596} 597 598void DesktopNotificationService::OnDisabledSystemComponentIdsChanged() { 599 disabled_system_component_ids_.clear(); 600 CopySetFromPrefToMemory(profile_->GetPrefs(), 601 prefs::kMessageCenterDisabledSystemComponentIds, 602 &disabled_system_component_ids_); 603} 604 605WebKit::WebNotificationPresenter::Permission 606 DesktopNotificationService::HasPermission(const GURL& origin) { 607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 608 HostContentSettingsMap* host_content_settings_map = 609 profile_->GetHostContentSettingsMap(); 610 ContentSetting setting = host_content_settings_map->GetContentSetting( 611 origin, 612 origin, 613 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, 614 NO_RESOURCE_IDENTIFIER); 615 616 if (setting == CONTENT_SETTING_ALLOW) 617 return WebKit::WebNotificationPresenter::PermissionAllowed; 618 if (setting == CONTENT_SETTING_BLOCK) 619 return WebKit::WebNotificationPresenter::PermissionDenied; 620 if (setting == CONTENT_SETTING_ASK) 621 return WebKit::WebNotificationPresenter::PermissionNotAllowed; 622 NOTREACHED() << "Invalid notifications settings value: " << setting; 623 return WebKit::WebNotificationPresenter::PermissionNotAllowed; 624} 625 626void DesktopNotificationService::Observe( 627 int type, 628 const content::NotificationSource& source, 629 const content::NotificationDetails& details) { 630 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNINSTALLED, type); 631 632 extensions::Extension* extension = 633 content::Details<extensions::Extension>(details).ptr(); 634 if (IsExtensionEnabled(extension->id())) 635 return; 636 637 SetExtensionEnabled(extension->id(), true); 638} 639