peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "content/browser/notifications/notification_event_dispatcher_impl.h" |
| 6 | |
| 7 | #include "base/callback.h" |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 8 | #include "base/callback_helpers.h" |
peter | f8ea4c4 | 2017-02-13 18:08:36 | [diff] [blame] | 9 | #include "base/optional.h" |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 10 | #include "build/build_config.h" |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 11 | #include "content/browser/notifications/notification_message_filter.h" |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 12 | #include "content/browser/notifications/platform_notification_context_impl.h" |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 13 | #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" |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 16 | #include "content/common/platform_notification_messages.h" |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 17 | #include "content/public/browser/browser_context.h" |
| 18 | #include "content/public/browser/browser_thread.h" |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 19 | #include "content/public/browser/render_process_host.h" |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 20 | #include "content/public/browser/storage_partition.h" |
peter | 7329c2c | 2014-12-12 14:42:59 | [diff] [blame] | 21 | #include "content/public/common/platform_notification_data.h" |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 22 | |
| 23 | namespace content { |
| 24 | namespace { |
| 25 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 26 | using NotificationDispatchCompleteCallback = |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 27 | base::Callback<void(PersistentNotificationStatus)>; |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 28 | using NotificationOperationCallback = |
| 29 | base::Callback<void(const ServiceWorkerRegistration*, |
| 30 | const NotificationDatabaseData&)>; |
| 31 | using NotificationOperationCallbackWithContext = |
| 32 | base::Callback<void(const scoped_refptr<PlatformNotificationContext>&, |
| 33 | const ServiceWorkerRegistration*, |
| 34 | const NotificationDatabaseData&)>; |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 35 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 36 | // To be called when a notification event has finished executing. Will post a |
| 37 | // task to call |dispatch_complete_callback| on the UI thread. |
| 38 | void NotificationEventFinished( |
| 39 | const NotificationDispatchCompleteCallback& dispatch_complete_callback, |
| 40 | PersistentNotificationStatus status) { |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 41 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 42 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 43 | BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
tzik | e2aca99 | 2017-09-05 08:50:54 | [diff] [blame] | 44 | base::BindOnce(dispatch_complete_callback, status)); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 45 | } |
| 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. |
| 50 | void ServiceWorkerNotificationEventFinished( |
| 51 | const NotificationDispatchCompleteCallback& dispatch_complete_callback, |
| 52 | ServiceWorkerStatusCode service_worker_status) { |
peter | 80739bb | 2015-10-20 11:17:46 | [diff] [blame] | 53 | #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. |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 57 | LOG(INFO) << "The notification event has finished: " << service_worker_status; |
peter | 80739bb | 2015-10-20 11:17:46 | [diff] [blame] | 58 | #endif |
| 59 | |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 60 | 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.long | afc4f16f | 2015-02-04 07:04:57 | [diff] [blame] | 79 | case SERVICE_WORKER_ERROR_STATE: |
falken | 292e84a | 2015-03-05 16:54:25 | [diff] [blame] | 80 | case SERVICE_WORKER_ERROR_TIMEOUT: |
falken | 9573d4d | 2015-04-15 16:49:39 | [diff] [blame] | 81 | case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: |
falken | fb74da9 | 2015-04-24 23:00:19 | [diff] [blame] | 82 | case SERVICE_WORKER_ERROR_DISK_CACHE: |
falken | 45f450e3 | 2015-06-09 04:33:19 | [diff] [blame] | 83 | case SERVICE_WORKER_ERROR_REDUNDANT: |
rdevlin.cronin | f5863da | 2015-09-10 19:21:45 | [diff] [blame] | 84 | case SERVICE_WORKER_ERROR_DISALLOWED: |
falken | 292e84a | 2015-03-05 16:54:25 | [diff] [blame] | 85 | case SERVICE_WORKER_ERROR_MAX_VALUE: |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 86 | status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR; |
| 87 | break; |
| 88 | } |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 89 | NotificationEventFinished(dispatch_complete_callback, status); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 90 | } |
| 91 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 92 | // Dispatches the given notification action event on |
| 93 | // |service_worker_registration| if the registration was available. Must be |
| 94 | // called on the IO thread. |
| 95 | void DispatchNotificationEventOnRegistration( |
mek | d9ef3115 | 2016-01-26 19:35:55 | [diff] [blame] | 96 | const NotificationDatabaseData& notification_database_data, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 97 | const scoped_refptr<PlatformNotificationContext>& notification_context, |
| 98 | const NotificationOperationCallback& dispatch_event_action, |
| 99 | const NotificationDispatchCompleteCallback& dispatch_error_callback, |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 100 | ServiceWorkerStatusCode service_worker_status, |
horo | 519e054 | 2016-07-26 10:43:05 | [diff] [blame] | 101 | scoped_refptr<ServiceWorkerRegistration> service_worker_registration) { |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 102 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
peter | 80739bb | 2015-10-20 11:17:46 | [diff] [blame] | 103 | #if defined(OS_ANDROID) |
peter | 372525c | 2015-11-20 16:07:17 | [diff] [blame] | 104 | // 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. |
miguelg | 9ac06e4 | 2015-11-02 19:15:04 | [diff] [blame] | 107 | LOG(INFO) << "Trying to dispatch notification for SW with status: " |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 108 | << service_worker_status; |
peter | 80739bb | 2015-10-20 11:17:46 | [diff] [blame] | 109 | #endif |
miguelg | 9ac06e4 | 2015-11-02 19:15:04 | [diff] [blame] | 110 | if (service_worker_status == SERVICE_WORKER_OK) { |
nhiroki | 47def5cb | 2015-10-09 09:50:05 | [diff] [blame] | 111 | DCHECK(service_worker_registration->active_version()); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 112 | |
| 113 | dispatch_event_action.Run(service_worker_registration.get(), |
| 114 | notification_database_data); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 115 | 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.long | afc4f16f | 2015-02-04 07:04:57 | [diff] [blame] | 134 | case SERVICE_WORKER_ERROR_STATE: |
falken | 292e84a | 2015-03-05 16:54:25 | [diff] [blame] | 135 | case SERVICE_WORKER_ERROR_TIMEOUT: |
falken | 9573d4d | 2015-04-15 16:49:39 | [diff] [blame] | 136 | case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: |
falken | fb74da9 | 2015-04-24 23:00:19 | [diff] [blame] | 137 | case SERVICE_WORKER_ERROR_DISK_CACHE: |
falken | 45f450e3 | 2015-06-09 04:33:19 | [diff] [blame] | 138 | case SERVICE_WORKER_ERROR_REDUNDANT: |
rdevlin.cronin | f5863da | 2015-09-10 19:21:45 | [diff] [blame] | 139 | case SERVICE_WORKER_ERROR_DISALLOWED: |
falken | 292e84a | 2015-03-05 16:54:25 | [diff] [blame] | 140 | case SERVICE_WORKER_ERROR_MAX_VALUE: |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 141 | status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR; |
| 142 | break; |
| 143 | case SERVICE_WORKER_OK: |
| 144 | NOTREACHED(); |
| 145 | break; |
| 146 | } |
| 147 | |
peter | 372525c | 2015-11-20 16:07:17 | [diff] [blame] | 148 | BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
tzik | e2aca99 | 2017-09-05 08:50:54 | [diff] [blame] | 149 | base::BindOnce(dispatch_error_callback, status)); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | // Finds the ServiceWorkerRegistration associated with the |origin| and |
| 153 | // |service_worker_registration_id|. Must be called on the IO thread. |
| 154 | void FindServiceWorkerRegistration( |
| 155 | const GURL& origin, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 156 | 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, |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 160 | bool success, |
| 161 | const NotificationDatabaseData& notification_database_data) { |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 162 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
miguelg | 9ac06e4 | 2015-11-02 19:15:04 | [diff] [blame] | 163 | |
| 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. |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 168 | LOG(INFO) << "Lookup for ServiceWoker Registration: success: " << success; |
miguelg | 9ac06e4 | 2015-11-02 19:15:04 | [diff] [blame] | 169 | #endif |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 170 | if (!success) { |
| 171 | BrowserThread::PostTask( |
peter | 372525c | 2015-11-20 16:07:17 | [diff] [blame] | 172 | BrowserThread::UI, FROM_HERE, |
tzik | e2aca99 | 2017-09-05 08:50:54 | [diff] [blame] | 173 | base::BindOnce(dispatch_error_callback, |
| 174 | PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR)); |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 175 | return; |
| 176 | } |
| 177 | |
nhiroki | 47def5cb | 2015-10-09 09:50:05 | [diff] [blame] | 178 | service_worker_context->FindReadyRegistrationForId( |
peter | 372525c | 2015-11-20 16:07:17 | [diff] [blame] | 179 | notification_database_data.service_worker_registration_id, origin, |
tzik | ff02d28 | 2018-02-22 06:11:08 | [diff] [blame^] | 180 | base::BindOnce(&DispatchNotificationEventOnRegistration, |
| 181 | notification_database_data, notification_context, |
| 182 | notification_action_callback, dispatch_error_callback)); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 183 | } |
| 184 | |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 185 | // Reads the data associated with the |notification_id| belonging to |origin| |
| 186 | // from the notification context. |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 187 | void ReadNotificationDatabaseData( |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 188 | const std::string& notification_id, |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 189 | const GURL& origin, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 190 | 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) { |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 194 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 195 | notification_context->ReadNotificationData( |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 196 | notification_id, origin, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 197 | base::Bind(&FindServiceWorkerRegistration, origin, service_worker_context, |
| 198 | notification_context, notification_read_callback, |
| 199 | dispatch_error_callback)); |
| 200 | } |
| 201 | |
| 202 | // ----------------------------------------------------------------------------- |
| 203 | |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 204 | // Dispatches the notificationclick event on |service_worker|. |
| 205 | // Must be called on the IO thread. |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 206 | void DispatchNotificationClickEventOnWorker( |
| 207 | const scoped_refptr<ServiceWorkerVersion>& service_worker, |
| 208 | const NotificationDatabaseData& notification_database_data, |
Peter Beverloo | 988ef96 | 2017-09-12 15:49:17 | [diff] [blame] | 209 | const base::Optional<int>& action_index, |
| 210 | const base::Optional<base::string16>& reply, |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 211 | ServiceWorkerVersion::StatusCallback callback, |
| 212 | ServiceWorkerStatusCode start_worker_status) { |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 213 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 214 | if (start_worker_status != SERVICE_WORKER_OK) { |
| 215 | std::move(callback).Run(start_worker_status); |
| 216 | return; |
| 217 | } |
| 218 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 219 | int request_id = service_worker->StartRequest( |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 220 | ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, std::move(callback)); |
peter | f8ea4c4 | 2017-02-13 18:08:36 | [diff] [blame] | 221 | |
Peter Beverloo | 988ef96 | 2017-09-12 15:49:17 | [diff] [blame] | 222 | int action_index_int = -1 /* no value */; |
| 223 | if (action_index.has_value()) |
| 224 | action_index_int = action_index.value(); |
peter | f8ea4c4 | 2017-02-13 18:08:36 | [diff] [blame] | 225 | |
| 226 | service_worker->event_dispatcher()->DispatchNotificationClickEvent( |
| 227 | notification_database_data.notification_id, |
Peter Beverloo | 988ef96 | 2017-09-12 15:49:17 | [diff] [blame] | 228 | notification_database_data.notification_data, action_index_int, reply, |
| 229 | service_worker->CreateSimpleEventCallback(request_id)); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | // Dispatches the notification click event on the |service_worker_registration|. |
| 233 | void DoDispatchNotificationClickEvent( |
Peter Beverloo | 988ef96 | 2017-09-12 15:49:17 | [diff] [blame] | 234 | const base::Optional<int>& action_index, |
| 235 | const base::Optional<base::string16>& reply, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 236 | const NotificationDispatchCompleteCallback& dispatch_complete_callback, |
| 237 | const scoped_refptr<PlatformNotificationContext>& notification_context, |
| 238 | const ServiceWorkerRegistration* service_worker_registration, |
| 239 | const NotificationDatabaseData& notification_database_data) { |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 240 | service_worker_registration->active_version()->RunAfterStartWorker( |
falken | 98a2140 | 2016-03-16 05:21:34 | [diff] [blame] | 241 | ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, |
Yannic Bonenberger | 0e2d7ce5 | 2017-08-21 02:54:04 | [diff] [blame] | 242 | base::BindOnce( |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 243 | &DispatchNotificationClickEventOnWorker, |
kylechar | da69d88 | 2017-10-04 05:49:52 | [diff] [blame] | 244 | base::WrapRefCounted(service_worker_registration->active_version()), |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 245 | notification_database_data, action_index, reply, |
| 246 | base::BindOnce(&ServiceWorkerNotificationEventFinished, |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 247 | dispatch_complete_callback))); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | // ----------------------------------------------------------------------------- |
| 251 | |
| 252 | // Called when the notification data has been deleted to finish the notification |
| 253 | // close event. |
| 254 | void 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. |
| 271 | void DeleteNotificationDataFromDatabase( |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 272 | const std::string& notification_id, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 273 | 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 Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 283 | // Dispatches the notificationclose event on |service_worker|. |
| 284 | // Must be called on the IO thread. |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 285 | void DispatchNotificationCloseEventOnWorker( |
| 286 | const scoped_refptr<ServiceWorkerVersion>& service_worker, |
| 287 | const NotificationDatabaseData& notification_database_data, |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 288 | ServiceWorkerVersion::StatusCallback callback, |
| 289 | ServiceWorkerStatusCode start_worker_status) { |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 290 | DCHECK_CURRENTLY_ON(BrowserThread::IO); |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 291 | if (start_worker_status != SERVICE_WORKER_OK) { |
| 292 | std::move(callback).Run(start_worker_status); |
| 293 | return; |
| 294 | } |
| 295 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 296 | int request_id = service_worker->StartRequest( |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 297 | ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, std::move(callback)); |
peter | f8ea4c4 | 2017-02-13 18:08:36 | [diff] [blame] | 298 | |
| 299 | service_worker->event_dispatcher()->DispatchNotificationCloseEvent( |
| 300 | notification_database_data.notification_id, |
| 301 | notification_database_data.notification_data, |
| 302 | service_worker->CreateSimpleEventCallback(request_id)); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 303 | } |
| 304 | |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 305 | // Dispatches the notification close event on the service worker registration. |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 306 | void DoDispatchNotificationCloseEvent( |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 307 | const std::string& notification_id, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 308 | 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) { |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 313 | if (by_user) { |
| 314 | service_worker_registration->active_version()->RunAfterStartWorker( |
falken | 98a2140 | 2016-03-16 05:21:34 | [diff] [blame] | 315 | ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, |
Yannic Bonenberger | 0e2d7ce5 | 2017-08-21 02:54:04 | [diff] [blame] | 316 | base::BindOnce( |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 317 | &DispatchNotificationCloseEventOnWorker, |
kylechar | da69d88 | 2017-10-04 05:49:52 | [diff] [blame] | 318 | base::WrapRefCounted(service_worker_registration->active_version()), |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 319 | notification_database_data, |
| 320 | base::BindOnce(&DeleteNotificationDataFromDatabase, notification_id, |
| 321 | notification_database_data.origin, |
Yannic Bonenberger | 157d58a | 2018-01-12 09:55:58 | [diff] [blame] | 322 | notification_context, dispatch_complete_callback))); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 323 | } else { |
Yannic Bonenberger | 1291624 | 2017-12-31 16:05:30 | [diff] [blame] | 324 | DeleteNotificationDataFromDatabase( |
| 325 | notification_id, notification_database_data.origin, |
| 326 | notification_context, dispatch_complete_callback, |
| 327 | ServiceWorkerStatusCode::SERVICE_WORKER_OK); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 328 | } |
| 329 | } |
| 330 | |
| 331 | // Dispatches any notification event. The actual, specific event dispatch should |
| 332 | // be done by the |notification_action_callback|. |
| 333 | void DispatchNotificationEvent( |
| 334 | BrowserContext* browser_context, |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 335 | const std::string& notification_id, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 336 | const GURL& origin, |
| 337 | const NotificationOperationCallbackWithContext& |
| 338 | notification_action_callback, |
| 339 | const NotificationDispatchCompleteCallback& notification_error_callback) { |
| 340 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 341 | DCHECK(!notification_id.empty()); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 342 | 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, |
tzik | e2aca99 | 2017-09-05 08:50:54 | [diff] [blame] | 355 | 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)); |
peter | 2ee1f3c | 2015-04-15 13:09:09 | [diff] [blame] | 360 | } |
| 361 | |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 362 | } // namespace |
| 363 | |
| 364 | // static |
| 365 | NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() { |
| 366 | return NotificationEventDispatcherImpl::GetInstance(); |
| 367 | } |
| 368 | |
| 369 | NotificationEventDispatcherImpl* |
| 370 | NotificationEventDispatcherImpl::GetInstance() { |
| 371 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
olli.raula | 36aa8be | 2015-09-10 11:14:22 | [diff] [blame] | 372 | return base::Singleton<NotificationEventDispatcherImpl>::get(); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 373 | } |
| 374 | |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 375 | NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() = default; |
| 376 | NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() = default; |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 377 | |
| 378 | void NotificationEventDispatcherImpl::DispatchNotificationClickEvent( |
| 379 | BrowserContext* browser_context, |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 380 | const std::string& notification_id, |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 381 | const GURL& origin, |
Peter Beverloo | 988ef96 | 2017-09-12 15:49:17 | [diff] [blame] | 382 | const base::Optional<int>& action_index, |
| 383 | const base::Optional<base::string16>& reply, |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 384 | 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 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 390 | DispatchNotificationEvent( |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 391 | browser_context, notification_id, origin, |
awdf | f42998e | 2016-10-13 16:58:54 | [diff] [blame] | 392 | base::Bind(&DoDispatchNotificationClickEvent, action_index, reply, |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 393 | repeating_callback), |
| 394 | repeating_callback /* notification_error_callback */); |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 395 | } |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 396 | |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 397 | void NotificationEventDispatcherImpl::DispatchNotificationCloseEvent( |
| 398 | BrowserContext* browser_context, |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 399 | const std::string& notification_id, |
nsatragno | 2f82b23b | 2016-02-05 12:55:09 | [diff] [blame] | 400 | const GURL& origin, |
| 401 | bool by_user, |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 402 | 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 | |
peter | c45944c3 | 2016-09-13 14:35:59 | [diff] [blame] | 408 | DispatchNotificationEvent( |
| 409 | browser_context, notification_id, origin, |
| 410 | base::Bind(&DoDispatchNotificationCloseEvent, notification_id, by_user, |
Peter Beverloo | 64337af | 2017-11-21 18:04:02 | [diff] [blame] | 411 | repeating_callback), |
| 412 | repeating_callback /* notification_error_callback */); |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 413 | } |
| 414 | |
Anita Woodruff | f5ae28e | 2018-01-25 18:22:38 | [diff] [blame] | 415 | void 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 | |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 443 | void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent( |
| 444 | const std::string& notification_id) { |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 445 | if (!non_persistent_notification_listeners_.count(notification_id)) |
Anita Woodruff | f5ae28e | 2018-01-25 18:22:38 | [diff] [blame] | 446 | return; |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 447 | non_persistent_notification_listeners_[notification_id]->OnShow(); |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 448 | } |
| 449 | |
| 450 | void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent( |
| 451 | const std::string& notification_id) { |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 452 | if (!non_persistent_notification_listeners_.count(notification_id)) |
Anita Woodruff | f5ae28e | 2018-01-25 18:22:38 | [diff] [blame] | 453 | return; |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 454 | non_persistent_notification_listeners_[notification_id]->OnClick(); |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 455 | } |
| 456 | |
| 457 | void NotificationEventDispatcherImpl::DispatchNonPersistentCloseEvent( |
| 458 | const std::string& notification_id) { |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 459 | if (!non_persistent_notification_listeners_.count(notification_id)) |
Anita Woodruff | f5ae28e | 2018-01-25 18:22:38 | [diff] [blame] | 460 | return; |
Anita Woodruff | ef76ee3e6 | 2018-02-12 14:19:41 | [diff] [blame] | 461 | non_persistent_notification_listeners_[notification_id]->OnClose(); |
| 462 | non_persistent_notification_listeners_.erase(notification_id); |
miguelg | 26f0196 | 2017-06-02 14:51:09 | [diff] [blame] | 463 | } |
| 464 | |
Anita Woodruff | f5ae28e | 2018-01-25 18:22:38 | [diff] [blame] | 465 | void 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 | |
peter | d69823a1 | 2014-12-09 14:06:59 | [diff] [blame] | 472 | } // namespace content |