15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/notifications/desktop_notification_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/notifications/desktop_notification_profile_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/notifications/desktop_notification_service_factory.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/notifications/notification.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/notifications/notification_object_proxy.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/notifications/notification_ui_manager.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/browser/desktop_notification_delegate.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "content/public/browser/render_frame_host.h"
300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "content/public/browser/render_process_host.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/show_desktop_notification_params.h"
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/webui/web_ui_util.h"
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/notifier_settings.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(ENABLE_EXTENSIONS)
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/extensions/api/notifications/notifications_api.h"
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/extensions/extension_service.h"
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/event_router.h"
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/extension_system.h"
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_util.h"
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/info_map.h"
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/constants.h"
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/extension.h"
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/extension_set.h"
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochusing blink::WebTextDirection;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing message_center::NotifierId;
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid CancelNotification(const std::string& id) {
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  g_browser_process->notification_ui_manager()->CancelById(id);
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DesktopNotificationService -------------------------------------------------
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DesktopNotificationService::RegisterProfilePrefs(
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registry->RegisterListPref(
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kMessageCenterDisabledExtensionIds,
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registry->RegisterListPref(
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kMessageCenterDisabledSystemComponentIds,
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DesktopNotificationService::AddIconNotification(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url,
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& title,
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& message,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Image& icon,
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& replace_id,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotificationDelegate* delegate,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile) {
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Notification notification(message_center::NOTIFICATION_TYPE_SIMPLE,
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            origin_url,
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            title,
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            message,
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            icon,
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                            blink::WebTextDirectionDefault,
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            message_center::NotifierId(origin_url),
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            base::string16(),
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            replace_id,
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            message_center::RichNotificationData(),
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            delegate);
97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  g_browser_process->notification_ui_manager()->Add(notification, profile);
986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return notification.delegate_id();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciDesktopNotificationService::DesktopNotificationService(Profile* profile)
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS),
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      profile_(profile),
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extension_registry_observer_(this),
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_factory_(this) {
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  OnStringListPrefChanged(
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      prefs::kMessageCenterDisabledExtensionIds, &disabled_extension_ids_);
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  OnStringListPrefChanged(
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      prefs::kMessageCenterDisabledSystemComponentIds,
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &disabled_system_component_ids_);
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  disabled_extension_id_pref_.Init(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prefs::kMessageCenterDisabledExtensionIds,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_->GetPrefs(),
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          &DesktopNotificationService::OnStringListPrefChanged,
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(this),
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(prefs::kMessageCenterDisabledExtensionIds),
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(&disabled_extension_ids_)));
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  disabled_system_component_id_pref_.Init(
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prefs::kMessageCenterDisabledSystemComponentIds,
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      profile_->GetPrefs(),
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          &DesktopNotificationService::OnStringListPrefChanged,
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(this),
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds),
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Unretained(&disabled_system_component_ids_)));
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  extension_registry_observer_.Add(
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::ExtensionRegistry::Get(profile_));
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DesktopNotificationService::~DesktopNotificationService() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void DesktopNotificationService::RequestNotificationPermission(
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content::WebContents* web_contents,
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const PermissionRequestID& request_id,
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const GURL& requesting_frame,
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool user_gesture,
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const NotificationPermissionCallback& callback) {
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  RequestPermission(
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      web_contents,
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      request_id,
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      requesting_frame,
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      user_gesture,
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&DesktopNotificationService::OnNotificationPermissionRequested,
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 weak_factory_.GetWeakPtr(),
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 callback));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DesktopNotificationService::ShowDesktopNotification(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::ShowDesktopNotificationHostMsgParams& params,
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    content::RenderFrameHost* render_frame_host,
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<content::DesktopNotificationDelegate> delegate,
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::Closure* cancel_callback) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL& origin = params.origin;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotificationObjectProxy* proxy =
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new NotificationObjectProxy(render_frame_host, delegate.Pass());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::string16 display_source = DisplayNameForOriginInProcessId(
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      origin, render_frame_host->GetProcess()->GetID());
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Notification notification(origin, params.icon_url, params.title,
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      params.body, params.direction, display_source, params.replace_id,
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      proxy);
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The webkit notification doesn't timeout.
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notification.set_never_timeout(true);
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  g_browser_process->notification_ui_manager()->Add(notification, profile_);
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (cancel_callback)
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    *cancel_callback = base::Bind(&CancelNotification, proxy->id());
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DesktopNotificationProfileUtil::UsePermission(profile_, origin);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 DesktopNotificationService::DisplayNameForOriginInProcessId(
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& origin, int process_id) {
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(ENABLE_EXTENSIONS)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the source is an extension, lookup the display name.
185a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (origin.SchemeIs(extensions::kExtensionScheme)) {
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    extensions::InfoMap* extension_info_map =
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extensions::ExtensionSystem::Get(profile_)->info_map();
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (extension_info_map) {
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extensions::ExtensionSet extensions;
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          origin,
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          process_id,
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          extensions::APIPermission::kNotifications,
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &extensions);
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           iter != extensions.end(); ++iter) {
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        NotifierId notifier_id(NotifierId::APPLICATION, (*iter)->id());
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if (IsNotifierEnabled(notifier_id))
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return base::UTF8ToUTF16((*iter)->name());
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::UTF8ToUTF16(origin.host());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DesktopNotificationService::IsNotifierEnabled(
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const NotifierId& notifier_id) {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (notifier_id.type) {
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case NotifierId::APPLICATION:
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return disabled_extension_ids_.find(notifier_id.id) ==
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          disabled_extension_ids_.end();
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case NotifierId::WEB_PAGE:
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return DesktopNotificationProfileUtil::GetContentSetting(
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          profile_, notifier_id.url) == CONTENT_SETTING_ALLOW;
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case NotifierId::SYSTEM_COMPONENT:
218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_CHROMEOS)
219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return disabled_system_component_ids_.find(notifier_id.id) ==
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          disabled_system_component_ids_.end();
221424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#else
222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // We do not disable system component notifications.
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return true;
224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  NOTREACHED();
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return false;
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid DesktopNotificationService::SetNotifierEnabled(
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const NotifierId& notifier_id,
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool enabled) {
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(NotifierId::WEB_PAGE, notifier_id.type);
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool add_new_item = false;
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const char* pref_name = NULL;
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::StringValue> id;
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (notifier_id.type) {
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case NotifierId::APPLICATION:
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      pref_name = prefs::kMessageCenterDisabledExtensionIds;
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      add_new_item = !enabled;
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      id.reset(new base::StringValue(notifier_id.id));
2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FirePermissionLevelChangedEvent(notifier_id, enabled);
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case NotifierId::SYSTEM_COMPONENT:
247424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_CHROMEOS)
248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      pref_name = prefs::kMessageCenterDisabledSystemComponentIds;
249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      add_new_item = !enabled;
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      id.reset(new base::StringValue(notifier_id.id));
251424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#else
252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return;
253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default:
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NOTREACHED();
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(pref_name != NULL);
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ListPrefUpdate update(profile_->GetPrefs(), pref_name);
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::ListValue* const list = update.Get();
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (add_new_item) {
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // AppendIfNotPresent will delete |adding_value| when the same value
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // already exists.
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    list->AppendIfNotPresent(id.release());
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else {
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    list->Remove(*id, NULL);
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid DesktopNotificationService::OnStringListPrefChanged(
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const char* pref_name, std::set<std::string>* ids_field) {
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ids_field->clear();
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Separate GetPrefs()->GetList() to analyze the crash. See crbug.com/322320
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const PrefService* pref_service = profile_->GetPrefs();
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(pref_service);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::ListValue* pref_list = pref_service->GetList(pref_name);
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < pref_list->GetSize(); ++i) {
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string element;
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (pref_list->GetString(i, &element) && !element.empty())
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ids_field->insert(element);
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      LOG(WARNING) << i << "-th element is not a string for " << pref_name;
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void DesktopNotificationService::OnExtensionUninstalled(
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content::BrowserContext* browser_context,
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const extensions::Extension* extension,
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    extensions::UninstallReason reason) {
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (IsNotifierEnabled(notifier_id))
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The settings for ephemeral apps will be persisted across cache evictions.
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (extensions::util::IsEphemeralApp(extension->id(), profile_))
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetNotifierEnabled(notifier_id, true);
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Unlike other permission types, granting a notification for a given origin
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// will not take into account the |embedder_origin|, it will only be based
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// on the requesting iframe origin.
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// TODO(mukai) Consider why notifications behave differently than
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// other permissions. crbug.com/416894
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DesktopNotificationService::UpdateContentSetting(
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& requesting_origin,
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& embedder_origin,
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool allowed) {
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (allowed) {
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DesktopNotificationProfileUtil::GrantPermission(
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        profile_, requesting_origin);
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DesktopNotificationProfileUtil::DenyPermission(profile_, requesting_origin);
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void DesktopNotificationService::OnNotificationPermissionRequested(
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const NotificationPermissionCallback& callback, bool allowed) {
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  blink::WebNotificationPermission permission = allowed ?
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      blink::WebNotificationPermissionAllowed :
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      blink::WebNotificationPermissionDenied;
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  callback.Run(permission);
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void DesktopNotificationService::FirePermissionLevelChangedEvent(
3311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const NotifierId& notifier_id, bool enabled) {
3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(ENABLE_EXTENSIONS)
3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK_EQ(NotifierId::APPLICATION, notifier_id.type);
3341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  extensions::api::notifications::PermissionLevel permission =
3351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
3361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)              : extensions::api::notifications::PERMISSION_LEVEL_DENIED;
3371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<base::ListValue> args(new base::ListValue());
3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  args->Append(new base::StringValue(
3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      extensions::api::notifications::ToString(permission)));
3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      extensions::api::notifications::OnPermissionLevelChanged::kEventName,
3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      args.Pass()));
3430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extensions::EventRouter::Get(profile_)
3440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ->DispatchEventToExtension(notifier_id.id, event.Pass());
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Tell the IO thread that this extension's permission for notifications
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // has changed.
348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  extensions::InfoMap* extension_info_map =
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->info_map();
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserThread::PostTask(
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&extensions::InfoMap::SetNotificationsDisabled,
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 extension_info_map, notifier_id.id, !enabled));
3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
3551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
356