blob: 3b593eb6c0b3b5e074fde9765de478faa8fe5303 [file] [log] [blame]
peterd69823a12014-12-09 14:06:591// 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.
4
5#include "content/browser/notifications/notification_event_dispatcher_impl.h"
6
7#include "base/callback.h"
Peter Beverloo64337af2017-11-21 18:04:028#include "base/callback_helpers.h"
peterf8ea4c42017-02-13 18:08:369#include "base/optional.h"
avib7348942015-12-25 20:57:1010#include "build/build_config.h"
miguelg26f01962017-06-02 14:51:0911#include "content/browser/notifications/notification_message_filter.h"
peter2ee1f3c2015-04-15 13:09:0912#include "content/browser/notifications/platform_notification_context_impl.h"
peterd69823a12014-12-09 14:06:5913#include "content/browser/service_worker/service_worker_context_wrapper.h"
14#include "content/browser/service_worker/service_worker_registration.h"
15#include "content/browser/service_worker/service_worker_storage.h"
miguelg26f01962017-06-02 14:51:0916#include "content/common/platform_notification_messages.h"
peterd69823a12014-12-09 14:06:5917#include "content/public/browser/browser_context.h"
18#include "content/public/browser/browser_thread.h"
miguelg26f01962017-06-02 14:51:0919#include "content/public/browser/render_process_host.h"
peterd69823a12014-12-09 14:06:5920#include "content/public/browser/storage_partition.h"
peter7329c2c2014-12-12 14:42:5921#include "content/public/common/platform_notification_data.h"
peterd69823a12014-12-09 14:06:5922
23namespace content {
24namespace {
25
nsatragno2f82b23b2016-02-05 12:55:0926using NotificationDispatchCompleteCallback =
Peter Beverloo64337af2017-11-21 18:04:0227 base::Callback<void(PersistentNotificationStatus)>;
nsatragno2f82b23b2016-02-05 12:55:0928using NotificationOperationCallback =
29 base::Callback<void(const ServiceWorkerRegistration*,
30 const NotificationDatabaseData&)>;
31using NotificationOperationCallbackWithContext =
32 base::Callback<void(const scoped_refptr<PlatformNotificationContext>&,
33 const ServiceWorkerRegistration*,
34 const NotificationDatabaseData&)>;
peterd69823a12014-12-09 14:06:5935
nsatragno2f82b23b2016-02-05 12:55:0936// To be called when a notification event has finished executing. Will post a
37// task to call |dispatch_complete_callback| on the UI thread.
38void NotificationEventFinished(
39 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
40 PersistentNotificationStatus status) {
peterd69823a12014-12-09 14:06:5941 DCHECK_CURRENTLY_ON(BrowserThread::IO);
42
nsatragno2f82b23b2016-02-05 12:55:0943 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
tzike2aca992017-09-05 08:50:5444 base::BindOnce(dispatch_complete_callback, status));
nsatragno2f82b23b2016-02-05 12:55:0945}
46
47// To be called when a notification event has finished with a
48// ServiceWorkerStatusCode result. Will call NotificationEventFinished with a
49// PersistentNotificationStatus derived from the service worker status.
50void ServiceWorkerNotificationEventFinished(
51 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
52 ServiceWorkerStatusCode service_worker_status) {
peter80739bb2015-10-20 11:17:4653#if defined(OS_ANDROID)
54 // This LOG(INFO) deliberately exists to help track down the cause of
55 // https://crbug.com/534537, where notifications sometimes do not react to
56 // the user clicking on them. It should be removed once that's fixed.
nsatragno2f82b23b2016-02-05 12:55:0957 LOG(INFO) << "The notification event has finished: " << service_worker_status;
peter80739bb2015-10-20 11:17:4658#endif
59
peterd69823a12014-12-09 14:06:5960 PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
61 switch (service_worker_status) {
62 case SERVICE_WORKER_OK:
63 // Success status was initialized above.
64 break;
65 case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
66 status = PERSISTENT_NOTIFICATION_STATUS_EVENT_WAITUNTIL_REJECTED;
67 break;
68 case SERVICE_WORKER_ERROR_FAILED:
69 case SERVICE_WORKER_ERROR_ABORT:
70 case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
71 case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
72 case SERVICE_WORKER_ERROR_NOT_FOUND:
73 case SERVICE_WORKER_ERROR_EXISTS:
74 case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
75 case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
76 case SERVICE_WORKER_ERROR_IPC_FAILED:
77 case SERVICE_WORKER_ERROR_NETWORK:
78 case SERVICE_WORKER_ERROR_SECURITY:
xiang.longafc4f16f2015-02-04 07:04:5779 case SERVICE_WORKER_ERROR_STATE:
falken292e84a2015-03-05 16:54:2580 case SERVICE_WORKER_ERROR_TIMEOUT:
falken9573d4d2015-04-15 16:49:3981 case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
falkenfb74da92015-04-24 23:00:1982 case SERVICE_WORKER_ERROR_DISK_CACHE:
falken45f450e32015-06-09 04:33:1983 case SERVICE_WORKER_ERROR_REDUNDANT:
rdevlin.croninf5863da2015-09-10 19:21:4584 case SERVICE_WORKER_ERROR_DISALLOWED:
falken292e84a2015-03-05 16:54:2585 case SERVICE_WORKER_ERROR_MAX_VALUE:
peterd69823a12014-12-09 14:06:5986 status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
87 break;
88 }
nsatragno2f82b23b2016-02-05 12:55:0989 NotificationEventFinished(dispatch_complete_callback, status);
peterd69823a12014-12-09 14:06:5990}
91
nsatragno2f82b23b2016-02-05 12:55:0992// Dispatches the given notification action event on
93// |service_worker_registration| if the registration was available. Must be
94// called on the IO thread.
95void DispatchNotificationEventOnRegistration(
mekd9ef31152016-01-26 19:35:5596 const NotificationDatabaseData& notification_database_data,
nsatragno2f82b23b2016-02-05 12:55:0997 const scoped_refptr<PlatformNotificationContext>& notification_context,
98 const NotificationOperationCallback& dispatch_event_action,
99 const NotificationDispatchCompleteCallback& dispatch_error_callback,
peterd69823a12014-12-09 14:06:59100 ServiceWorkerStatusCode service_worker_status,
horo519e0542016-07-26 10:43:05101 scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
peterd69823a12014-12-09 14:06:59102 DCHECK_CURRENTLY_ON(BrowserThread::IO);
peter80739bb2015-10-20 11:17:46103#if defined(OS_ANDROID)
peter372525c2015-11-20 16:07:17104 // This LOG(INFO) deliberately exists to help track down the cause of
105 // https://crbug.com/534537, where notifications sometimes do not react to
106 // the user clicking on them. It should be removed once that's fixed.
miguelg9ac06e42015-11-02 19:15:04107 LOG(INFO) << "Trying to dispatch notification for SW with status: "
nsatragno2f82b23b2016-02-05 12:55:09108 << service_worker_status;
peter80739bb2015-10-20 11:17:46109#endif
miguelg9ac06e42015-11-02 19:15:04110 if (service_worker_status == SERVICE_WORKER_OK) {
nhiroki47def5cb2015-10-09 09:50:05111 DCHECK(service_worker_registration->active_version());
nsatragno2f82b23b2016-02-05 12:55:09112
113 dispatch_event_action.Run(service_worker_registration.get(),
114 notification_database_data);
peterd69823a12014-12-09 14:06:59115 return;
116 }
117
118 PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
119 switch (service_worker_status) {
120 case SERVICE_WORKER_ERROR_NOT_FOUND:
121 status = PERSISTENT_NOTIFICATION_STATUS_NO_SERVICE_WORKER;
122 break;
123 case SERVICE_WORKER_ERROR_FAILED:
124 case SERVICE_WORKER_ERROR_ABORT:
125 case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
126 case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
127 case SERVICE_WORKER_ERROR_EXISTS:
128 case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
129 case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
130 case SERVICE_WORKER_ERROR_IPC_FAILED:
131 case SERVICE_WORKER_ERROR_NETWORK:
132 case SERVICE_WORKER_ERROR_SECURITY:
133 case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
xiang.longafc4f16f2015-02-04 07:04:57134 case SERVICE_WORKER_ERROR_STATE:
falken292e84a2015-03-05 16:54:25135 case SERVICE_WORKER_ERROR_TIMEOUT:
falken9573d4d2015-04-15 16:49:39136 case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
falkenfb74da92015-04-24 23:00:19137 case SERVICE_WORKER_ERROR_DISK_CACHE:
falken45f450e32015-06-09 04:33:19138 case SERVICE_WORKER_ERROR_REDUNDANT:
rdevlin.croninf5863da2015-09-10 19:21:45139 case SERVICE_WORKER_ERROR_DISALLOWED:
falken292e84a2015-03-05 16:54:25140 case SERVICE_WORKER_ERROR_MAX_VALUE:
peterd69823a12014-12-09 14:06:59141 status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
142 break;
143 case SERVICE_WORKER_OK:
144 NOTREACHED();
145 break;
146 }
147
peter372525c2015-11-20 16:07:17148 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
tzike2aca992017-09-05 08:50:54149 base::BindOnce(dispatch_error_callback, status));
peterd69823a12014-12-09 14:06:59150}
151
152// Finds the ServiceWorkerRegistration associated with the |origin| and
153// |service_worker_registration_id|. Must be called on the IO thread.
154void FindServiceWorkerRegistration(
155 const GURL& origin,
nsatragno2f82b23b2016-02-05 12:55:09156 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
157 const scoped_refptr<PlatformNotificationContext>& notification_context,
158 const NotificationOperationCallback& notification_action_callback,
159 const NotificationDispatchCompleteCallback& dispatch_error_callback,
peter2ee1f3c2015-04-15 13:09:09160 bool success,
161 const NotificationDatabaseData& notification_database_data) {
peterd69823a12014-12-09 14:06:59162 DCHECK_CURRENTLY_ON(BrowserThread::IO);
miguelg9ac06e42015-11-02 19:15:04163
164#if defined(OS_ANDROID)
165 // This LOG(INFO) deliberately exists to help track down the cause of
166 // https://crbug.com/534537, where notifications sometimes do not react to
167 // the user clicking on them. It should be removed once that's fixed.
nsatragno2f82b23b2016-02-05 12:55:09168 LOG(INFO) << "Lookup for ServiceWoker Registration: success: " << success;
miguelg9ac06e42015-11-02 19:15:04169#endif
peter2ee1f3c2015-04-15 13:09:09170 if (!success) {
171 BrowserThread::PostTask(
peter372525c2015-11-20 16:07:17172 BrowserThread::UI, FROM_HERE,
tzike2aca992017-09-05 08:50:54173 base::BindOnce(dispatch_error_callback,
174 PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR));
peter2ee1f3c2015-04-15 13:09:09175 return;
176 }
177
nhiroki47def5cb2015-10-09 09:50:05178 service_worker_context->FindReadyRegistrationForId(
peter372525c2015-11-20 16:07:17179 notification_database_data.service_worker_registration_id, origin,
tzikff02d282018-02-22 06:11:08180 base::BindOnce(&DispatchNotificationEventOnRegistration,
181 notification_database_data, notification_context,
182 notification_action_callback, dispatch_error_callback));
peterd69823a12014-12-09 14:06:59183}
184
peterc45944c32016-09-13 14:35:59185// Reads the data associated with the |notification_id| belonging to |origin|
186// from the notification context.
peter2ee1f3c2015-04-15 13:09:09187void ReadNotificationDatabaseData(
peterc45944c32016-09-13 14:35:59188 const std::string& notification_id,
peter2ee1f3c2015-04-15 13:09:09189 const GURL& origin,
nsatragno2f82b23b2016-02-05 12:55:09190 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
191 const scoped_refptr<PlatformNotificationContext>& notification_context,
192 const NotificationOperationCallback& notification_read_callback,
193 const NotificationDispatchCompleteCallback& dispatch_error_callback) {
peter2ee1f3c2015-04-15 13:09:09194 DCHECK_CURRENTLY_ON(BrowserThread::IO);
195 notification_context->ReadNotificationData(
peterc45944c32016-09-13 14:35:59196 notification_id, origin,
nsatragno2f82b23b2016-02-05 12:55:09197 base::Bind(&FindServiceWorkerRegistration, origin, service_worker_context,
198 notification_context, notification_read_callback,
199 dispatch_error_callback));
200}
201
202// -----------------------------------------------------------------------------
203
Yannic Bonenberger157d58a2018-01-12 09:55:58204// Dispatches the notificationclick event on |service_worker|.
205// Must be called on the IO thread.
nsatragno2f82b23b2016-02-05 12:55:09206void DispatchNotificationClickEventOnWorker(
207 const scoped_refptr<ServiceWorkerVersion>& service_worker,
208 const NotificationDatabaseData& notification_database_data,
Peter Beverloo988ef962017-09-12 15:49:17209 const base::Optional<int>& action_index,
210 const base::Optional<base::string16>& reply,
Yannic Bonenberger157d58a2018-01-12 09:55:58211 ServiceWorkerVersion::StatusCallback callback,
212 ServiceWorkerStatusCode start_worker_status) {
nsatragno2f82b23b2016-02-05 12:55:09213 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Yannic Bonenberger157d58a2018-01-12 09:55:58214 if (start_worker_status != SERVICE_WORKER_OK) {
215 std::move(callback).Run(start_worker_status);
216 return;
217 }
218
nsatragno2f82b23b2016-02-05 12:55:09219 int request_id = service_worker->StartRequest(
Yannic Bonenberger12916242017-12-31 16:05:30220 ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, std::move(callback));
peterf8ea4c42017-02-13 18:08:36221
Peter Beverloo988ef962017-09-12 15:49:17222 int action_index_int = -1 /* no value */;
223 if (action_index.has_value())
224 action_index_int = action_index.value();
peterf8ea4c42017-02-13 18:08:36225
226 service_worker->event_dispatcher()->DispatchNotificationClickEvent(
227 notification_database_data.notification_id,
Peter Beverloo988ef962017-09-12 15:49:17228 notification_database_data.notification_data, action_index_int, reply,
229 service_worker->CreateSimpleEventCallback(request_id));
nsatragno2f82b23b2016-02-05 12:55:09230}
231
232// Dispatches the notification click event on the |service_worker_registration|.
233void DoDispatchNotificationClickEvent(
Peter Beverloo988ef962017-09-12 15:49:17234 const base::Optional<int>& action_index,
235 const base::Optional<base::string16>& reply,
nsatragno2f82b23b2016-02-05 12:55:09236 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
237 const scoped_refptr<PlatformNotificationContext>& notification_context,
238 const ServiceWorkerRegistration* service_worker_registration,
239 const NotificationDatabaseData& notification_database_data) {
nsatragno2f82b23b2016-02-05 12:55:09240 service_worker_registration->active_version()->RunAfterStartWorker(
falken98a21402016-03-16 05:21:34241 ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK,
Yannic Bonenberger0e2d7ce52017-08-21 02:54:04242 base::BindOnce(
nsatragno2f82b23b2016-02-05 12:55:09243 &DispatchNotificationClickEventOnWorker,
kylecharda69d882017-10-04 05:49:52244 base::WrapRefCounted(service_worker_registration->active_version()),
Yannic Bonenberger12916242017-12-31 16:05:30245 notification_database_data, action_index, reply,
246 base::BindOnce(&ServiceWorkerNotificationEventFinished,
Yannic Bonenberger157d58a2018-01-12 09:55:58247 dispatch_complete_callback)));
nsatragno2f82b23b2016-02-05 12:55:09248}
249
250// -----------------------------------------------------------------------------
251
252// Called when the notification data has been deleted to finish the notification
253// close event.
254void OnPersistentNotificationDataDeleted(
255 ServiceWorkerStatusCode service_worker_status,
256 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
257 bool success) {
258 if (service_worker_status != SERVICE_WORKER_OK) {
259 ServiceWorkerNotificationEventFinished(dispatch_complete_callback,
260 service_worker_status);
261 return;
262 }
263 NotificationEventFinished(
264 dispatch_complete_callback,
265 success ? PERSISTENT_NOTIFICATION_STATUS_SUCCESS
266 : PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR);
267}
268
269// Called when the persistent notification close event has been handled
270// to remove the notification from the database.
271void DeleteNotificationDataFromDatabase(
peterc45944c32016-09-13 14:35:59272 const std::string& notification_id,
nsatragno2f82b23b2016-02-05 12:55:09273 const GURL& origin,
274 const scoped_refptr<PlatformNotificationContext>& notification_context,
275 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
276 ServiceWorkerStatusCode status_code) {
277 notification_context->DeleteNotificationData(
278 notification_id, origin,
279 base::Bind(&OnPersistentNotificationDataDeleted, status_code,
280 dispatch_complete_callback));
281}
282
Yannic Bonenberger157d58a2018-01-12 09:55:58283// Dispatches the notificationclose event on |service_worker|.
284// Must be called on the IO thread.
nsatragno2f82b23b2016-02-05 12:55:09285void DispatchNotificationCloseEventOnWorker(
286 const scoped_refptr<ServiceWorkerVersion>& service_worker,
287 const NotificationDatabaseData& notification_database_data,
Yannic Bonenberger157d58a2018-01-12 09:55:58288 ServiceWorkerVersion::StatusCallback callback,
289 ServiceWorkerStatusCode start_worker_status) {
nsatragno2f82b23b2016-02-05 12:55:09290 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Yannic Bonenberger157d58a2018-01-12 09:55:58291 if (start_worker_status != SERVICE_WORKER_OK) {
292 std::move(callback).Run(start_worker_status);
293 return;
294 }
295
nsatragno2f82b23b2016-02-05 12:55:09296 int request_id = service_worker->StartRequest(
Yannic Bonenberger12916242017-12-31 16:05:30297 ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, std::move(callback));
peterf8ea4c42017-02-13 18:08:36298
299 service_worker->event_dispatcher()->DispatchNotificationCloseEvent(
300 notification_database_data.notification_id,
301 notification_database_data.notification_data,
302 service_worker->CreateSimpleEventCallback(request_id));
nsatragno2f82b23b2016-02-05 12:55:09303}
304
Yannic Bonenberger12916242017-12-31 16:05:30305// Dispatches the notification close event on the service worker registration.
nsatragno2f82b23b2016-02-05 12:55:09306void DoDispatchNotificationCloseEvent(
peterc45944c32016-09-13 14:35:59307 const std::string& notification_id,
nsatragno2f82b23b2016-02-05 12:55:09308 bool by_user,
309 const NotificationDispatchCompleteCallback& dispatch_complete_callback,
310 const scoped_refptr<PlatformNotificationContext>& notification_context,
311 const ServiceWorkerRegistration* service_worker_registration,
312 const NotificationDatabaseData& notification_database_data) {
nsatragno2f82b23b2016-02-05 12:55:09313 if (by_user) {
314 service_worker_registration->active_version()->RunAfterStartWorker(
falken98a21402016-03-16 05:21:34315 ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE,
Yannic Bonenberger0e2d7ce52017-08-21 02:54:04316 base::BindOnce(
nsatragno2f82b23b2016-02-05 12:55:09317 &DispatchNotificationCloseEventOnWorker,
kylecharda69d882017-10-04 05:49:52318 base::WrapRefCounted(service_worker_registration->active_version()),
Yannic Bonenberger12916242017-12-31 16:05:30319 notification_database_data,
320 base::BindOnce(&DeleteNotificationDataFromDatabase, notification_id,
321 notification_database_data.origin,
Yannic Bonenberger157d58a2018-01-12 09:55:58322 notification_context, dispatch_complete_callback)));
nsatragno2f82b23b2016-02-05 12:55:09323 } else {
Yannic Bonenberger12916242017-12-31 16:05:30324 DeleteNotificationDataFromDatabase(
325 notification_id, notification_database_data.origin,
326 notification_context, dispatch_complete_callback,
327 ServiceWorkerStatusCode::SERVICE_WORKER_OK);
nsatragno2f82b23b2016-02-05 12:55:09328 }
329}
330
331// Dispatches any notification event. The actual, specific event dispatch should
332// be done by the |notification_action_callback|.
333void DispatchNotificationEvent(
334 BrowserContext* browser_context,
peterc45944c32016-09-13 14:35:59335 const std::string& notification_id,
nsatragno2f82b23b2016-02-05 12:55:09336 const GURL& origin,
337 const NotificationOperationCallbackWithContext&
338 notification_action_callback,
339 const NotificationDispatchCompleteCallback& notification_error_callback) {
340 DCHECK_CURRENTLY_ON(BrowserThread::UI);
peterc45944c32016-09-13 14:35:59341 DCHECK(!notification_id.empty());
nsatragno2f82b23b2016-02-05 12:55:09342 DCHECK(origin.is_valid());
343
344 StoragePartition* partition =
345 BrowserContext::GetStoragePartitionForSite(browser_context, origin);
346
347 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
348 static_cast<ServiceWorkerContextWrapper*>(
349 partition->GetServiceWorkerContext());
350 scoped_refptr<PlatformNotificationContext> notification_context =
351 partition->GetPlatformNotificationContext();
352
353 BrowserThread::PostTask(
354 BrowserThread::IO, FROM_HERE,
tzike2aca992017-09-05 08:50:54355 base::BindOnce(
356 &ReadNotificationDatabaseData, notification_id, origin,
357 service_worker_context, notification_context,
358 base::Bind(notification_action_callback, notification_context),
359 notification_error_callback));
peter2ee1f3c2015-04-15 13:09:09360}
361
peterd69823a12014-12-09 14:06:59362} // namespace
363
364// static
365NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() {
366 return NotificationEventDispatcherImpl::GetInstance();
367}
368
369NotificationEventDispatcherImpl*
370NotificationEventDispatcherImpl::GetInstance() {
371 DCHECK_CURRENTLY_ON(BrowserThread::UI);
olli.raula36aa8be2015-09-10 11:14:22372 return base::Singleton<NotificationEventDispatcherImpl>::get();
peterd69823a12014-12-09 14:06:59373}
374
miguelg26f01962017-06-02 14:51:09375NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() = default;
376NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() = default;
peterd69823a12014-12-09 14:06:59377
378void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
379 BrowserContext* browser_context,
peterc45944c32016-09-13 14:35:59380 const std::string& notification_id,
peterd69823a12014-12-09 14:06:59381 const GURL& origin,
Peter Beverloo988ef962017-09-12 15:49:17382 const base::Optional<int>& action_index,
383 const base::Optional<base::string16>& reply,
Peter Beverloo64337af2017-11-21 18:04:02384 NotificationDispatchCompleteCallback dispatch_complete_callback) {
385 // TODO(peter): Remove AdaptCallbackForRepeating() when the dependencies of
386 // the NotificationEventDispatcherImpl have updated to using OnceCallbacks.
387 auto repeating_callback =
388 base::AdaptCallbackForRepeating(std::move(dispatch_complete_callback));
389
nsatragno2f82b23b2016-02-05 12:55:09390 DispatchNotificationEvent(
peterc45944c32016-09-13 14:35:59391 browser_context, notification_id, origin,
awdff42998e2016-10-13 16:58:54392 base::Bind(&DoDispatchNotificationClickEvent, action_index, reply,
Peter Beverloo64337af2017-11-21 18:04:02393 repeating_callback),
394 repeating_callback /* notification_error_callback */);
nsatragno2f82b23b2016-02-05 12:55:09395}
peterd69823a12014-12-09 14:06:59396
nsatragno2f82b23b2016-02-05 12:55:09397void NotificationEventDispatcherImpl::DispatchNotificationCloseEvent(
398 BrowserContext* browser_context,
peterc45944c32016-09-13 14:35:59399 const std::string& notification_id,
nsatragno2f82b23b2016-02-05 12:55:09400 const GURL& origin,
401 bool by_user,
Peter Beverloo64337af2017-11-21 18:04:02402 NotificationDispatchCompleteCallback dispatch_complete_callback) {
403 // TODO(peter): Remove AdaptCallbackForRepeating() when the dependencies of
404 // the NotificationEventDispatcherImpl have updated to using OnceCallbacks.
405 auto repeating_callback =
406 base::AdaptCallbackForRepeating(std::move(dispatch_complete_callback));
407
peterc45944c32016-09-13 14:35:59408 DispatchNotificationEvent(
409 browser_context, notification_id, origin,
410 base::Bind(&DoDispatchNotificationCloseEvent, notification_id, by_user,
Peter Beverloo64337af2017-11-21 18:04:02411 repeating_callback),
412 repeating_callback /* notification_error_callback */);
peterd69823a12014-12-09 14:06:59413}
414
Anita Woodrufff5ae28e2018-01-25 18:22:38415void NotificationEventDispatcherImpl::RegisterNonPersistentNotificationListener(
416 const std::string& notification_id,
417 blink::mojom::NonPersistentNotificationListenerPtrInfo listener_ptr_info) {
418 if (non_persistent_notification_listeners_.count(notification_id)) {
419 // Dispatch the close event for any previously displayed notification with
420 // the same notification id. This happens whenever a non-persistent
421 // notification is replaced (by creating another with the same tag), since
422 // from the JavaScript point of view there will be two notification objects,
423 // and the old one needs to receive a close event before the new one
424 // receives a show event.
425 DispatchNonPersistentCloseEvent(notification_id);
426 }
427
428 blink::mojom::NonPersistentNotificationListenerPtr listener_ptr(
429 std::move(listener_ptr_info));
430
431 // Observe connection errors, which occur when the JavaScript object or the
432 // renderer hosting them goes away. (For example through navigation.) The
433 // listener gets freed together with |this|, thus the Unretained is safe.
434 listener_ptr.set_connection_error_handler(base::BindOnce(
435 &NotificationEventDispatcherImpl::
436 HandleConnectionErrorForNonPersistentNotificationListener,
437 base::Unretained(this), notification_id));
438
439 non_persistent_notification_listeners_.emplace(notification_id,
440 std::move(listener_ptr));
441}
442
miguelg26f01962017-06-02 14:51:09443void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent(
444 const std::string& notification_id) {
Anita Woodruffef76ee3e62018-02-12 14:19:41445 if (!non_persistent_notification_listeners_.count(notification_id))
Anita Woodrufff5ae28e2018-01-25 18:22:38446 return;
Anita Woodruffef76ee3e62018-02-12 14:19:41447 non_persistent_notification_listeners_[notification_id]->OnShow();
miguelg26f01962017-06-02 14:51:09448}
449
450void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent(
451 const std::string& notification_id) {
Anita Woodruffef76ee3e62018-02-12 14:19:41452 if (!non_persistent_notification_listeners_.count(notification_id))
Anita Woodrufff5ae28e2018-01-25 18:22:38453 return;
Anita Woodruffef76ee3e62018-02-12 14:19:41454 non_persistent_notification_listeners_[notification_id]->OnClick();
miguelg26f01962017-06-02 14:51:09455}
456
457void NotificationEventDispatcherImpl::DispatchNonPersistentCloseEvent(
458 const std::string& notification_id) {
Anita Woodruffef76ee3e62018-02-12 14:19:41459 if (!non_persistent_notification_listeners_.count(notification_id))
Anita Woodrufff5ae28e2018-01-25 18:22:38460 return;
Anita Woodruffef76ee3e62018-02-12 14:19:41461 non_persistent_notification_listeners_[notification_id]->OnClose();
462 non_persistent_notification_listeners_.erase(notification_id);
miguelg26f01962017-06-02 14:51:09463}
464
Anita Woodrufff5ae28e2018-01-25 18:22:38465void NotificationEventDispatcherImpl::
466 HandleConnectionErrorForNonPersistentNotificationListener(
467 const std::string& notification_id) {
468 DCHECK(non_persistent_notification_listeners_.count(notification_id));
469 non_persistent_notification_listeners_.erase(notification_id);
470}
471
peterd69823a12014-12-09 14:06:59472} // namespace content