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/common/platform_notification_messages.h"
17 #include "content/public/common/platform_notification_data.h"
18 #include "third_party/WebKit/public/platform/WebSerializedOrigin.h"
19 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationDelegate.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
22 using blink::WebNotificationPermission
;
27 int CurrentWorkerId() {
28 return WorkerTaskRunner::Instance()->CurrentWorkerId();
33 static base::LazyInstance
<base::ThreadLocalPointer
<NotificationManager
>>::Leaky
34 g_notification_manager_tls
= LAZY_INSTANCE_INITIALIZER
;
36 NotificationManager::NotificationManager(
37 ThreadSafeSender
* thread_safe_sender
,
38 base::SingleThreadTaskRunner
* main_thread_task_runner
,
39 NotificationDispatcher
* notification_dispatcher
)
40 : thread_safe_sender_(thread_safe_sender
),
41 notification_dispatcher_(notification_dispatcher
),
42 pending_notifications_(main_thread_task_runner
) {
43 g_notification_manager_tls
.Pointer()->Set(this);
46 NotificationManager::~NotificationManager() {
47 g_notification_manager_tls
.Pointer()->Set(nullptr);
50 NotificationManager
* NotificationManager::ThreadSpecificInstance(
51 ThreadSafeSender
* thread_safe_sender
,
52 base::SingleThreadTaskRunner
* main_thread_task_runner
,
53 NotificationDispatcher
* notification_dispatcher
) {
54 if (g_notification_manager_tls
.Pointer()->Get())
55 return g_notification_manager_tls
.Pointer()->Get();
57 NotificationManager
* manager
= new NotificationManager(
58 thread_safe_sender
, main_thread_task_runner
, notification_dispatcher
);
59 if (CurrentWorkerId())
60 WorkerTaskRunner::Instance()->AddStopObserver(manager
);
64 void NotificationManager::OnWorkerRunLoopStopped() {
68 void NotificationManager::show(
69 const blink::WebSerializedOrigin
& origin
,
70 const blink::WebNotificationData
& notification_data
,
71 blink::WebNotificationDelegate
* delegate
) {
72 if (notification_data
.icon
.isEmpty()) {
73 DisplayPageNotification(origin
, notification_data
, delegate
, SkBitmap());
77 pending_notifications_
.FetchPageNotificationResources(
80 base::Bind(&NotificationManager::DisplayPageNotification
,
81 base::Unretained(this), // this owns |pending_notifications_|
87 void NotificationManager::showPersistent(
88 const blink::WebSerializedOrigin
& origin
,
89 const blink::WebNotificationData
& notification_data
,
90 blink::WebServiceWorkerRegistration
* service_worker_registration
,
91 blink::WebNotificationShowCallbacks
* callbacks
) {
92 DCHECK(service_worker_registration
);
93 int64 service_worker_registration_id
=
94 static_cast<WebServiceWorkerRegistrationImpl
*>(
95 service_worker_registration
)->registration_id();
97 scoped_ptr
<blink::WebNotificationShowCallbacks
> owned_callbacks(callbacks
);
98 if (notification_data
.icon
.isEmpty()) {
99 DisplayPersistentNotification(origin
,
101 service_worker_registration_id
,
102 owned_callbacks
.Pass(),
107 pending_notifications_
.FetchPersistentNotificationResources(
109 base::Bind(&NotificationManager::DisplayPersistentNotification
,
110 base::Unretained(this), // this owns |pending_notifications_|
113 service_worker_registration_id
,
114 base::Passed(&owned_callbacks
)));
117 void NotificationManager::close(blink::WebNotificationDelegate
* delegate
) {
118 if (pending_notifications_
.CancelPageNotificationFetches(delegate
))
121 for (auto& iter
: active_page_notifications_
) {
122 if (iter
.second
!= delegate
)
125 thread_safe_sender_
->Send(
126 new PlatformNotificationHostMsg_Close(iter
.first
));
127 active_page_notifications_
.erase(iter
.first
);
131 // It should not be possible for Blink to call close() on a Notification which
132 // does not exist in either the pending or active notification lists.
136 void NotificationManager::closePersistent(
137 const blink::WebString
& persistent_notification_id
) {
138 thread_safe_sender_
->Send(new PlatformNotificationHostMsg_ClosePersistent(
139 base::UTF16ToUTF8(persistent_notification_id
)));
142 void NotificationManager::notifyDelegateDestroyed(
143 blink::WebNotificationDelegate
* delegate
) {
144 if (pending_notifications_
.CancelPageNotificationFetches(delegate
))
147 for (auto& iter
: active_page_notifications_
) {
148 if (iter
.second
!= delegate
)
151 active_page_notifications_
.erase(iter
.first
);
156 WebNotificationPermission
NotificationManager::checkPermission(
157 const blink::WebSerializedOrigin
& origin
) {
158 WebNotificationPermission permission
=
159 blink::WebNotificationPermissionAllowed
;
160 thread_safe_sender_
->Send(new PlatformNotificationHostMsg_CheckPermission(
161 GURL(origin
.string()), &permission
));
166 bool NotificationManager::OnMessageReceived(const IPC::Message
& message
) {
168 IPC_BEGIN_MESSAGE_MAP(NotificationManager
, message
)
169 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow
, OnDidShow
);
170 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose
, OnDidClose
);
171 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick
, OnDidClick
);
172 IPC_MESSAGE_UNHANDLED(handled
= false)
173 IPC_END_MESSAGE_MAP()
178 void NotificationManager::OnDidShow(int notification_id
) {
179 const auto& iter
= active_page_notifications_
.find(notification_id
);
180 if (iter
== active_page_notifications_
.end())
183 iter
->second
->dispatchShowEvent();
186 void NotificationManager::OnDidClose(int notification_id
) {
187 const auto& iter
= active_page_notifications_
.find(notification_id
);
188 if (iter
== active_page_notifications_
.end())
191 iter
->second
->dispatchCloseEvent();
192 active_page_notifications_
.erase(iter
);
195 void NotificationManager::OnDidClick(int notification_id
) {
196 const auto& iter
= active_page_notifications_
.find(notification_id
);
197 if (iter
== active_page_notifications_
.end())
200 iter
->second
->dispatchClickEvent();
203 void NotificationManager::DisplayPageNotification(
204 const blink::WebSerializedOrigin
& origin
,
205 const blink::WebNotificationData
& notification_data
,
206 blink::WebNotificationDelegate
* delegate
,
207 const SkBitmap
& icon
) {
208 int notification_id
=
209 notification_dispatcher_
->GenerateNotificationId(CurrentWorkerId());
211 active_page_notifications_
[notification_id
] = delegate
;
212 thread_safe_sender_
->Send(
213 new PlatformNotificationHostMsg_Show(
215 GURL(origin
.string()),
217 ToPlatformNotificationData(notification_data
)));
220 void NotificationManager::DisplayPersistentNotification(
221 const blink::WebSerializedOrigin
& origin
,
222 const blink::WebNotificationData
& notification_data
,
223 int64 service_worker_registration_id
,
224 scoped_ptr
<blink::WebNotificationShowCallbacks
> callbacks
,
225 const SkBitmap
& icon
) {
226 thread_safe_sender_
->Send(
227 new PlatformNotificationHostMsg_ShowPersistent(
228 service_worker_registration_id
,
229 GURL(origin
.string()),
231 ToPlatformNotificationData(notification_data
)));
233 // There currently isn't a case in which the promise would be rejected per
234 // our implementation, so always resolve it here.
235 callbacks
->onSuccess();
238 } // namespace content