OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/push_messaging/push_messaging_service_impl.h" | 5 #include "chrome/browser/push_messaging/push_messaging_service_impl.h" |
6 | 6 |
7 #include <bitset> | 7 #include <bitset> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/barrier_closure.h" | 10 #include "base/barrier_closure.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "chrome/common/chrome_switches.h" | 30 #include "chrome/common/chrome_switches.h" |
31 #include "chrome/common/pref_names.h" | 31 #include "chrome/common/pref_names.h" |
32 #include "chrome/grit/generated_resources.h" | 32 #include "chrome/grit/generated_resources.h" |
33 #include "components/content_settings/core/browser/host_content_settings_map.h" | 33 #include "components/content_settings/core/browser/host_content_settings_map.h" |
34 #include "components/content_settings/core/common/permission_request_id.h" | 34 #include "components/content_settings/core/common/permission_request_id.h" |
35 #include "components/gcm_driver/gcm_driver.h" | 35 #include "components/gcm_driver/gcm_driver.h" |
36 #include "components/pref_registry/pref_registry_syncable.h" | 36 #include "components/pref_registry/pref_registry_syncable.h" |
37 #include "components/rappor/rappor_utils.h" | 37 #include "components/rappor/rappor_utils.h" |
38 #include "content/public/browser/browser_context.h" | 38 #include "content/public/browser/browser_context.h" |
39 #include "content/public/browser/browser_thread.h" | 39 #include "content/public/browser/browser_thread.h" |
| 40 #include "content/public/browser/notification_database_data.h" |
| 41 #include "content/public/browser/platform_notification_context.h" |
40 #include "content/public/browser/render_frame_host.h" | 42 #include "content/public/browser/render_frame_host.h" |
41 #include "content/public/browser/service_worker_context.h" | 43 #include "content/public/browser/service_worker_context.h" |
42 #include "content/public/browser/storage_partition.h" | 44 #include "content/public/browser/storage_partition.h" |
43 #include "content/public/browser/web_contents.h" | 45 #include "content/public/browser/web_contents.h" |
44 #include "content/public/common/child_process_host.h" | 46 #include "content/public/common/child_process_host.h" |
45 #include "content/public/common/content_switches.h" | 47 #include "content/public/common/content_switches.h" |
46 #include "content/public/common/platform_notification_data.h" | 48 #include "content/public/common/platform_notification_data.h" |
47 #include "content/public/common/push_messaging_status.h" | 49 #include "content/public/common/push_messaging_status.h" |
48 #include "third_party/skia/include/core/SkBitmap.h" | 50 #include "third_party/skia/include/core/SkBitmap.h" |
49 #include "ui/base/l10n/l10n_util.h" | 51 #include "ui/base/l10n/l10n_util.h" |
50 | 52 |
51 #if defined(OS_ANDROID) | 53 #if defined(OS_ANDROID) |
52 #include "chrome/browser/ui/android/tab_model/tab_model.h" | 54 #include "chrome/browser/ui/android/tab_model/tab_model.h" |
53 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" | 55 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" |
54 #else | 56 #else |
55 #include "chrome/browser/ui/browser.h" | 57 #include "chrome/browser/ui/browser.h" |
56 #include "chrome/browser/ui/browser_iterator.h" | 58 #include "chrome/browser/ui/browser_iterator.h" |
57 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 59 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
58 #endif | 60 #endif |
59 | 61 |
| 62 using content::BrowserThread; |
| 63 |
60 namespace { | 64 namespace { |
61 const int kMaxRegistrations = 1000000; | 65 const int kMaxRegistrations = 1000000; |
62 | 66 |
63 void RecordDeliveryStatus(content::PushDeliveryStatus status) { | 67 void RecordDeliveryStatus(content::PushDeliveryStatus status) { |
64 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", | 68 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", |
65 status, | 69 status, |
66 content::PUSH_DELIVERY_STATUS_LAST + 1); | 70 content::PUSH_DELIVERY_STATUS_LAST + 1); |
67 } | 71 } |
68 | 72 |
69 void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { | 73 void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: | 275 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: |
272 Unregister(app_id_guid, message.sender_id, | 276 Unregister(app_id_guid, message.sender_id, |
273 base::Bind(&UnregisterCallbackToClosure, | 277 base::Bind(&UnregisterCallbackToClosure, |
274 message_handled_closure)); | 278 message_handled_closure)); |
275 break; | 279 break; |
276 } | 280 } |
277 RecordDeliveryStatus(status); | 281 RecordDeliveryStatus(status); |
278 } | 282 } |
279 | 283 |
280 void PushMessagingServiceImpl::RequireUserVisibleUX( | 284 void PushMessagingServiceImpl::RequireUserVisibleUX( |
281 const GURL& requesting_origin, int64 service_worker_registration_id, | 285 const GURL& requesting_origin, int64_t service_worker_registration_id, |
282 const base::Closure& message_handled_closure) { | 286 const base::Closure& message_handled_closure) { |
| 287 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
283 #if defined(ENABLE_NOTIFICATIONS) | 288 #if defined(ENABLE_NOTIFICATIONS) |
284 // TODO(johnme): Relax this heuristic slightly. | 289 // TODO(johnme): Relax this heuristic slightly. |
285 PlatformNotificationServiceImpl* notification_service = | 290 scoped_refptr<content::PlatformNotificationContext> notification_context = |
286 PlatformNotificationServiceImpl::GetInstance(); | 291 content::BrowserContext::GetStoragePartitionForSite( |
287 // Can't use g_browser_process->notification_ui_manager(), since the test uses | 292 profile_, requesting_origin)->GetPlatformNotificationContext(); |
288 // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. | 293 BrowserThread::PostTask( |
289 // TODO(peter): Remove the need to use both APIs here once Notification.get() | 294 BrowserThread::IO, FROM_HERE, |
290 // is supported. | 295 base::Bind( |
291 int notification_count = notification_service->GetNotificationUIManager()-> | 296 &content::PlatformNotificationContext |
292 GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); | 297 ::ReadAllNotificationDataForServiceWorkerRegistration, |
| 298 notification_context, |
| 299 requesting_origin, service_worker_registration_id, |
| 300 base::Bind( |
| 301 &PushMessagingServiceImpl::DidGetNotificationsFromDatabaseIOProxy, |
| 302 weak_factory_.GetWeakPtr(), |
| 303 requesting_origin, service_worker_registration_id, |
| 304 message_handled_closure))); |
| 305 #else |
| 306 message_handled_closure.Run(); |
| 307 #endif // defined(ENABLE_NOTIFICATIONS) |
| 308 } |
| 309 |
| 310 // static |
| 311 void PushMessagingServiceImpl::DidGetNotificationsFromDatabaseIOProxy( |
| 312 const base::WeakPtr<PushMessagingServiceImpl>& ui_weak_ptr, |
| 313 const GURL& requesting_origin, |
| 314 int64_t service_worker_registration_id, |
| 315 const base::Closure& message_handled_closure, |
| 316 bool success, |
| 317 const std::vector<content::NotificationDatabaseData>& data) { |
| 318 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 319 BrowserThread::PostTask( |
| 320 BrowserThread::UI, FROM_HERE, |
| 321 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsFromDatabase, |
| 322 ui_weak_ptr, |
| 323 requesting_origin, service_worker_registration_id, |
| 324 message_handled_closure, |
| 325 success, data)); |
| 326 } |
| 327 |
| 328 void PushMessagingServiceImpl::DidGetNotificationsFromDatabase( |
| 329 const GURL& requesting_origin, int64_t service_worker_registration_id, |
| 330 const base::Closure& message_handled_closure, |
| 331 bool success, const std::vector<content::NotificationDatabaseData>& data) { |
| 332 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
293 // TODO(johnme): Hiding an existing notification should also count as a useful | 333 // TODO(johnme): Hiding an existing notification should also count as a useful |
294 // user-visible action done in response to a push message - but make sure that | 334 // user-visible action done in response to a push message - but make sure that |
295 // sending two messages in rapid succession which show then hide a | 335 // sending two messages in rapid succession which show then hide a |
296 // notification doesn't count. | 336 // notification doesn't count. |
| 337 int notification_count = success ? data.size() : 0; |
297 bool notification_shown = notification_count > 0; | 338 bool notification_shown = notification_count > 0; |
298 | 339 |
299 bool notification_needed = true; | 340 bool notification_needed = true; |
300 // Sites with a currently visible tab don't need to show notifications. | 341 // Sites with a currently visible tab don't need to show notifications. |
301 #if defined(OS_ANDROID) | 342 #if defined(OS_ANDROID) |
302 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { | 343 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { |
303 Profile* profile = (*it)->GetProfile(); | 344 Profile* profile = (*it)->GetProfile(); |
304 content::WebContents* active_web_contents = | 345 content::WebContents* active_web_contents = |
305 (*it)->GetActiveWebContents(); | 346 (*it)->GetActiveWebContents(); |
306 #else | 347 #else |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 | 381 |
341 // Don't track push messages that didn't show a notification but were exempt | 382 // Don't track push messages that didn't show a notification but were exempt |
342 // from needing to do so. | 383 // from needing to do so. |
343 if (notification_shown || notification_needed) { | 384 if (notification_shown || notification_needed) { |
344 content::ServiceWorkerContext* service_worker_context = | 385 content::ServiceWorkerContext* service_worker_context = |
345 content::BrowserContext::GetStoragePartitionForSite( | 386 content::BrowserContext::GetStoragePartitionForSite( |
346 profile_, requesting_origin)->GetServiceWorkerContext(); | 387 profile_, requesting_origin)->GetServiceWorkerContext(); |
347 | 388 |
348 GetNotificationsShownByLastFewPushes( | 389 GetNotificationsShownByLastFewPushes( |
349 service_worker_context, service_worker_registration_id, | 390 service_worker_context, service_worker_registration_id, |
350 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, | 391 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShownAndNeeded, |
351 weak_factory_.GetWeakPtr(), | 392 weak_factory_.GetWeakPtr(), |
352 requesting_origin, service_worker_registration_id, | 393 requesting_origin, service_worker_registration_id, |
353 notification_shown, notification_needed, | 394 notification_shown, notification_needed, |
354 message_handled_closure)); | 395 message_handled_closure)); |
355 } else { | 396 } else { |
356 RecordUserVisibleStatus( | 397 RecordUserVisibleStatus( |
357 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); | 398 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); |
358 message_handled_closure.Run(); | 399 message_handled_closure.Run(); |
359 } | 400 } |
360 #else | |
361 message_handled_closure.Run(); | |
362 #endif // defined(ENABLE_NOTIFICATIONS) | |
363 } | 401 } |
364 | 402 |
365 static void IgnoreResult(bool unused) { | 403 static void IgnoreResult(bool unused) { |
366 } | 404 } |
367 | 405 |
368 void PushMessagingServiceImpl::DidGetNotificationsShown( | 406 void PushMessagingServiceImpl::DidGetNotificationsShownAndNeeded( |
369 const GURL& requesting_origin, int64 service_worker_registration_id, | 407 const GURL& requesting_origin, int64_t service_worker_registration_id, |
370 bool notification_shown, bool notification_needed, | 408 bool notification_shown, bool notification_needed, |
371 const base::Closure& message_handled_closure, | 409 const base::Closure& message_handled_closure, |
372 const std::string& data, bool success, bool not_found) { | 410 const std::string& data, bool success, bool not_found) { |
| 411 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
373 content::ServiceWorkerContext* service_worker_context = | 412 content::ServiceWorkerContext* service_worker_context = |
374 content::BrowserContext::GetStoragePartitionForSite( | 413 content::BrowserContext::GetStoragePartitionForSite( |
375 profile_, requesting_origin)->GetServiceWorkerContext(); | 414 profile_, requesting_origin)->GetServiceWorkerContext(); |
376 | 415 |
377 // We remember whether the last (up to) 10 pushes showed notifications. | 416 // We remember whether the last (up to) 10 pushes showed notifications. |
378 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; | 417 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; |
379 // data is a string like "0001000", where '0' means shown, and '1' means | 418 // data is a string like "0001000", where '0' means shown, and '1' means |
380 // needed but not shown. We manipulate it in bitset form. | 419 // needed but not shown. We manipulate it in bitset form. |
381 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); | 420 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); |
382 | 421 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 // TODO(johnme): The generic notification should probably automatically | 461 // TODO(johnme): The generic notification should probably automatically |
423 // close itself when the next push message arrives? | 462 // close itself when the next push message arrives? |
424 content::PlatformNotificationData notification_data; | 463 content::PlatformNotificationData notification_data; |
425 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 | 464 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 |
426 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); | 465 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); |
427 notification_data.direction = | 466 notification_data.direction = |
428 content::PlatformNotificationData::NotificationDirectionLeftToRight; | 467 content::PlatformNotificationData::NotificationDirectionLeftToRight; |
429 notification_data.body = | 468 notification_data.body = |
430 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); | 469 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); |
431 notification_data.tag = kPushMessagingForcedNotificationTag; | 470 notification_data.tag = kPushMessagingForcedNotificationTag; |
432 notification_data.icon = GURL(); // TODO(johnme): Better icon? | 471 notification_data.icon = GURL(); |
433 notification_data.silent = true; | 472 notification_data.silent = true; |
434 PlatformNotificationServiceImpl* notification_service = | 473 |
435 PlatformNotificationServiceImpl::GetInstance(); | 474 content::NotificationDatabaseData database_data; |
436 notification_service->DisplayPersistentNotification( | 475 database_data.origin = requesting_origin; |
| 476 database_data.service_worker_registration_id = |
| 477 service_worker_registration_id; |
| 478 database_data.notification_data = notification_data; |
| 479 |
| 480 scoped_refptr<content::PlatformNotificationContext> notification_context = |
| 481 content::BrowserContext::GetStoragePartitionForSite( |
| 482 profile_, requesting_origin)->GetPlatformNotificationContext(); |
| 483 BrowserThread::PostTask( |
| 484 BrowserThread::IO, FROM_HERE, |
| 485 base::Bind( |
| 486 &content::PlatformNotificationContext::WriteNotificationData, |
| 487 notification_context, |
| 488 requesting_origin, database_data, |
| 489 base::Bind(&PushMessagingServiceImpl::DidWriteNotificationDataIOProxy, |
| 490 weak_factory_.GetWeakPtr(), |
| 491 requesting_origin, notification_data, |
| 492 message_handled_closure))); |
| 493 } |
| 494 |
| 495 // static |
| 496 void PushMessagingServiceImpl::DidWriteNotificationDataIOProxy( |
| 497 const base::WeakPtr<PushMessagingServiceImpl>& ui_weak_ptr, |
| 498 const GURL& requesting_origin, |
| 499 const content::PlatformNotificationData& notification_data, |
| 500 const base::Closure& message_handled_closure, |
| 501 bool success, |
| 502 int64_t persistent_notification_id) { |
| 503 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 504 BrowserThread::PostTask( |
| 505 BrowserThread::UI, FROM_HERE, |
| 506 base::Bind(&PushMessagingServiceImpl::DidWriteNotificationData, |
| 507 ui_weak_ptr, |
| 508 requesting_origin, notification_data, message_handled_closure, |
| 509 success, persistent_notification_id)); |
| 510 } |
| 511 |
| 512 void PushMessagingServiceImpl::DidWriteNotificationData( |
| 513 const GURL& requesting_origin, |
| 514 const content::PlatformNotificationData& notification_data, |
| 515 const base::Closure& message_handled_closure, |
| 516 bool success, |
| 517 int64_t persistent_notification_id) { |
| 518 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 519 if (!success) { |
| 520 DLOG(ERROR) << "Writing forced notification to database should not fail"; |
| 521 message_handled_closure.Run(); |
| 522 return; |
| 523 } |
| 524 PlatformNotificationServiceImpl::GetInstance()->DisplayPersistentNotification( |
437 profile_, | 525 profile_, |
438 service_worker_registration_id, | 526 persistent_notification_id, |
439 requesting_origin, | 527 requesting_origin, |
440 SkBitmap() /* icon */, | 528 SkBitmap() /* icon */, |
441 notification_data); | 529 notification_data); |
442 message_handled_closure.Run(); | 530 message_handled_closure.Run(); |
443 } | 531 } |
444 | 532 |
445 void PushMessagingServiceImpl::SetMessageCallbackForTesting( | 533 void PushMessagingServiceImpl::SetMessageCallbackForTesting( |
446 const base::Closure& callback) { | 534 const base::Closure& callback) { |
447 message_callback_for_testing_ = callback; | 535 message_callback_for_testing_ = callback; |
448 } | 536 } |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
817 CONTENT_SETTING_ALLOW; | 905 CONTENT_SETTING_ALLOW; |
818 } | 906 } |
819 | 907 |
820 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { | 908 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { |
821 gcm::GCMProfileService* gcm_profile_service = | 909 gcm::GCMProfileService* gcm_profile_service = |
822 gcm::GCMProfileServiceFactory::GetForProfile(profile_); | 910 gcm::GCMProfileServiceFactory::GetForProfile(profile_); |
823 CHECK(gcm_profile_service); | 911 CHECK(gcm_profile_service); |
824 CHECK(gcm_profile_service->driver()); | 912 CHECK(gcm_profile_service->driver()); |
825 return gcm_profile_service->driver(); | 913 return gcm_profile_service->driver(); |
826 } | 914 } |
OLD | NEW |