[Eraser strings] Remove unused Supervised User infobar and corresponding strings
[chromium-blink-merge.git] / chrome / browser / notifications / platform_notification_service_impl.cc
blobf03f2beb7239553a3abe9bbbfb9c0c51abd75955
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/metrics/histogram_macros.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
12 #include "chrome/browser/notifications/notification_object_proxy.h"
13 #include "chrome/browser/notifications/notification_ui_manager.h"
14 #include "chrome/browser/notifications/persistent_notification_delegate.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_io_data.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/content_settings/core/browser/host_content_settings_map.h"
19 #include "components/content_settings/core/common/content_settings.h"
20 #include "components/url_formatter/url_formatter.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/desktop_notification_delegate.h"
23 #include "content/public/browser/notification_event_dispatcher.h"
24 #include "content/public/browser/platform_notification_context.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "content/public/common/platform_notification_data.h"
27 #include "ui/message_center/notifier_settings.h"
28 #include "url/url_constants.h"
30 #if defined(ENABLE_EXTENSIONS)
31 #include "chrome/browser/notifications/notifier_state_tracker.h"
32 #include "chrome/browser/notifications/notifier_state_tracker_factory.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "extensions/browser/info_map.h"
35 #include "extensions/common/constants.h"
36 #include "extensions/common/permissions/api_permission.h"
37 #include "extensions/common/permissions/permissions_data.h"
38 #endif
40 #if defined(OS_ANDROID)
41 #include "base/strings/string_number_conversions.h"
42 #endif
44 using content::BrowserContext;
45 using content::BrowserThread;
46 using content::PlatformNotificationContext;
47 using message_center::NotifierId;
49 namespace {
51 // Callback to provide when deleting the data associated with persistent Web
52 // Notifications from the notification database.
53 void OnPersistentNotificationDataDeleted(bool success) {
54 UMA_HISTOGRAM_BOOLEAN("Notifications.PersistentNotificationDataDeleted",
55 success);
58 // Persistent notifications fired through the delegate do not care about the
59 // lifetime of the Service Worker responsible for executing the event.
60 void OnEventDispatchComplete(content::PersistentNotificationStatus status) {
61 UMA_HISTOGRAM_ENUMERATION(
62 "Notifications.PersistentWebNotificationClickResult", status,
63 content::PersistentNotificationStatus::
64 PERSISTENT_NOTIFICATION_STATUS_MAX);
67 void CancelNotification(const std::string& id, ProfileID profile_id) {
68 PlatformNotificationServiceImpl::GetInstance()
69 ->GetNotificationUIManager()->CancelById(id, profile_id);
72 } // namespace
74 // static
75 PlatformNotificationServiceImpl*
76 PlatformNotificationServiceImpl::GetInstance() {
77 return Singleton<PlatformNotificationServiceImpl>::get();
80 PlatformNotificationServiceImpl::PlatformNotificationServiceImpl()
81 : notification_ui_manager_for_tests_(nullptr) {}
83 PlatformNotificationServiceImpl::~PlatformNotificationServiceImpl() {}
85 void PlatformNotificationServiceImpl::OnPersistentNotificationClick(
86 BrowserContext* browser_context,
87 int64_t persistent_notification_id,
88 const GURL& origin,
89 int action_index) const {
90 DCHECK_CURRENTLY_ON(BrowserThread::UI);
91 content::NotificationEventDispatcher::GetInstance()
92 ->DispatchNotificationClickEvent(
93 browser_context,
94 persistent_notification_id,
95 origin,
96 action_index,
97 base::Bind(&OnEventDispatchComplete));
100 void PlatformNotificationServiceImpl::OnPersistentNotificationClose(
101 BrowserContext* browser_context,
102 int64_t persistent_notification_id,
103 const GURL& origin) const {
104 DCHECK_CURRENTLY_ON(BrowserThread::UI);
105 PlatformNotificationContext* context =
106 BrowserContext::GetStoragePartitionForSite(browser_context, origin)
107 ->GetPlatformNotificationContext();
109 BrowserThread::PostTask(
110 BrowserThread::IO,
111 FROM_HERE,
112 base::Bind(&PlatformNotificationContext::DeleteNotificationData,
113 context,
114 persistent_notification_id,
115 origin,
116 base::Bind(&OnPersistentNotificationDataDeleted)));
119 blink::WebNotificationPermission
120 PlatformNotificationServiceImpl::CheckPermissionOnUIThread(
121 BrowserContext* browser_context,
122 const GURL& origin,
123 int render_process_id) {
124 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126 Profile* profile = Profile::FromBrowserContext(browser_context);
127 DCHECK(profile);
129 #if defined(ENABLE_EXTENSIONS)
130 // Extensions support an API permission named "notification". This will grant
131 // not only grant permission for using the Chrome App extension API, but also
132 // for the Web Notification API.
133 if (origin.SchemeIs(extensions::kExtensionScheme)) {
134 extensions::ExtensionRegistry* registry =
135 extensions::ExtensionRegistry::Get(browser_context);
136 extensions::ProcessMap* process_map =
137 extensions::ProcessMap::Get(browser_context);
139 const extensions::Extension* extension =
140 registry->GetExtensionById(origin.host(),
141 extensions::ExtensionRegistry::ENABLED);
143 if (extension &&
144 extension->permissions_data()->HasAPIPermission(
145 extensions::APIPermission::kNotifications) &&
146 process_map->Contains(extension->id(), render_process_id)) {
147 NotifierStateTracker* notifier_state_tracker =
148 NotifierStateTrackerFactory::GetForProfile(profile);
149 DCHECK(notifier_state_tracker);
151 NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
152 if (notifier_state_tracker->IsNotifierEnabled(notifier_id))
153 return blink::WebNotificationPermissionAllowed;
156 #endif
158 ContentSetting setting =
159 DesktopNotificationProfileUtil::GetContentSetting(profile, origin);
161 if (setting == CONTENT_SETTING_ALLOW)
162 return blink::WebNotificationPermissionAllowed;
163 if (setting == CONTENT_SETTING_BLOCK)
164 return blink::WebNotificationPermissionDenied;
166 return blink::WebNotificationPermissionDefault;
169 blink::WebNotificationPermission
170 PlatformNotificationServiceImpl::CheckPermissionOnIOThread(
171 content::ResourceContext* resource_context,
172 const GURL& origin,
173 int render_process_id) {
174 DCHECK_CURRENTLY_ON(BrowserThread::IO);
176 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
177 #if defined(ENABLE_EXTENSIONS)
178 // Extensions support an API permission named "notification". This will grant
179 // not only grant permission for using the Chrome App extension API, but also
180 // for the Web Notification API.
181 if (origin.SchemeIs(extensions::kExtensionScheme)) {
182 extensions::InfoMap* extension_info_map = io_data->GetExtensionInfoMap();
183 const extensions::ProcessMap& process_map =
184 extension_info_map->process_map();
186 const extensions::Extension* extension =
187 extension_info_map->extensions().GetByID(origin.host());
189 if (extension &&
190 extension->permissions_data()->HasAPIPermission(
191 extensions::APIPermission::kNotifications) &&
192 process_map.Contains(extension->id(), render_process_id)) {
193 if (!extension_info_map->AreNotificationsDisabled(extension->id()))
194 return blink::WebNotificationPermissionAllowed;
197 #endif
199 // No enabled extensions exist, so check the normal host content settings.
200 HostContentSettingsMap* host_content_settings_map =
201 io_data->GetHostContentSettingsMap();
202 ContentSetting setting = host_content_settings_map->GetContentSetting(
203 origin,
204 origin,
205 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
206 content_settings::ResourceIdentifier());
208 if (setting == CONTENT_SETTING_ALLOW)
209 return blink::WebNotificationPermissionAllowed;
210 if (setting == CONTENT_SETTING_BLOCK)
211 return blink::WebNotificationPermissionDenied;
213 return blink::WebNotificationPermissionDefault;
216 void PlatformNotificationServiceImpl::DisplayNotification(
217 BrowserContext* browser_context,
218 const GURL& origin,
219 const SkBitmap& icon,
220 const content::PlatformNotificationData& notification_data,
221 scoped_ptr<content::DesktopNotificationDelegate> delegate,
222 base::Closure* cancel_callback) {
223 DCHECK_CURRENTLY_ON(BrowserThread::UI);
225 Profile* profile = Profile::FromBrowserContext(browser_context);
226 DCHECK(profile);
228 NotificationObjectProxy* proxy = new NotificationObjectProxy(delegate.Pass());
229 Notification notification = CreateNotificationFromData(
230 profile, origin, icon, notification_data, proxy);
232 GetNotificationUIManager()->Add(notification, profile);
233 if (cancel_callback)
234 *cancel_callback =
235 base::Bind(&CancelNotification,
236 notification.delegate_id(),
237 NotificationUIManager::GetProfileID(profile));
239 profile->GetHostContentSettingsMap()->UpdateLastUsage(
240 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
243 void PlatformNotificationServiceImpl::DisplayPersistentNotification(
244 BrowserContext* browser_context,
245 int64_t persistent_notification_id,
246 const GURL& origin,
247 const SkBitmap& icon,
248 const content::PlatformNotificationData& notification_data) {
249 DCHECK_CURRENTLY_ON(BrowserThread::UI);
251 Profile* profile = Profile::FromBrowserContext(browser_context);
252 DCHECK(profile);
254 PersistentNotificationDelegate* delegate = new PersistentNotificationDelegate(
255 browser_context, persistent_notification_id, origin);
257 Notification notification = CreateNotificationFromData(
258 profile, origin, icon, notification_data, delegate);
260 // TODO(peter): Remove this mapping when we have reliable id generation for
261 // the message_center::Notification objects.
262 persistent_notifications_[persistent_notification_id] = notification.id();
264 GetNotificationUIManager()->Add(notification, profile);
266 profile->GetHostContentSettingsMap()->UpdateLastUsage(
267 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
270 void PlatformNotificationServiceImpl::ClosePersistentNotification(
271 BrowserContext* browser_context,
272 int64_t persistent_notification_id) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
275 Profile* profile = Profile::FromBrowserContext(browser_context);
276 DCHECK(profile);
278 #if defined(OS_ANDROID)
279 // TODO(peter): Remove this conversion when the notification ids are being
280 // generated by the caller of this method.
281 std::string textual_persistent_notification_id =
282 base::Int64ToString(persistent_notification_id);
283 GetNotificationUIManager()->CancelById(
284 textual_persistent_notification_id,
285 NotificationUIManager::GetProfileID(profile));
286 #else
287 auto iter = persistent_notifications_.find(persistent_notification_id);
288 if (iter == persistent_notifications_.end())
289 return;
291 GetNotificationUIManager()->CancelById(
292 iter->second, NotificationUIManager::GetProfileID(profile));
294 persistent_notifications_.erase(iter);
295 #endif
298 bool PlatformNotificationServiceImpl::GetDisplayedPersistentNotifications(
299 BrowserContext* browser_context,
300 std::set<std::string>* displayed_notifications) {
301 DCHECK(displayed_notifications);
303 #if !defined(OS_ANDROID)
304 Profile* profile = Profile::FromBrowserContext(browser_context);
305 if (!profile || profile->AsTestingProfile())
306 return false; // Tests will not have a message center.
308 // TODO(peter): Filter for persistent notifications only.
309 *displayed_notifications = GetNotificationUIManager()->GetAllIdsByProfile(
310 NotificationUIManager::GetProfileID(profile));
312 return true;
313 #else
314 // Android cannot reliably return the notifications that are currently being
315 // displayed on the platform, see the comment in NotificationUIManagerAndroid.
316 return false;
317 #endif // !defined(OS_ANDROID)
320 Notification PlatformNotificationServiceImpl::CreateNotificationFromData(
321 Profile* profile,
322 const GURL& origin,
323 const SkBitmap& icon,
324 const content::PlatformNotificationData& notification_data,
325 NotificationDelegate* delegate) const {
326 base::string16 display_source = DisplayNameForOrigin(profile, origin);
328 // TODO(peter): Icons for Web Notifications are currently always requested for
329 // 1x scale, whereas the displays on which they can be displayed can have a
330 // different pixel density. Be smarter about this when the API gets updated
331 // with a way for developers to specify images of different resolutions.
332 Notification notification(origin, notification_data.title,
333 notification_data.body, gfx::Image::CreateFrom1xBitmap(icon),
334 display_source, notification_data.tag, delegate);
336 notification.set_context_message(display_source);
337 notification.set_vibration_pattern(notification_data.vibration_pattern);
338 notification.set_silent(notification_data.silent);
340 std::vector<message_center::ButtonInfo> buttons;
341 for (const auto& action : notification_data.actions)
342 buttons.push_back(message_center::ButtonInfo(action.title));
344 notification.set_buttons(buttons);
346 // Web Notifications do not timeout.
347 notification.set_never_timeout(true);
349 return notification;
352 NotificationUIManager*
353 PlatformNotificationServiceImpl::GetNotificationUIManager() const {
354 if (notification_ui_manager_for_tests_)
355 return notification_ui_manager_for_tests_;
357 return g_browser_process->notification_ui_manager();
360 void PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting(
361 NotificationUIManager* manager) {
362 notification_ui_manager_for_tests_ = manager;
365 base::string16 PlatformNotificationServiceImpl::DisplayNameForOrigin(
366 Profile* profile,
367 const GURL& origin) const {
368 #if defined(ENABLE_EXTENSIONS)
369 // If the source is an extension, lookup the display name.
370 if (origin.SchemeIs(extensions::kExtensionScheme)) {
371 const extensions::Extension* extension =
372 extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
373 origin.host(), extensions::ExtensionRegistry::EVERYTHING);
374 DCHECK(extension);
376 return base::UTF8ToUTF16(extension->name());
378 #endif
380 std::string languages =
381 profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
383 return WebOriginDisplayName(origin, languages);
386 // static
387 // TODO(palmer): It might be good to replace this with a call to
388 // |FormatUrlForSecurityDisplay|. crbug.com/496965
389 base::string16 PlatformNotificationServiceImpl::WebOriginDisplayName(
390 const GURL& origin,
391 const std::string& languages) {
392 if (origin.SchemeIsHTTPOrHTTPS()) {
393 base::string16 formatted_origin;
394 if (origin.SchemeIs(url::kHttpScheme)) {
395 const url::Parsed& parsed = origin.parsed_for_possibly_invalid_spec();
396 const std::string& spec = origin.possibly_invalid_spec();
397 formatted_origin.append(
398 spec.begin(),
399 spec.begin() +
400 parsed.CountCharactersBefore(url::Parsed::USERNAME, true));
402 formatted_origin.append(
403 url_formatter::IDNToUnicode(origin.host(), languages));
404 if (origin.has_port()) {
405 formatted_origin.push_back(':');
406 formatted_origin.append(base::UTF8ToUTF16(origin.port()));
408 return formatted_origin;
411 // TODO(dewittj): Once file:// URLs are passed in to the origin
412 // GURL here, begin returning the path as the display name.
413 return url_formatter::FormatUrl(origin, languages);