Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / notifications / notification_manager.cc
blob6f5e8fefdb49b9bf4b086661e4ba56c772ef8d16
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;
23 namespace content {
24 namespace {
26 int CurrentWorkerId() {
27 return WorkerTaskRunner::Instance()->CurrentWorkerId();
30 } // namespace
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);
60 return manager;
63 void NotificationManager::OnWorkerRunLoopStopped() {
64 delete this;
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());
73 return;
76 pending_notifications_.FetchPageNotificationResources(
77 notification_data,
78 delegate,
79 base::Bind(&NotificationManager::DisplayPageNotification,
80 base::Unretained(this), // this owns |pending_notifications_|
81 origin,
82 notification_data,
83 delegate));
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,
99 notification_data,
100 service_worker_registration_id,
101 owned_callbacks.Pass(),
102 SkBitmap());
103 return;
106 pending_notifications_.FetchPersistentNotificationResources(
107 notification_data,
108 base::Bind(&NotificationManager::DisplayPersistentNotification,
109 base::Unretained(this), // this owns |pending_notifications_|
110 origin,
111 notification_data,
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);
121 DCHECK(callbacks);
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.
133 int request_id =
134 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
136 pending_get_notification_requests_.AddWithID(callbacks, request_id);
138 thread_safe_sender_->Send(
139 new PlatformNotificationHostMsg_GetNotifications(
140 request_id,
141 service_worker_registration_id,
142 origin,
143 base::UTF16ToUTF8(filter_tag)));
146 void NotificationManager::close(blink::WebNotificationDelegate* delegate) {
147 if (pending_notifications_.CancelPageNotificationFetches(delegate))
148 return;
150 for (auto& iter : active_page_notifications_) {
151 if (iter.second != delegate)
152 continue;
154 thread_safe_sender_->Send(
155 new PlatformNotificationHostMsg_Close(iter.first));
156 active_page_notifications_.erase(iter.first);
157 return;
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.
162 NOTREACHED();
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))
176 return;
178 for (auto& iter : active_page_notifications_) {
179 if (iter.second != delegate)
180 continue;
182 active_page_notifications_.erase(iter.first);
183 return;
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));
194 return permission;
197 bool NotificationManager::OnMessageReceived(const IPC::Message& message) {
198 bool handled = true;
199 IPC_BEGIN_MESSAGE_MAP(NotificationManager, message)
200 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow, OnDidShow);
201 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent,
202 OnDidShowPersistent)
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()
210 return handled;
213 void NotificationManager::OnDidShow(int notification_id) {
214 const auto& iter = active_page_notifications_.find(notification_id);
215 if (iter == active_page_notifications_.end())
216 return;
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);
224 DCHECK(callbacks);
226 if (!callbacks)
227 return;
229 if (success)
230 callbacks->onSuccess();
231 else
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())
240 return;
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())
249 return;
251 iter->second->dispatchClickEvent();
254 void NotificationManager::OnDidGetNotifications(
255 int request_id,
256 const std::vector<PersistentNotificationInfo>& notification_infos) {
257 blink::WebNotificationGetCallbacks* callbacks =
258 pending_get_notification_requests_.Lookup(request_id);
259 DCHECK(callbacks);
260 if (!callbacks)
261 return;
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(
293 notification_id,
294 GURL(origin.string()),
295 icon,
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.
307 int request_id =
308 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
310 pending_show_notification_requests_.AddWithID(callbacks.release(),
311 request_id);
313 thread_safe_sender_->Send(
314 new PlatformNotificationHostMsg_ShowPersistent(
315 request_id,
316 service_worker_registration_id,
317 GURL(origin.string()),
318 icon,
319 ToPlatformNotificationData(notification_data)));
322 } // namespace content