blob: 9f08158ec1f06564ff66952643a46c96a421792d [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"
peter2ee1f3c2015-04-15 13:09:098#include "base/strings/string_number_conversions.h"
9#include "content/browser/notifications/platform_notification_context_impl.h"
peterd69823a12014-12-09 14:06:5910#include "content/browser/service_worker/service_worker_context_wrapper.h"
11#include "content/browser/service_worker/service_worker_registration.h"
12#include "content/browser/service_worker/service_worker_storage.h"
13#include "content/public/browser/browser_context.h"
14#include "content/public/browser/browser_thread.h"
peter2ee1f3c2015-04-15 13:09:0915#include "content/public/browser/notification_database_data.h"
peterd69823a12014-12-09 14:06:5916#include "content/public/browser/storage_partition.h"
peter7329c2c2014-12-12 14:42:5917#include "content/public/common/platform_notification_data.h"
peterd69823a12014-12-09 14:06:5918
19namespace content {
20namespace {
21
22using NotificationClickDispatchCompleteCallback =
23 NotificationEventDispatcher::NotificationClickDispatchCompleteCallback;
24
25// To be called when the notificationclick event has finished executing. Will
26// post a task to call |dispatch_complete_callback| on the UI thread.
27void NotificationClickEventFinished(
28 const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
29 const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
30 ServiceWorkerStatusCode service_worker_status) {
31 DCHECK_CURRENTLY_ON(BrowserThread::IO);
32
33 PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
34 switch (service_worker_status) {
35 case SERVICE_WORKER_OK:
36 // Success status was initialized above.
37 break;
38 case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
39 status = PERSISTENT_NOTIFICATION_STATUS_EVENT_WAITUNTIL_REJECTED;
40 break;
41 case SERVICE_WORKER_ERROR_FAILED:
42 case SERVICE_WORKER_ERROR_ABORT:
43 case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
44 case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
45 case SERVICE_WORKER_ERROR_NOT_FOUND:
46 case SERVICE_WORKER_ERROR_EXISTS:
47 case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
48 case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
49 case SERVICE_WORKER_ERROR_IPC_FAILED:
50 case SERVICE_WORKER_ERROR_NETWORK:
51 case SERVICE_WORKER_ERROR_SECURITY:
xiang.longafc4f16f2015-02-04 07:04:5752 case SERVICE_WORKER_ERROR_STATE:
falken292e84a2015-03-05 16:54:2553 case SERVICE_WORKER_ERROR_TIMEOUT:
54 case SERVICE_WORKER_ERROR_MAX_VALUE:
peterd69823a12014-12-09 14:06:5955 status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
56 break;
57 }
58
59 BrowserThread::PostTask(BrowserThread::UI,
60 FROM_HERE,
61 base::Bind(dispatch_complete_callback, status));
62}
63
64// Dispatches the notificationclick on |service_worker_registration| if the
65// registration was available. Must be called on the IO thread.
66void DispatchNotificationClickEventOnRegistration(
peter2ee1f3c2015-04-15 13:09:0967 const NotificationDatabaseData& notification_database_data,
peterd69823a12014-12-09 14:06:5968 const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
69 ServiceWorkerStatusCode service_worker_status,
70 const scoped_refptr<ServiceWorkerRegistration>&
71 service_worker_registration) {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO);
73 if (service_worker_status == SERVICE_WORKER_OK) {
74 base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
75 base::Bind(&NotificationClickEventFinished,
76 dispatch_complete_callback,
77 service_worker_registration);
peter2ee1f3c2015-04-15 13:09:0978
79 // TODO(peter): Pass the persistent notification id as an int64_t rather
80 // than as a string. This depends on the Blink API being updated.
81 std::string persistent_notification_id_string =
82 base::Int64ToString(notification_database_data.notification_id);
83
84 service_worker_registration->active_version()->
85 DispatchNotificationClickEvent(
86 dispatch_event_callback,
87 persistent_notification_id_string,
88 notification_database_data.notification_data);
peterd69823a12014-12-09 14:06:5989 return;
90 }
91
92 PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
93 switch (service_worker_status) {
94 case SERVICE_WORKER_ERROR_NOT_FOUND:
95 status = PERSISTENT_NOTIFICATION_STATUS_NO_SERVICE_WORKER;
96 break;
97 case SERVICE_WORKER_ERROR_FAILED:
98 case SERVICE_WORKER_ERROR_ABORT:
99 case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
100 case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
101 case SERVICE_WORKER_ERROR_EXISTS:
102 case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
103 case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
104 case SERVICE_WORKER_ERROR_IPC_FAILED:
105 case SERVICE_WORKER_ERROR_NETWORK:
106 case SERVICE_WORKER_ERROR_SECURITY:
107 case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
xiang.longafc4f16f2015-02-04 07:04:57108 case SERVICE_WORKER_ERROR_STATE:
falken292e84a2015-03-05 16:54:25109 case SERVICE_WORKER_ERROR_TIMEOUT:
110 case SERVICE_WORKER_ERROR_MAX_VALUE:
peterd69823a12014-12-09 14:06:59111 status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
112 break;
113 case SERVICE_WORKER_OK:
114 NOTREACHED();
115 break;
116 }
117
118 BrowserThread::PostTask(BrowserThread::UI,
119 FROM_HERE,
120 base::Bind(dispatch_complete_callback, status));
121}
122
123// Finds the ServiceWorkerRegistration associated with the |origin| and
124// |service_worker_registration_id|. Must be called on the IO thread.
125void FindServiceWorkerRegistration(
126 const GURL& origin,
peterd69823a12014-12-09 14:06:59127 const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
peter2ee1f3c2015-04-15 13:09:09128 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
129 bool success,
130 const NotificationDatabaseData& notification_database_data) {
peterd69823a12014-12-09 14:06:59131 DCHECK_CURRENTLY_ON(BrowserThread::IO);
peter2ee1f3c2015-04-15 13:09:09132 if (!success) {
133 BrowserThread::PostTask(
134 BrowserThread::UI,
135 FROM_HERE,
136 base::Bind(dispatch_complete_callback,
137 PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR));
138 return;
139 }
140
peterd69823a12014-12-09 14:06:59141 service_worker_context->context()->storage()->FindRegistrationForId(
peter2ee1f3c2015-04-15 13:09:09142 notification_database_data.service_worker_registration_id,
peterd69823a12014-12-09 14:06:59143 origin,
144 base::Bind(&DispatchNotificationClickEventOnRegistration,
peter2ee1f3c2015-04-15 13:09:09145 notification_database_data,
peterd69823a12014-12-09 14:06:59146 dispatch_complete_callback));
147}
148
peter2ee1f3c2015-04-15 13:09:09149// Reads the data associated with the |persistent_notification_id| belonging to
150// |origin| from the notification context.
151void ReadNotificationDatabaseData(
152 int64_t persistent_notification_id,
153 const GURL& origin,
154 const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
155 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
156 scoped_refptr<PlatformNotificationContextImpl> notification_context) {
157 DCHECK_CURRENTLY_ON(BrowserThread::IO);
158 notification_context->ReadNotificationData(
159 persistent_notification_id,
160 origin,
161 base::Bind(&FindServiceWorkerRegistration,
162 origin, dispatch_complete_callback, service_worker_context));
163}
164
peterd69823a12014-12-09 14:06:59165} // namespace
166
167// static
168NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() {
169 return NotificationEventDispatcherImpl::GetInstance();
170}
171
172NotificationEventDispatcherImpl*
173NotificationEventDispatcherImpl::GetInstance() {
174 DCHECK_CURRENTLY_ON(BrowserThread::UI);
175 return Singleton<NotificationEventDispatcherImpl>::get();
176}
177
178NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() {}
179
180NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() {}
181
182void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
183 BrowserContext* browser_context,
peter2ee1f3c2015-04-15 13:09:09184 int64_t persistent_notification_id,
peterd69823a12014-12-09 14:06:59185 const GURL& origin,
peterd69823a12014-12-09 14:06:59186 const NotificationClickDispatchCompleteCallback&
187 dispatch_complete_callback) {
188 DCHECK_CURRENTLY_ON(BrowserThread::UI);
peter2ee1f3c2015-04-15 13:09:09189 DCHECK_GT(persistent_notification_id, 0);
190 DCHECK(origin.is_valid());
peterd69823a12014-12-09 14:06:59191
192 StoragePartition* partition =
193 BrowserContext::GetStoragePartitionForSite(browser_context, origin);
peter2ee1f3c2015-04-15 13:09:09194
peterd69823a12014-12-09 14:06:59195 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
196 static_cast<ServiceWorkerContextWrapper*>(
197 partition->GetServiceWorkerContext());
peter2ee1f3c2015-04-15 13:09:09198 scoped_refptr<PlatformNotificationContextImpl> notification_context =
199 static_cast<PlatformNotificationContextImpl*>(
200 partition->GetPlatformNotificationContext());
201
peterd69823a12014-12-09 14:06:59202 BrowserThread::PostTask(
203 BrowserThread::IO,
204 FROM_HERE,
peter2ee1f3c2015-04-15 13:09:09205 base::Bind(&ReadNotificationDatabaseData,
206 persistent_notification_id,
peterd69823a12014-12-09 14:06:59207 origin,
peterd69823a12014-12-09 14:06:59208 dispatch_complete_callback,
peter2ee1f3c2015-04-15 13:09:09209 service_worker_context,
210 notification_context));
peterd69823a12014-12-09 14:06:59211}
212
213} // namespace content