| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 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/blink_notification_service_impl.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "content/browser/notifications/notification_id_generator.h" |
| 11 #include "content/browser/notifications/page_notification_delegate.h" |
| 12 #include "content/browser/notifications/platform_notification_context_impl.h" |
| 13 #include "content/browser/notifications/type_converters.h" |
| 14 #include "content/public/browser/browser_thread.h" |
| 15 #include "content/public/browser/content_browser_client.h" |
| 16 #include "content/public/browser/notification_database_data.h" |
| 17 #include "content/public/browser/platform_notification_service.h" |
| 18 #include "content/public/common/content_client.h" |
| 19 #include "content/public/common/notification_resources.h" |
| 20 #include "content/public/common/platform_notification_data.h" |
| 21 #include "skia/public/type_converters.h" |
| 22 #include "third_party/WebKit/public/platform/modules/permissions/permission_stat
us.mojom.h" |
| 23 #include "url/gurl.h" |
| 24 |
| 25 namespace content { |
| 26 |
| 27 namespace { |
| 28 |
| 29 // Returns the implementation of the PlatformNotificationService. May be NULL. |
| 30 PlatformNotificationService* service() { |
| 31 return GetContentClient()->browser()->GetPlatformNotificationService(); |
| 32 } |
| 33 |
| 34 // Displays a non-persistent notification with the given information on the UI |
| 35 // thread. The close closure will be written to |*close_closure|. |
| 36 void DisplayNonPersistentNotificationOnUI( |
| 37 BrowserContext* browser_context, |
| 38 const GURL& origin, |
| 39 blink::mojom::NotificationPtr notification, |
| 40 blink::mojom::NotificationResourcesPtr notification_resources, |
| 41 blink::mojom::NotificationClientPtrInfo notification_client_info, |
| 42 base::Closure* close_closure) { |
| 43 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 44 blink::mojom::NotificationClientPtr notification_client = |
| 45 mojo::MakeProxy(std::move(notification_client_info)); |
| 46 |
| 47 std::unique_ptr<PageNotificationDelegate> delegate( |
| 48 new PageNotificationDelegate(std::move(notification_client))); |
| 49 |
| 50 // TODO(peter): Use the |notification_id| when showing a notification. |
| 51 service()->DisplayNotification( |
| 52 browser_context, origin, notification.To<PlatformNotificationData>(), |
| 53 notification_resources.To<NotificationResources>(), std::move(delegate), |
| 54 close_closure); |
| 55 |
| 56 DCHECK(!close_closure->is_null()); |
| 57 } |
| 58 |
| 59 } // namespace |
| 60 |
| 61 BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( |
| 62 PlatformNotificationContextImpl* notification_context, |
| 63 BrowserContext* browser_context, |
| 64 ResourceContext* resource_context, |
| 65 int render_process_id, |
| 66 mojo::InterfaceRequest<blink::mojom::NotificationService> request) |
| 67 : notification_context_(notification_context), |
| 68 browser_context_(browser_context), |
| 69 resource_context_(resource_context), |
| 70 render_process_id_(render_process_id), |
| 71 binding_(this, std::move(request)), |
| 72 weak_ptr_factory_(this) { |
| 73 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 74 DCHECK(notification_context_); |
| 75 DCHECK(browser_context_); |
| 76 |
| 77 notification_id_generator_.reset( |
| 78 new NotificationIdGenerator(browser_context_, render_process_id_)); |
| 79 |
| 80 binding_.set_connection_error_handler( |
| 81 base::Bind(&BlinkNotificationServiceImpl::OnConnectionError, |
| 82 base::Unretained(this) /* the channel is owned by this */)); |
| 83 } |
| 84 |
| 85 BlinkNotificationServiceImpl::~BlinkNotificationServiceImpl() { |
| 86 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 87 } |
| 88 |
| 89 void BlinkNotificationServiceImpl::GetPermissionStatus( |
| 90 const mojo::String& origin, |
| 91 const GetPermissionStatusCallback& callback) { |
| 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 93 |
| 94 if (!service()) { |
| 95 callback.Run(blink::mojom::PermissionStatus::DENIED); |
| 96 return; |
| 97 } |
| 98 |
| 99 blink::mojom::PermissionStatus permission_status = |
| 100 service()->CheckPermissionOnIOThread( |
| 101 resource_context_, GURL(origin.get()), render_process_id_); |
| 102 |
| 103 callback.Run(permission_status); |
| 104 } |
| 105 |
| 106 void BlinkNotificationServiceImpl::Display( |
| 107 const mojo::String& origin, |
| 108 blink::mojom::NotificationPtr notification, |
| 109 blink::mojom::NotificationResourcesPtr notification_resources, |
| 110 blink::mojom::NotificationClientPtr notification_client, |
| 111 const DisplayCallback& callback) { |
| 112 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 113 DCHECK(service()); // TODO: This should be BadMessage? |
| 114 |
| 115 // TODO(peter): Verify the notification's data and that permission has been |
| 116 // granted for the given |origin|. |
| 117 |
| 118 GURL origin_url(origin.get()); |
| 119 |
| 120 std::string notification_id = |
| 121 notification_id_generator_->GenerateForNonPersistentNotification( |
| 122 origin_url, notification->tag, ++non_persistent_notification_id_); |
| 123 |
| 124 LOG(ERROR) << "Notification Id: " << notification_id; |
| 125 |
| 126 std::unique_ptr<base::Closure> close_closure(new base::Closure()); |
| 127 |
| 128 BrowserThread::PostTaskAndReply( |
| 129 BrowserThread::UI, FROM_HERE, |
| 130 base::Bind(&DisplayNonPersistentNotificationOnUI, browser_context_, |
| 131 origin_url, base::Passed(¬ification), |
| 132 base::Passed(¬ification_resources), |
| 133 base::Passed(notification_client.PassInterface()), |
| 134 base::Unretained(close_closure.get())), |
| 135 base::Bind(&BlinkNotificationServiceImpl::DidDisplay, |
| 136 weak_ptr_factory_.GetWeakPtr(), notification_id, |
| 137 base::Passed(std::move(close_closure)), callback)); |
| 138 } |
| 139 |
| 140 void BlinkNotificationServiceImpl::DidDisplay( |
| 141 const std::string& notification_id, |
| 142 std::unique_ptr<base::Closure> close_closure, |
| 143 const DisplayCallback& callback) { |
| 144 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 145 |
| 146 close_closures_[notification_id] = *close_closure; |
| 147 |
| 148 callback.Run(blink::mojom::NotificationDisplayResult::SUCCESS, |
| 149 notification_id); |
| 150 } |
| 151 |
| 152 void BlinkNotificationServiceImpl::DisplayPersistent( |
| 153 const mojo::String& origin, |
| 154 int64_t service_worker_registration_id, |
| 155 blink::mojom::NotificationPtr notification, |
| 156 blink::mojom::NotificationResourcesPtr notification_resources, |
| 157 const DisplayPersistentCallback& callback) { |
| 158 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 159 DCHECK(service()); // TODO: This should be BadMessage? |
| 160 |
| 161 // TODO(peter): Verify the notification's data and that permission has been |
| 162 // granted for the given |origin|. |
| 163 |
| 164 GURL origin_url(origin.get()); |
| 165 |
| 166 NotificationDatabaseData database_data; |
| 167 database_data.origin = origin_url; |
| 168 database_data.service_worker_registration_id = service_worker_registration_id; |
| 169 database_data.notification_data = notification.To<PlatformNotificationData>(); |
| 170 |
| 171 notification_context_->WriteNotificationData( |
| 172 origin_url, database_data, |
| 173 base::Bind(&BlinkNotificationServiceImpl::DidStorePersistent, |
| 174 weak_ptr_factory_.GetWeakPtr(), origin_url, |
| 175 base::Passed(¬ification), |
| 176 base::Passed(¬ification_resources), callback)); |
| 177 } |
| 178 |
| 179 void BlinkNotificationServiceImpl::DidStorePersistent( |
| 180 const GURL& origin, |
| 181 blink::mojom::NotificationPtr notification, |
| 182 blink::mojom::NotificationResourcesPtr notification_resources, |
| 183 const DisplayPersistentCallback& callback, |
| 184 bool success, |
| 185 int64_t persistent_notification_id) { |
| 186 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 187 |
| 188 if (!success) { |
| 189 callback.Run(blink::mojom::NotificationDisplayResult::FAILED_STORAGE_ERROR); |
| 190 return; |
| 191 } |
| 192 |
| 193 // TODO(peter): Send an Id generated by the NotificationIdGenerator to the |
| 194 // service rather than the integral database id. |
| 195 BrowserThread::PostTask( |
| 196 BrowserThread::UI, FROM_HERE, |
| 197 base::Bind(&PlatformNotificationService::DisplayPersistentNotification, |
| 198 base::Unretained(service()), browser_context_, |
| 199 persistent_notification_id, origin, |
| 200 notification.To<PlatformNotificationData>(), |
| 201 notification_resources.To<NotificationResources>())); |
| 202 |
| 203 callback.Run(blink::mojom::NotificationDisplayResult::SUCCESS); |
| 204 } |
| 205 |
| 206 void BlinkNotificationServiceImpl::GetNotifications( |
| 207 const mojo::String& origin, |
| 208 int64_t service_worker_registration_id, |
| 209 const mojo::String& tag, |
| 210 const GetNotificationsCallback& callback) { |
| 211 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 212 |
| 213 // TODO(peter): If no permission has been granted, invoke |callback| quickly |
| 214 // with an empty Mojo array and avoid hitting the database. |
| 215 |
| 216 GURL origin_url(origin.get()); |
| 217 |
| 218 notification_context_->ReadAllNotificationDataForServiceWorkerRegistration( |
| 219 origin_url, service_worker_registration_id, |
| 220 base::Bind(&BlinkNotificationServiceImpl::DidGetNotifications, |
| 221 weak_ptr_factory_.GetWeakPtr(), tag.get(), callback)); |
| 222 } |
| 223 |
| 224 void BlinkNotificationServiceImpl::DidGetNotifications( |
| 225 const std::string& tag, |
| 226 const GetNotificationsCallback& callback, |
| 227 bool success, |
| 228 const std::vector<NotificationDatabaseData>& notifications) { |
| 229 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 230 |
| 231 if (!success) { |
| 232 callback.Run(mojo::Array<blink::mojom::NotificationPtr>()); |
| 233 return; |
| 234 } |
| 235 |
| 236 mojo::Array<blink::mojom::NotificationPtr> mojo_notifications; |
| 237 |
| 238 for (const auto& notification : notifications) { |
| 239 if (!tag.empty() && notification.notification_data.tag != tag) |
| 240 continue; |
| 241 |
| 242 blink::mojom::NotificationPtr mojo_notification = |
| 243 blink::mojom::Notification::From(notification.notification_data); |
| 244 |
| 245 // TODO(peter): Use the NotificationIdGenerator when the database has been |
| 246 // taught to work with these identifiers rather than the current numbers. |
| 247 mojo_notification->id = base::Int64ToString(notification.notification_id); |
| 248 |
| 249 mojo_notifications.push_back(std::move(mojo_notification)); |
| 250 } |
| 251 |
| 252 callback.Run(std::move(mojo_notifications)); |
| 253 } |
| 254 |
| 255 void BlinkNotificationServiceImpl::Close(const mojo::String& origin, |
| 256 const mojo::String& notification_id, |
| 257 const CloseCallback& callback) { |
| 258 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 259 DCHECK(service()); // TODO: This should be BadMessage? |
| 260 |
| 261 // TODO(peter): Do the necessary permission checks. |
| 262 |
| 263 const std::string id = notification_id.get(); |
| 264 |
| 265 int64_t persistent_notification_id = 0; |
| 266 |
| 267 // TODO(peter): Use NotificationIdGenerator::IsPersistentNotification when |
| 268 // the notification system is in charge of generating its own ids. |
| 269 if (base::StringToInt64(notification_id.get(), &persistent_notification_id)) { |
| 270 // There's no point in waiting until the database has been updated before |
| 271 // closing the notification presented to the user. |
| 272 BrowserThread::PostTask( |
| 273 BrowserThread::UI, FROM_HERE, |
| 274 base::Bind(&PlatformNotificationService::ClosePersistentNotification, |
| 275 base::Unretained(service()), // The service is a singleton. |
| 276 browser_context_, persistent_notification_id)); |
| 277 |
| 278 notification_context_->DeleteNotificationData( |
| 279 persistent_notification_id, GURL(origin.get()), |
| 280 base::Bind(&BlinkNotificationServiceImpl::DidClosePersistent, |
| 281 weak_ptr_factory_.GetWeakPtr(), callback)); |
| 282 |
| 283 return; |
| 284 } else if (NotificationIdGenerator::IsNonPersistentNotification(id)) { |
| 285 const auto& notification_iter = close_closures_.find(id); |
| 286 if (notification_iter != close_closures_.end()) { |
| 287 BrowserThread::PostTask( |
| 288 BrowserThread::UI, FROM_HERE, notification_iter->second); |
| 289 |
| 290 close_closures_.erase(notification_iter); |
| 291 |
| 292 callback.Run(blink::mojom::NotificationCloseResult::CLOSED); |
| 293 return; |
| 294 } |
| 295 } else { |
| 296 // TODO: This should be BadMessage? |
| 297 NOTREACHED() << "Unrecognized notification id"; |
| 298 } |
| 299 |
| 300 callback.Run(blink::mojom::NotificationCloseResult::NOT_FOUND); |
| 301 } |
| 302 |
| 303 void BlinkNotificationServiceImpl::DidClosePersistent( |
| 304 const CloseCallback& callback, |
| 305 bool success) { |
| 306 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 307 |
| 308 auto result = success ? blink::mojom::NotificationCloseResult::CLOSED |
| 309 : blink::mojom::NotificationCloseResult::NOT_FOUND; |
| 310 |
| 311 callback.Run(result); |
| 312 } |
| 313 |
| 314 void BlinkNotificationServiceImpl::OnConnectionError() { |
| 315 notification_context_->RemoveService(this); |
| 316 // |this| has now been deleted. |
| 317 } |
| 318 |
| 319 } // namespace content |
| OLD | NEW |