Revert of Remove OneClickSigninHelper since it is no longer used. (patchset #5 id...
[chromium-blink-merge.git] / chrome / browser / notifications / platform_notification_service_impl.cc
blob8b8136942c41f37b3988226f8d5eb8a3a393cb3c
1 // Copyright 2014 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.
5 #include "chrome/browser/notifications/platform_notification_service_impl.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
11 #include "chrome/browser/notifications/notification_object_proxy.h"
12 #include "chrome/browser/notifications/notification_ui_manager.h"
13 #include "chrome/browser/notifications/persistent_notification_delegate.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_io_data.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/content_settings/core/browser/host_content_settings_map.h"
18 #include "components/content_settings/core/common/content_settings.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/desktop_notification_delegate.h"
21 #include "content/public/browser/notification_event_dispatcher.h"
22 #include "content/public/common/platform_notification_data.h"
23 #include "net/base/net_util.h"
24 #include "ui/message_center/notifier_settings.h"
25 #include "url/url_constants.h"
27 #if defined(ENABLE_EXTENSIONS)
28 #include "chrome/browser/notifications/desktop_notification_service.h"
29 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "extensions/browser/extension_system.h"
32 #include "extensions/browser/info_map.h"
33 #include "extensions/common/constants.h"
34 #include "extensions/common/extension_set.h"
35 #include "extensions/common/permissions/api_permission.h"
36 #include "extensions/common/permissions/permissions_data.h"
37 #endif
39 using content::BrowserThread;
40 using message_center::NotifierId;
42 namespace {
44 void CancelNotification(const std::string& id, ProfileID profile_id) {
45 PlatformNotificationServiceImpl::GetInstance()
46 ->GetNotificationUIManager()->CancelById(id, profile_id);
49 } // namespace
51 // static
52 PlatformNotificationServiceImpl*
53 PlatformNotificationServiceImpl::GetInstance() {
54 return Singleton<PlatformNotificationServiceImpl>::get();
57 PlatformNotificationServiceImpl::PlatformNotificationServiceImpl()
58 : notification_ui_manager_for_tests_(nullptr) {}
60 PlatformNotificationServiceImpl::~PlatformNotificationServiceImpl() {}
62 void PlatformNotificationServiceImpl::OnPersistentNotificationClick(
63 content::BrowserContext* browser_context,
64 int64 service_worker_registration_id,
65 const std::string& notification_id,
66 const GURL& origin,
67 const content::PlatformNotificationData& notification_data,
68 const base::Callback<void(content::PersistentNotificationStatus)>&
69 callback) const {
70 DCHECK_CURRENTLY_ON(BrowserThread::UI);
71 content::NotificationEventDispatcher::GetInstance()
72 ->DispatchNotificationClickEvent(
73 browser_context,
74 origin,
75 service_worker_registration_id,
76 notification_id,
77 notification_data,
78 callback);
81 blink::WebNotificationPermission
82 PlatformNotificationServiceImpl::CheckPermissionOnUIThread(
83 content::BrowserContext* browser_context,
84 const GURL& origin,
85 int render_process_id) {
86 DCHECK_CURRENTLY_ON(BrowserThread::UI);
88 Profile* profile = Profile::FromBrowserContext(browser_context);
89 DCHECK(profile);
91 #if defined(ENABLE_EXTENSIONS)
92 // Extensions support an API permission named "notification". This will grant
93 // not only grant permission for using the Chrome App extension API, but also
94 // for the Web Notification API.
95 extensions::ExtensionRegistry* registry =
96 extensions::ExtensionRegistry::Get(browser_context);
97 extensions::ProcessMap* process_map =
98 extensions::ProcessMap::Get(browser_context);
99 extensions::ExtensionSet extensions;
101 DesktopNotificationService* desktop_notification_service =
102 DesktopNotificationServiceFactory::GetForProfile(profile);
103 DCHECK(desktop_notification_service);
105 // If |origin| is an enabled extension, only select that one. Otherwise select
106 // all extensions whose web content matches |origin|.
107 if (origin.SchemeIs(extensions::kExtensionScheme)) {
108 const extensions::Extension* extension = registry->GetExtensionById(
109 origin.host(), extensions::ExtensionRegistry::ENABLED);
110 if (extension)
111 extensions.Insert(extension);
112 } else {
113 for (const auto& extension : registry->enabled_extensions()) {
114 if (extension->web_extent().MatchesSecurityOrigin(origin))
115 extensions.Insert(extension);
119 // Check if any of the selected extensions have the "notification" API
120 // permission, are active in |render_process_id| and has not been manually
121 // disabled by the user. If all of that is true, grant permission.
122 for (const auto& extension : extensions) {
123 if (!extension->permissions_data()->HasAPIPermission(
124 extensions::APIPermission::kNotifications))
125 continue;
127 if (!process_map->Contains(extension->id(), render_process_id))
128 continue;
130 NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
131 if (!desktop_notification_service->IsNotifierEnabled(notifier_id))
132 continue;
134 return blink::WebNotificationPermissionAllowed;
136 #endif
138 ContentSetting setting =
139 DesktopNotificationProfileUtil::GetContentSetting(profile, origin);
141 if (setting == CONTENT_SETTING_ALLOW)
142 return blink::WebNotificationPermissionAllowed;
143 if (setting == CONTENT_SETTING_BLOCK)
144 return blink::WebNotificationPermissionDenied;
146 return blink::WebNotificationPermissionDefault;
149 blink::WebNotificationPermission
150 PlatformNotificationServiceImpl::CheckPermissionOnIOThread(
151 content::ResourceContext* resource_context,
152 const GURL& origin,
153 int render_process_id) {
154 DCHECK_CURRENTLY_ON(BrowserThread::IO);
156 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
157 #if defined(ENABLE_EXTENSIONS)
158 extensions::InfoMap* extension_info_map = io_data->GetExtensionInfoMap();
160 // We want to see if there is an extension that hasn't been manually disabled
161 // that has the notifications permission and applies to this security origin.
162 // First, get the list of extensions with permission for the origin.
163 extensions::ExtensionSet extensions;
164 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
165 origin,
166 render_process_id,
167 extensions::APIPermission::kNotifications,
168 &extensions);
169 for (const auto& extension : extensions) {
170 if (!extension_info_map->AreNotificationsDisabled(extension->id()))
171 return blink::WebNotificationPermissionAllowed;
173 #endif
175 // No enabled extensions exist, so check the normal host content settings.
176 HostContentSettingsMap* host_content_settings_map =
177 io_data->GetHostContentSettingsMap();
178 ContentSetting setting = host_content_settings_map->GetContentSetting(
179 origin,
180 origin,
181 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
182 NO_RESOURCE_IDENTIFIER);
184 if (setting == CONTENT_SETTING_ALLOW)
185 return blink::WebNotificationPermissionAllowed;
186 if (setting == CONTENT_SETTING_BLOCK)
187 return blink::WebNotificationPermissionDenied;
189 return blink::WebNotificationPermissionDefault;
192 void PlatformNotificationServiceImpl::DisplayNotification(
193 content::BrowserContext* browser_context,
194 const GURL& origin,
195 const SkBitmap& icon,
196 const content::PlatformNotificationData& notification_data,
197 scoped_ptr<content::DesktopNotificationDelegate> delegate,
198 base::Closure* cancel_callback) {
199 DCHECK_CURRENTLY_ON(BrowserThread::UI);
201 Profile* profile = Profile::FromBrowserContext(browser_context);
202 DCHECK(profile);
204 NotificationObjectProxy* proxy = new NotificationObjectProxy(delegate.Pass());
205 Notification notification = CreateNotificationFromData(
206 profile, origin, icon, notification_data, proxy);
208 GetNotificationUIManager()->Add(notification, profile);
209 if (cancel_callback)
210 *cancel_callback =
211 base::Bind(&CancelNotification,
212 notification.delegate_id(),
213 NotificationUIManager::GetProfileID(profile));
215 profile->GetHostContentSettingsMap()->UpdateLastUsage(
216 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
219 void PlatformNotificationServiceImpl::DisplayPersistentNotification(
220 content::BrowserContext* browser_context,
221 int64 service_worker_registration_id,
222 const GURL& origin,
223 const SkBitmap& icon,
224 const content::PlatformNotificationData& notification_data) {
225 DCHECK_CURRENTLY_ON(BrowserThread::UI);
227 Profile* profile = Profile::FromBrowserContext(browser_context);
228 DCHECK(profile);
230 PersistentNotificationDelegate* delegate = new PersistentNotificationDelegate(
231 browser_context,
232 service_worker_registration_id,
233 origin,
234 notification_data);
236 Notification notification = CreateNotificationFromData(
237 profile, origin, icon, notification_data, delegate);
239 GetNotificationUIManager()->Add(notification, profile);
241 profile->GetHostContentSettingsMap()->UpdateLastUsage(
242 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
245 void PlatformNotificationServiceImpl::ClosePersistentNotification(
246 content::BrowserContext* browser_context,
247 const std::string& persistent_notification_id) {
248 DCHECK_CURRENTLY_ON(BrowserThread::UI);
250 Profile* profile = Profile::FromBrowserContext(browser_context);
251 DCHECK(profile);
253 GetNotificationUIManager()->CancelById(
254 persistent_notification_id, NotificationUIManager::GetProfileID(profile));
257 Notification PlatformNotificationServiceImpl::CreateNotificationFromData(
258 Profile* profile,
259 const GURL& origin,
260 const SkBitmap& icon,
261 const content::PlatformNotificationData& notification_data,
262 NotificationDelegate* delegate) const {
263 base::string16 display_source = DisplayNameForOrigin(profile, origin);
265 // TODO(peter): Icons for Web Notifications are currently always requested for
266 // 1x scale, whereas the displays on which they can be displayed can have a
267 // different pixel density. Be smarter about this when the API gets updated
268 // with a way for developers to specify images of different resolutions.
269 Notification notification(origin, notification_data.title,
270 notification_data.body, gfx::Image::CreateFrom1xBitmap(icon),
271 display_source, notification_data.tag, delegate);
273 notification.set_context_message(display_source);
274 notification.set_silent(notification_data.silent);
276 // Web Notifications do not timeout.
277 notification.set_never_timeout(true);
279 return notification;
282 NotificationUIManager*
283 PlatformNotificationServiceImpl::GetNotificationUIManager() const {
284 if (notification_ui_manager_for_tests_)
285 return notification_ui_manager_for_tests_;
287 return g_browser_process->notification_ui_manager();
290 void PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting(
291 NotificationUIManager* manager) {
292 notification_ui_manager_for_tests_ = manager;
295 base::string16 PlatformNotificationServiceImpl::DisplayNameForOrigin(
296 Profile* profile,
297 const GURL& origin) const {
298 #if defined(ENABLE_EXTENSIONS)
299 // If the source is an extension, lookup the display name.
300 if (origin.SchemeIs(extensions::kExtensionScheme)) {
301 const extensions::Extension* extension =
302 extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
303 origin.host(), extensions::ExtensionRegistry::EVERYTHING);
304 DCHECK(extension);
306 return base::UTF8ToUTF16(extension->name());
308 #endif
310 std::string languages =
311 profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
313 return WebOriginDisplayName(origin, languages);
316 // static
317 base::string16 PlatformNotificationServiceImpl::WebOriginDisplayName(
318 const GURL& origin,
319 const std::string& languages) {
320 if (origin.SchemeIsHTTPOrHTTPS()) {
321 base::string16 formatted_origin;
322 if (origin.SchemeIs(url::kHttpScheme)) {
323 const url::Parsed& parsed = origin.parsed_for_possibly_invalid_spec();
324 const std::string& spec = origin.possibly_invalid_spec();
325 formatted_origin.append(
326 spec.begin(),
327 spec.begin() +
328 parsed.CountCharactersBefore(url::Parsed::USERNAME, true));
330 formatted_origin.append(net::IDNToUnicode(origin.host(), languages));
331 if (origin.has_port()) {
332 formatted_origin.push_back(':');
333 formatted_origin.append(base::UTF8ToUTF16(origin.port()));
335 return formatted_origin;
338 // TODO(dewittj): Once file:// URLs are passed in to the origin
339 // GURL here, begin returning the path as the display name.
340 return net::FormatUrl(origin, languages);