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 "content/child/notifications/notification_manager.h"
7 #include "base/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/threading/thread_local.h"
11 #include "content/child/notifications/notification_data_conversions.h"
12 #include "content/child/notifications/notification_dispatcher.h"
13 #include "content/child/service_worker/web_service_worker_registration_impl.h"
14 #include "content/child/thread_safe_sender.h"
15 #include "content/child/worker_task_runner.h"
16 #include "content/public/common/platform_notification_data.h"
17 #include "third_party/WebKit/public/platform/WebSerializedOrigin.h"
18 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationDelegate.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
21 using blink::WebNotificationPermission
;
26 int CurrentWorkerId() {
27 return WorkerTaskRunner::Instance()->CurrentWorkerId();
32 static base::LazyInstance
<base::ThreadLocalPointer
<NotificationManager
>>::Leaky
33 g_notification_manager_tls
= LAZY_INSTANCE_INITIALIZER
;
35 NotificationManager::NotificationManager(
36 ThreadSafeSender
* thread_safe_sender
,
37 base::SingleThreadTaskRunner
* main_thread_task_runner
,
38 NotificationDispatcher
* notification_dispatcher
)
39 : thread_safe_sender_(thread_safe_sender
),
40 notification_dispatcher_(notification_dispatcher
),
41 pending_notifications_(main_thread_task_runner
) {
42 g_notification_manager_tls
.Pointer()->Set(this);
45 NotificationManager::~NotificationManager() {
46 g_notification_manager_tls
.Pointer()->Set(nullptr);
49 NotificationManager
* NotificationManager::ThreadSpecificInstance(
50 ThreadSafeSender
* thread_safe_sender
,
51 base::SingleThreadTaskRunner
* main_thread_task_runner
,
52 NotificationDispatcher
* notification_dispatcher
) {
53 if (g_notification_manager_tls
.Pointer()->Get())
54 return g_notification_manager_tls
.Pointer()->Get();
56 NotificationManager
* manager
= new NotificationManager(
57 thread_safe_sender
, main_thread_task_runner
, notification_dispatcher
);
58 if (CurrentWorkerId())
59 WorkerTaskRunner::Instance()->AddStopObserver(manager
);
63 void NotificationManager::OnWorkerRunLoopStopped() {
67 void NotificationManager::show(
68 const blink::WebSerializedOrigin
& origin
,
69 const blink::WebNotificationData
& notification_data
,
70 blink::WebNotificationDelegate
* delegate
) {
71 if (notification_data
.icon
.isEmpty()) {
72 DisplayPageNotification(origin
, notification_data
, delegate
, SkBitmap());
76 pending_notifications_
.FetchPageNotificationResources(
79 base::Bind(&NotificationManager::DisplayPageNotification
,
80 base::Unretained(this), // this owns |pending_notifications_|
86 void NotificationManager::showPersistent(
87 const blink::WebSerializedOrigin
& origin
,
88 const blink::WebNotificationData
& notification_data
,
89 blink::WebServiceWorkerRegistration
* service_worker_registration
,
90 blink::WebNotificationShowCallbacks
* callbacks
) {
91 DCHECK(service_worker_registration
);
92 int64 service_worker_registration_id
=
93 static_cast<WebServiceWorkerRegistrationImpl
*>(
94 service_worker_registration
)->registration_id();
96 scoped_ptr
<blink::WebNotificationShowCallbacks
> owned_callbacks(callbacks
);
97 if (notification_data
.icon
.isEmpty()) {
98 DisplayPersistentNotification(origin
,
100 service_worker_registration_id
,
101 owned_callbacks
.Pass(),
106 pending_notifications_
.FetchPersistentNotificationResources(
108 base::Bind(&NotificationManager::DisplayPersistentNotification
,
109 base::Unretained(this), // this owns |pending_notifications_|
112 service_worker_registration_id
,
113 base::Passed(&owned_callbacks
)));
116 void NotificationManager::getNotifications(
117 const blink::WebString
& filter_tag
,
118 blink::WebServiceWorkerRegistration
* service_worker_registration
,
119 blink::WebNotificationGetCallbacks
* callbacks
) {
120 DCHECK(service_worker_registration
);
123 WebServiceWorkerRegistrationImpl
* service_worker_registration_impl
=
124 static_cast<WebServiceWorkerRegistrationImpl
*>(
125 service_worker_registration
);
127 GURL origin
= GURL(service_worker_registration_impl
->scope()).GetOrigin();
128 int64 service_worker_registration_id
=
129 service_worker_registration_impl
->registration_id();
131 // TODO(peter): GenerateNotificationId is more of a request id. Consider
132 // renaming the method in the NotificationDispatcher if this makes sense.
134 notification_dispatcher_
->GenerateNotificationId(CurrentWorkerId());
136 pending_get_notification_requests_
.AddWithID(callbacks
, request_id
);
138 thread_safe_sender_
->Send(
139 new PlatformNotificationHostMsg_GetNotifications(
141 service_worker_registration_id
,
143 base::UTF16ToUTF8(filter_tag
)));
146 void NotificationManager::close(blink::WebNotificationDelegate
* delegate
) {
147 if (pending_notifications_
.CancelPageNotificationFetches(delegate
))
150 for (auto& iter
: active_page_notifications_
) {
151 if (iter
.second
!= delegate
)
154 thread_safe_sender_
->Send(
155 new PlatformNotificationHostMsg_Close(iter
.first
));
156 active_page_notifications_
.erase(iter
.first
);
160 // It should not be possible for Blink to call close() on a Notification which
161 // does not exist in either the pending or active notification lists.
165 void NotificationManager::closePersistent(
166 const blink::WebSerializedOrigin
& origin
,
167 const blink::WebString
& persistent_notification_id
) {
168 thread_safe_sender_
->Send(new PlatformNotificationHostMsg_ClosePersistent(
169 GURL(origin
.string()),
170 base::UTF16ToUTF8(persistent_notification_id
)));
173 void NotificationManager::notifyDelegateDestroyed(
174 blink::WebNotificationDelegate
* delegate
) {
175 if (pending_notifications_
.CancelPageNotificationFetches(delegate
))
178 for (auto& iter
: active_page_notifications_
) {
179 if (iter
.second
!= delegate
)
182 active_page_notifications_
.erase(iter
.first
);
187 WebNotificationPermission
NotificationManager::checkPermission(
188 const blink::WebSerializedOrigin
& origin
) {
189 WebNotificationPermission permission
=
190 blink::WebNotificationPermissionAllowed
;
191 thread_safe_sender_
->Send(new PlatformNotificationHostMsg_CheckPermission(
192 GURL(origin
.string()), &permission
));
197 bool NotificationManager::OnMessageReceived(const IPC::Message
& message
) {
199 IPC_BEGIN_MESSAGE_MAP(NotificationManager
, message
)
200 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow
, OnDidShow
);
201 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent
,
203 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose
, OnDidClose
);
204 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick
, OnDidClick
);
205 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidGetNotifications
,
206 OnDidGetNotifications
)
207 IPC_MESSAGE_UNHANDLED(handled
= false)
208 IPC_END_MESSAGE_MAP()
213 void NotificationManager::OnDidShow(int notification_id
) {
214 const auto& iter
= active_page_notifications_
.find(notification_id
);
215 if (iter
== active_page_notifications_
.end())
218 iter
->second
->dispatchShowEvent();
221 void NotificationManager::OnDidShowPersistent(int request_id
, bool success
) {
222 blink::WebNotificationShowCallbacks
* callbacks
=
223 pending_show_notification_requests_
.Lookup(request_id
);
230 callbacks
->onSuccess();
232 callbacks
->onError();
234 pending_show_notification_requests_
.Remove(request_id
);
237 void NotificationManager::OnDidClose(int notification_id
) {
238 const auto& iter
= active_page_notifications_
.find(notification_id
);
239 if (iter
== active_page_notifications_
.end())
242 iter
->second
->dispatchCloseEvent();
243 active_page_notifications_
.erase(iter
);
246 void NotificationManager::OnDidClick(int notification_id
) {
247 const auto& iter
= active_page_notifications_
.find(notification_id
);
248 if (iter
== active_page_notifications_
.end())
251 iter
->second
->dispatchClickEvent();
254 void NotificationManager::OnDidGetNotifications(
256 const std::vector
<PersistentNotificationInfo
>& notification_infos
) {
257 blink::WebNotificationGetCallbacks
* callbacks
=
258 pending_get_notification_requests_
.Lookup(request_id
);
263 scoped_ptr
<blink::WebVector
<blink::WebPersistentNotificationInfo
>>
264 notifications(new blink::WebVector
<blink::WebPersistentNotificationInfo
>(
265 notification_infos
.size()));
267 for (size_t i
= 0; i
< notification_infos
.size(); ++i
) {
268 blink::WebPersistentNotificationInfo web_notification_info
;
269 web_notification_info
.persistentNotificationId
=
270 blink::WebString::fromUTF8(notification_infos
[i
].first
);
271 web_notification_info
.data
=
272 ToWebNotificationData(notification_infos
[i
].second
);
274 (*notifications
)[i
] = web_notification_info
;
277 callbacks
->onSuccess(notifications
.release());
279 pending_get_notification_requests_
.Remove(request_id
);
282 void NotificationManager::DisplayPageNotification(
283 const blink::WebSerializedOrigin
& origin
,
284 const blink::WebNotificationData
& notification_data
,
285 blink::WebNotificationDelegate
* delegate
,
286 const SkBitmap
& icon
) {
287 int notification_id
=
288 notification_dispatcher_
->GenerateNotificationId(CurrentWorkerId());
290 active_page_notifications_
[notification_id
] = delegate
;
291 thread_safe_sender_
->Send(
292 new PlatformNotificationHostMsg_Show(
294 GURL(origin
.string()),
296 ToPlatformNotificationData(notification_data
)));
299 void NotificationManager::DisplayPersistentNotification(
300 const blink::WebSerializedOrigin
& origin
,
301 const blink::WebNotificationData
& notification_data
,
302 int64 service_worker_registration_id
,
303 scoped_ptr
<blink::WebNotificationShowCallbacks
> callbacks
,
304 const SkBitmap
& icon
) {
305 // TODO(peter): GenerateNotificationId is more of a request id. Consider
306 // renaming the method in the NotificationDispatcher if this makes sense.
308 notification_dispatcher_
->GenerateNotificationId(CurrentWorkerId());
310 pending_show_notification_requests_
.AddWithID(callbacks
.release(),
313 thread_safe_sender_
->Send(
314 new PlatformNotificationHostMsg_ShowPersistent(
316 service_worker_registration_id
,
317 GURL(origin
.string()),
319 ToPlatformNotificationData(notification_data
)));
322 } // namespace content