desktop_notification_service.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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/threading/thread.h"
9#include "base/utf_string_conversions.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/Source/WebKit/chromium/public/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 gfx::Image* GetIcon() 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
193gfx::Image* NotificationPermissionInfoBarDelegate::GetIcon() const {
194  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
195      IDR_INFOBAR_DESKTOP_NOTIFICATIONS);
196}
197
198InfoBarDelegate::Type
199    NotificationPermissionInfoBarDelegate::GetInfoBarType() const {
200  return PAGE_ACTION_TYPE;
201}
202
203string16 NotificationPermissionInfoBarDelegate::GetMessageText() const {
204  return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
205                                    display_name_);
206}
207
208string16 NotificationPermissionInfoBarDelegate::GetButtonLabel(
209    InfoBarButton button) const {
210  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
211      IDS_NOTIFICATION_PERMISSION_YES : IDS_NOTIFICATION_PERMISSION_NO);
212}
213
214bool NotificationPermissionInfoBarDelegate::Accept() {
215  UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
216  notification_service_->GrantPermission(origin_);
217  action_taken_ = true;
218  return true;
219}
220
221bool NotificationPermissionInfoBarDelegate::Cancel() {
222  UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
223  notification_service_->DenyPermission(origin_);
224  action_taken_ = true;
225  return true;
226}
227
228
229// DesktopNotificationService -------------------------------------------------
230
231// static
232void DesktopNotificationService::RegisterUserPrefs(
233    user_prefs::PrefRegistrySyncable* registry) {
234  registry->RegisterListPref(prefs::kMessageCenterDisabledExtensionIds,
235                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
236  registry->RegisterListPref(prefs::kMessageCenterDisabledSystemComponentIds,
237                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
238}
239
240// static
241string16 DesktopNotificationService::CreateDataUrl(
242    const GURL& icon_url, const string16& title, const string16& body,
243    WebTextDirection dir) {
244  int resource;
245  std::vector<std::string> subst;
246  if (icon_url.is_valid()) {
247    resource = IDR_NOTIFICATION_ICON_HTML;
248    subst.push_back(icon_url.spec());
249    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(title)));
250    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(body)));
251    // icon float position
252    subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ?
253                    "right" : "left");
254  } else if (title.empty() || body.empty()) {
255    resource = IDR_NOTIFICATION_1LINE_HTML;
256    string16 line = title.empty() ? body : title;
257    // Strings are div names in the template file.
258    string16 line_name = title.empty() ? ASCIIToUTF16("description")
259                                       : ASCIIToUTF16("title");
260    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(line_name)));
261    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(line)));
262  } else {
263    resource = IDR_NOTIFICATION_2LINE_HTML;
264    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(title)));
265    subst.push_back(net::EscapeForHTML(UTF16ToUTF8(body)));
266  }
267  // body text direction
268  subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ?
269                  "rtl" : "ltr");
270
271  return CreateDataUrl(resource, subst);
272}
273
274// static
275string16 DesktopNotificationService::CreateDataUrl(
276    int resource, const std::vector<std::string>& subst) {
277  const base::StringPiece template_html(
278      ResourceBundle::GetSharedInstance().GetRawDataResource(
279          resource));
280
281  if (template_html.empty()) {
282    NOTREACHED() << "unable to load template. ID: " << resource;
283    return string16();
284  }
285
286  std::string data = ReplaceStringPlaceholders(template_html, subst, NULL);
287  return UTF8ToUTF16("data:text/html;charset=utf-8," +
288                      net::EscapeQueryParamValue(data, false));
289}
290
291// static
292std::string DesktopNotificationService::AddNotification(
293    const GURL& origin_url,
294    const string16& title,
295    const string16& message,
296    const GURL& icon_url,
297    const string16& replace_id,
298    NotificationDelegate* delegate,
299    Profile* profile) {
300  if (message_center::IsRichNotificationEnabled()) {
301    // For message center create a non-HTML notification with |icon_url|.
302    Notification notification(origin_url, icon_url, title, message,
303                              WebKit::WebTextDirectionDefault,
304                              string16(), replace_id, delegate);
305    g_browser_process->notification_ui_manager()->Add(notification, profile);
306    return notification.notification_id();
307  }
308
309  // Generate a data URL embedding the icon URL, title, and message.
310  GURL content_url(CreateDataUrl(
311      icon_url, title, message, WebKit::WebTextDirectionDefault));
312  Notification notification(
313      GURL(), content_url, string16(), replace_id, delegate);
314  g_browser_process->notification_ui_manager()->Add(notification, profile);
315  return notification.notification_id();
316}
317
318// static
319std::string DesktopNotificationService::AddIconNotification(
320    const GURL& origin_url,
321    const string16& title,
322    const string16& message,
323    const gfx::Image& icon,
324    const string16& replace_id,
325    NotificationDelegate* delegate,
326    Profile* profile) {
327
328  if (message_center::IsRichNotificationEnabled()) {
329    // For message center create a non-HTML notification with |icon|.
330    Notification notification(origin_url, icon, title, message,
331                              WebKit::WebTextDirectionDefault,
332                              string16(), replace_id, delegate);
333    g_browser_process->notification_ui_manager()->Add(notification, profile);
334    return notification.notification_id();
335  }
336
337  GURL icon_url;
338  if (!icon.IsEmpty())
339    icon_url = GURL(webui::GetBitmapDataUrl(*icon.ToSkBitmap()));
340  return AddNotification(
341      origin_url, title, message, icon_url, replace_id, delegate, profile);
342}
343
344// static
345void DesktopNotificationService::RemoveNotification(
346    const std::string& notification_id) {
347    g_browser_process->notification_ui_manager()->CancelById(notification_id);
348}
349
350DesktopNotificationService::DesktopNotificationService(
351    Profile* profile,
352    NotificationUIManager* ui_manager)
353    : profile_(profile),
354      ui_manager_(ui_manager) {
355  OnDisabledExtensionIdsChanged();
356  OnDisabledSystemComponentIdsChanged();
357  disabled_extension_id_pref_.Init(
358      prefs::kMessageCenterDisabledExtensionIds,
359      profile_->GetPrefs(),
360      base::Bind(
361          &DesktopNotificationService::OnDisabledExtensionIdsChanged,
362          base::Unretained(this)));
363  disabled_system_component_id_pref_.Init(
364      prefs::kMessageCenterDisabledSystemComponentIds,
365      profile_->GetPrefs(),
366      base::Bind(
367          &DesktopNotificationService::OnDisabledSystemComponentIdsChanged,
368          base::Unretained(this)));
369}
370
371DesktopNotificationService::~DesktopNotificationService() {
372}
373
374void DesktopNotificationService::GrantPermission(const GURL& origin) {
375  ContentSettingsPattern primary_pattern =
376      ContentSettingsPattern::FromURLNoWildcard(origin);
377  profile_->GetHostContentSettingsMap()->SetContentSetting(
378      primary_pattern,
379      ContentSettingsPattern::Wildcard(),
380      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
381      NO_RESOURCE_IDENTIFIER,
382      CONTENT_SETTING_ALLOW);
383}
384
385void DesktopNotificationService::DenyPermission(const GURL& origin) {
386  ContentSettingsPattern primary_pattern =
387      ContentSettingsPattern::FromURLNoWildcard(origin);
388  profile_->GetHostContentSettingsMap()->SetContentSetting(
389      primary_pattern,
390      ContentSettingsPattern::Wildcard(),
391      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
392      NO_RESOURCE_IDENTIFIER,
393      CONTENT_SETTING_BLOCK);
394}
395
396ContentSetting DesktopNotificationService::GetDefaultContentSetting(
397    std::string* provider_id) {
398  return profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
399      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, provider_id);
400}
401
402void DesktopNotificationService::SetDefaultContentSetting(
403    ContentSetting setting) {
404  profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
405      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
406}
407
408void DesktopNotificationService::ResetToDefaultContentSetting() {
409  profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
410      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_DEFAULT);
411}
412
413void DesktopNotificationService::GetNotificationsSettings(
414    ContentSettingsForOneType* settings) {
415  profile_->GetHostContentSettingsMap()->GetSettingsForOneType(
416      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
417      NO_RESOURCE_IDENTIFIER,
418      settings);
419}
420
421void DesktopNotificationService::ClearSetting(
422    const ContentSettingsPattern& pattern) {
423  profile_->GetHostContentSettingsMap()->SetContentSetting(
424      pattern,
425      ContentSettingsPattern::Wildcard(),
426      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
427      NO_RESOURCE_IDENTIFIER,
428      CONTENT_SETTING_DEFAULT);
429}
430
431void DesktopNotificationService::ResetAllOrigins() {
432  profile_->GetHostContentSettingsMap()->ClearSettingsForOneType(
433      CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
434}
435
436ContentSetting DesktopNotificationService::GetContentSetting(
437    const GURL& origin) {
438  return profile_->GetHostContentSettingsMap()->GetContentSetting(
439      origin,
440      origin,
441      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
442      NO_RESOURCE_IDENTIFIER);
443}
444
445void DesktopNotificationService::RequestPermission(
446    const GURL& origin, int process_id, int route_id, int callback_context,
447    WebContents* contents) {
448  // If |origin| hasn't been seen before and the default content setting for
449  // notifications is "ask", show an infobar.
450  // The cache can only answer queries on the IO thread once it's initialized,
451  // so don't ask the cache.
452  ContentSetting setting = GetContentSetting(origin);
453  if (setting == CONTENT_SETTING_ASK) {
454    // Show an info bar requesting permission.
455    InfoBarService* infobar_service =
456        InfoBarService::FromWebContents(contents);
457    // |infobar_service| may be NULL, e.g., if this request originated in a
458    // browser action popup, extension background page, or any HTML that runs
459    // outside of a tab.
460    if (infobar_service) {
461      NotificationPermissionInfoBarDelegate::Create(
462          infobar_service,
463          DesktopNotificationServiceFactory::GetForProfile(
464              Profile::FromBrowserContext(contents->GetBrowserContext())),
465          origin,
466          DisplayNameForOriginInProcessId(origin, process_id),
467          process_id,
468          route_id,
469          callback_context);
470      return;
471    }
472  }
473
474  // Notify renderer immediately.
475  RenderViewHost* host = RenderViewHost::FromID(process_id, route_id);
476  if (host)
477    host->DesktopNotificationPermissionRequestDone(callback_context);
478}
479
480#if !defined(OS_WIN)
481void DesktopNotificationService::ShowNotification(
482    const Notification& notification) {
483  GetUIManager()->Add(notification, profile_);
484}
485
486bool DesktopNotificationService::CancelDesktopNotification(
487    int process_id, int route_id, int notification_id) {
488  scoped_refptr<NotificationObjectProxy> proxy(
489      new NotificationObjectProxy(process_id, route_id, notification_id,
490                                  false));
491  return GetUIManager()->CancelById(proxy->id());
492}
493#endif  // OS_WIN
494
495bool DesktopNotificationService::ShowDesktopNotification(
496    const content::ShowDesktopNotificationHostMsgParams& params,
497    int process_id, int route_id, DesktopNotificationSource source) {
498  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
499  const GURL& origin = params.origin;
500  NotificationObjectProxy* proxy =
501      new NotificationObjectProxy(process_id, route_id,
502                                  params.notification_id,
503                                  source == WorkerNotification);
504
505  string16 display_source = DisplayNameForOriginInProcessId(origin, process_id);
506  if (params.is_html) {
507    ShowNotification(Notification(origin, params.contents_url, display_source,
508        params.replace_id, proxy));
509  } else {
510    Notification notification(origin, params.icon_url, params.title,
511        params.body, params.direction, display_source, params.replace_id,
512        proxy);
513    // The webkit notification doesn't timeout.
514    notification.DisableTimeout();
515    ShowNotification(notification);
516  }
517  return true;
518}
519
520string16 DesktopNotificationService::DisplayNameForOriginInProcessId(
521    const GURL& origin, int process_id) {
522  // If the source is an extension, lookup the display name.
523  // Message center prefers to use extension name if the notification
524  // is allowed by an extension.
525  if (NotificationUIManager::DelegatesToMessageCenter() ||
526      origin.SchemeIs(extensions::kExtensionScheme)) {
527    ExtensionInfoMap* extension_info_map =
528        extensions::ExtensionSystem::Get(profile_)->info_map();
529    if (extension_info_map) {
530      ExtensionSet extensions;
531      extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
532          origin, process_id, extensions::APIPermission::kNotification,
533          &extensions);
534      for (ExtensionSet::const_iterator iter = extensions.begin();
535           iter != extensions.end(); ++iter) {
536        if (IsExtensionEnabled((*iter)->id()))
537          return UTF8ToUTF16((*iter)->name());
538      }
539    }
540  }
541  return UTF8ToUTF16(origin.host());
542}
543
544void DesktopNotificationService::NotifySettingsChange() {
545  content::NotificationService::current()->Notify(
546      chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
547      content::Source<DesktopNotificationService>(this),
548      content::NotificationService::NoDetails());
549}
550
551NotificationUIManager* DesktopNotificationService::GetUIManager() {
552  // We defer setting ui_manager_ to the global singleton until we need it
553  // in order to avoid UI dependent construction during startup.
554  if (!ui_manager_)
555    ui_manager_ = g_browser_process->notification_ui_manager();
556  return ui_manager_;
557}
558
559bool DesktopNotificationService::IsExtensionEnabled(const std::string& id) {
560  return disabled_extension_ids_.find(id) == disabled_extension_ids_.end();
561}
562
563void DesktopNotificationService::SetExtensionEnabled(
564    const std::string& id, bool enabled) {
565  // Do not touch |disabled_extension_ids_|. It will be updated at
566  // OnDisabledExtensionIdsChanged() which will be called when the pref changes.
567  ToggleListPrefItem(
568      profile_->GetPrefs(),
569      prefs::kMessageCenterDisabledExtensionIds,
570      id,
571      !enabled);
572}
573
574void DesktopNotificationService::OnDisabledExtensionIdsChanged() {
575  CopySetFromPrefToMemory(profile_->GetPrefs(),
576                          prefs::kMessageCenterDisabledExtensionIds,
577                          &disabled_extension_ids_);
578}
579
580bool DesktopNotificationService::IsSystemComponentEnabled(
581    message_center::Notifier::SystemComponentNotifierType type) {
582  return disabled_system_component_ids_.find(message_center::ToString(type)) ==
583         disabled_system_component_ids_.end();
584}
585
586void DesktopNotificationService::SetSystemComponentEnabled(
587    message_center::Notifier::SystemComponentNotifierType type, bool enabled) {
588  // Do not touch |disabled_extension_ids_|. It will be updated at
589  // OnDisabledExtensionIdsChanged() which will be called when the pref changes.
590  ToggleListPrefItem(
591      profile_->GetPrefs(),
592      prefs::kMessageCenterDisabledSystemComponentIds,
593      message_center::ToString(type),
594      !enabled);
595}
596
597void DesktopNotificationService::OnDisabledSystemComponentIdsChanged() {
598  disabled_system_component_ids_.clear();
599  CopySetFromPrefToMemory(profile_->GetPrefs(),
600                          prefs::kMessageCenterDisabledSystemComponentIds,
601                          &disabled_system_component_ids_);
602}
603
604WebKit::WebNotificationPresenter::Permission
605    DesktopNotificationService::HasPermission(const GURL& origin) {
606  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
607  HostContentSettingsMap* host_content_settings_map =
608      profile_->GetHostContentSettingsMap();
609  ContentSetting setting = host_content_settings_map->GetContentSetting(
610      origin,
611      origin,
612      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
613      NO_RESOURCE_IDENTIFIER);
614
615  if (setting == CONTENT_SETTING_ALLOW)
616    return WebKit::WebNotificationPresenter::PermissionAllowed;
617  if (setting == CONTENT_SETTING_BLOCK)
618    return WebKit::WebNotificationPresenter::PermissionDenied;
619  if (setting == CONTENT_SETTING_ASK)
620    return WebKit::WebNotificationPresenter::PermissionNotAllowed;
621  NOTREACHED() << "Invalid notifications settings value: " << setting;
622  return WebKit::WebNotificationPresenter::PermissionNotAllowed;
623}
624