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" |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/bind_to_current_loop.h" |
13 #include "base/command_line.h" | 14 #include "base/command_line.h" |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
16 #include "base/prefs/pref_service.h" | 17 #include "base/prefs/pref_service.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
20 #include "chrome/browser/notifications/notification_ui_manager.h" | 21 #include "chrome/browser/notifications/notification_ui_manager.h" |
21 #include "chrome/browser/notifications/platform_notification_service_impl.h" | 22 #include "chrome/browser/notifications/platform_notification_service_impl.h" |
22 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
23 #include "chrome/browser/push_messaging/push_messaging_application_id.h" | 24 #include "chrome/browser/push_messaging/push_messaging_application_id.h" |
24 #include "chrome/browser/push_messaging/push_messaging_constants.h" | 25 #include "chrome/browser/push_messaging/push_messaging_constants.h" |
25 #include "chrome/browser/push_messaging/push_messaging_permission_context.h" | 26 #include "chrome/browser/push_messaging/push_messaging_permission_context.h" |
26 #include "chrome/browser/push_messaging/push_messaging_permission_context_factor
y.h" | 27 #include "chrome/browser/push_messaging/push_messaging_permission_context_factor
y.h" |
27 #include "chrome/browser/push_messaging/push_messaging_service_factory.h" | 28 #include "chrome/browser/push_messaging/push_messaging_service_factory.h" |
28 #include "chrome/browser/services/gcm/gcm_profile_service.h" | 29 #include "chrome/browser/services/gcm/gcm_profile_service.h" |
29 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" | 30 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" |
30 #include "chrome/common/chrome_switches.h" | 31 #include "chrome/common/chrome_switches.h" |
31 #include "chrome/common/pref_names.h" | 32 #include "chrome/common/pref_names.h" |
32 #include "chrome/grit/generated_resources.h" | 33 #include "chrome/grit/generated_resources.h" |
33 #include "components/content_settings/core/browser/host_content_settings_map.h" | 34 #include "components/content_settings/core/browser/host_content_settings_map.h" |
34 #include "components/content_settings/core/common/permission_request_id.h" | 35 #include "components/content_settings/core/common/permission_request_id.h" |
35 #include "components/gcm_driver/gcm_driver.h" | 36 #include "components/gcm_driver/gcm_driver.h" |
36 #include "components/pref_registry/pref_registry_syncable.h" | 37 #include "components/pref_registry/pref_registry_syncable.h" |
37 #include "components/rappor/rappor_utils.h" | 38 #include "components/rappor/rappor_utils.h" |
38 #include "content/public/browser/browser_context.h" | 39 #include "content/public/browser/browser_context.h" |
39 #include "content/public/browser/browser_thread.h" | 40 #include "content/public/browser/browser_thread.h" |
| 41 #include "content/public/browser/notification_database_data.h" |
| 42 #include "content/public/browser/platform_notification_context.h" |
40 #include "content/public/browser/render_frame_host.h" | 43 #include "content/public/browser/render_frame_host.h" |
41 #include "content/public/browser/service_worker_context.h" | 44 #include "content/public/browser/service_worker_context.h" |
42 #include "content/public/browser/storage_partition.h" | 45 #include "content/public/browser/storage_partition.h" |
43 #include "content/public/browser/web_contents.h" | 46 #include "content/public/browser/web_contents.h" |
44 #include "content/public/common/child_process_host.h" | 47 #include "content/public/common/child_process_host.h" |
45 #include "content/public/common/content_switches.h" | 48 #include "content/public/common/content_switches.h" |
46 #include "content/public/common/platform_notification_data.h" | 49 #include "content/public/common/platform_notification_data.h" |
47 #include "content/public/common/push_messaging_status.h" | 50 #include "content/public/common/push_messaging_status.h" |
48 #include "third_party/skia/include/core/SkBitmap.h" | 51 #include "third_party/skia/include/core/SkBitmap.h" |
49 #include "ui/base/l10n/l10n_util.h" | 52 #include "ui/base/l10n/l10n_util.h" |
50 | 53 |
51 #if defined(OS_ANDROID) | 54 #if defined(OS_ANDROID) |
52 #include "chrome/browser/ui/android/tab_model/tab_model.h" | 55 #include "chrome/browser/ui/android/tab_model/tab_model.h" |
53 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" | 56 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" |
54 #else | 57 #else |
55 #include "chrome/browser/ui/browser.h" | 58 #include "chrome/browser/ui/browser.h" |
56 #include "chrome/browser/ui/browser_iterator.h" | 59 #include "chrome/browser/ui/browser_iterator.h" |
57 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 60 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
58 #endif | 61 #endif |
59 | 62 |
| 63 using content::BrowserThread; |
| 64 |
60 namespace { | 65 namespace { |
61 const int kMaxRegistrations = 1000000; | 66 const int kMaxRegistrations = 1000000; |
62 | 67 |
63 void RecordDeliveryStatus(content::PushDeliveryStatus status) { | 68 void RecordDeliveryStatus(content::PushDeliveryStatus status) { |
64 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", | 69 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", |
65 status, | 70 status, |
66 content::PUSH_DELIVERY_STATUS_LAST + 1); | 71 content::PUSH_DELIVERY_STATUS_LAST + 1); |
67 } | 72 } |
68 | 73 |
69 void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { | 74 void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 base::Bind(&UnregisterCallbackToClosure, | 281 base::Bind(&UnregisterCallbackToClosure, |
277 message_handled_closure)); | 282 message_handled_closure)); |
278 break; | 283 break; |
279 } | 284 } |
280 RecordDeliveryStatus(status); | 285 RecordDeliveryStatus(status); |
281 } | 286 } |
282 | 287 |
283 void PushMessagingServiceImpl::RequireUserVisibleUX( | 288 void PushMessagingServiceImpl::RequireUserVisibleUX( |
284 const GURL& requesting_origin, int64 service_worker_registration_id, | 289 const GURL& requesting_origin, int64 service_worker_registration_id, |
285 const base::Closure& message_handled_closure) { | 290 const base::Closure& message_handled_closure) { |
| 291 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
286 #if defined(ENABLE_NOTIFICATIONS) | 292 #if defined(ENABLE_NOTIFICATIONS) |
287 // TODO(johnme): Relax this heuristic slightly. | 293 // TODO(johnme): Relax this heuristic slightly. |
288 PlatformNotificationServiceImpl* notification_service = | 294 scoped_refptr<content::PlatformNotificationContext> notification_context = |
289 PlatformNotificationServiceImpl::GetInstance(); | 295 content::BrowserContext::GetStoragePartitionForSite( |
290 // Can't use g_browser_process->notification_ui_manager(), since the test uses | 296 profile_, requesting_origin)->GetPlatformNotificationContext(); |
291 // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. | 297 BrowserThread::PostTask( |
292 // TODO(peter): Remove the need to use both APIs here once Notification.get() | 298 BrowserThread::IO, FROM_HERE, |
293 // is supported. | 299 base::Bind(&content::PlatformNotificationContext |
294 int notification_count = notification_service->GetNotificationUIManager()-> | 300 ::ReadAllNotificationDataForServiceWorkerRegistration, |
295 GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); | 301 notification_context, |
| 302 requesting_origin, service_worker_registration_id, |
| 303 base::BindToCurrentLoop(base::Bind( |
| 304 &PushMessagingServiceImpl::DidGetNotificationsShowing, |
| 305 weak_factory_.GetWeakPtr(), |
| 306 requesting_origin, service_worker_registration_id, |
| 307 message_handled_closure)))); |
| 308 #else |
| 309 message_handled_closure.Run(); |
| 310 #endif // defined(ENABLE_NOTIFICATIONS) |
| 311 } |
| 312 |
| 313 void PushMessagingServiceImpl::DidGetNotificationsShowing( |
| 314 const GURL& requesting_origin, int64 service_worker_registration_id, |
| 315 const base::Closure& message_handled_closure, |
| 316 bool success, const std::vector<content::NotificationDatabaseData>& data) { |
| 317 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
296 // TODO(johnme): Hiding an existing notification should also count as a useful | 318 // TODO(johnme): Hiding an existing notification should also count as a useful |
297 // user-visible action done in response to a push message - but make sure that | 319 // user-visible action done in response to a push message - but make sure that |
298 // sending two messages in rapid succession which show then hide a | 320 // sending two messages in rapid succession which show then hide a |
299 // notification doesn't count. | 321 // notification doesn't count. |
| 322 int notification_count = success ? data.size() : 0; |
300 bool notification_shown = notification_count > 0; | 323 bool notification_shown = notification_count > 0; |
301 | 324 |
302 bool notification_needed = true; | 325 bool notification_needed = true; |
303 // Sites with a currently visible tab don't need to show notifications. | 326 // Sites with a currently visible tab don't need to show notifications. |
304 #if defined(OS_ANDROID) | 327 #if defined(OS_ANDROID) |
305 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { | 328 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { |
306 Profile* profile = (*it)->GetProfile(); | 329 Profile* profile = (*it)->GetProfile(); |
307 content::WebContents* active_web_contents = | 330 content::WebContents* active_web_contents = |
308 (*it)->GetActiveWebContents(); | 331 (*it)->GetActiveWebContents(); |
309 #else | 332 #else |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, | 376 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, |
354 weak_factory_.GetWeakPtr(), | 377 weak_factory_.GetWeakPtr(), |
355 requesting_origin, service_worker_registration_id, | 378 requesting_origin, service_worker_registration_id, |
356 notification_shown, notification_needed, | 379 notification_shown, notification_needed, |
357 message_handled_closure)); | 380 message_handled_closure)); |
358 } else { | 381 } else { |
359 RecordUserVisibleStatus( | 382 RecordUserVisibleStatus( |
360 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); | 383 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); |
361 message_handled_closure.Run(); | 384 message_handled_closure.Run(); |
362 } | 385 } |
363 #else | |
364 message_handled_closure.Run(); | |
365 #endif // defined(ENABLE_NOTIFICATIONS) | |
366 } | 386 } |
367 | 387 |
368 static void IgnoreResult(bool unused) { | 388 static void IgnoreResult(bool unused) { |
369 } | 389 } |
370 | 390 |
371 void PushMessagingServiceImpl::DidGetNotificationsShown( | 391 void PushMessagingServiceImpl::DidGetNotificationsShown( |
372 const GURL& requesting_origin, int64 service_worker_registration_id, | 392 const GURL& requesting_origin, int64 service_worker_registration_id, |
373 bool notification_shown, bool notification_needed, | 393 bool notification_shown, bool notification_needed, |
374 const base::Closure& message_handled_closure, | 394 const base::Closure& message_handled_closure, |
375 const std::string& data, bool success, bool not_found) { | 395 const std::string& data, bool success, bool not_found) { |
| 396 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
376 content::ServiceWorkerContext* service_worker_context = | 397 content::ServiceWorkerContext* service_worker_context = |
377 content::BrowserContext::GetStoragePartitionForSite( | 398 content::BrowserContext::GetStoragePartitionForSite( |
378 profile_, requesting_origin)->GetServiceWorkerContext(); | 399 profile_, requesting_origin)->GetServiceWorkerContext(); |
379 | 400 |
380 // We remember whether the last (up to) 10 pushes showed notifications. | 401 // We remember whether the last (up to) 10 pushes showed notifications. |
381 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; | 402 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; |
382 // data is a string like "0001000", where '0' means shown, and '1' means | 403 // data is a string like "0001000", where '0' means shown, and '1' means |
383 // needed but not shown. We manipulate it in bitset form. | 404 // needed but not shown. We manipulate it in bitset form. |
384 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); | 405 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); |
385 | 406 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 // TODO(johnme): The generic notification should probably automatically | 446 // TODO(johnme): The generic notification should probably automatically |
426 // close itself when the next push message arrives? | 447 // close itself when the next push message arrives? |
427 content::PlatformNotificationData notification_data; | 448 content::PlatformNotificationData notification_data; |
428 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 | 449 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 |
429 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); | 450 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); |
430 notification_data.direction = | 451 notification_data.direction = |
431 content::PlatformNotificationData::NotificationDirectionLeftToRight; | 452 content::PlatformNotificationData::NotificationDirectionLeftToRight; |
432 notification_data.body = | 453 notification_data.body = |
433 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); | 454 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); |
434 notification_data.tag = kPushMessagingForcedNotificationTag; | 455 notification_data.tag = kPushMessagingForcedNotificationTag; |
435 notification_data.icon = GURL(); // TODO(johnme): Better icon? | 456 notification_data.icon = GURL(); |
436 notification_data.silent = true; | 457 notification_data.silent = true; |
437 PlatformNotificationServiceImpl* notification_service = | 458 |
438 PlatformNotificationServiceImpl::GetInstance(); | 459 content::NotificationDatabaseData database_data; |
439 notification_service->DisplayPersistentNotification( | 460 database_data.origin = requesting_origin; |
| 461 database_data.service_worker_registration_id = |
| 462 service_worker_registration_id; |
| 463 database_data.notification_data = notification_data; |
| 464 |
| 465 scoped_refptr<content::PlatformNotificationContext> notification_context = |
| 466 content::BrowserContext::GetStoragePartitionForSite( |
| 467 profile_, requesting_origin)->GetPlatformNotificationContext(); |
| 468 BrowserThread::PostTask( |
| 469 BrowserThread::IO, FROM_HERE, |
| 470 base::Bind(&content::PlatformNotificationContext::WriteNotificationData, |
| 471 notification_context, |
| 472 requesting_origin, database_data, |
| 473 base::BindToCurrentLoop(base::Bind( |
| 474 &PushMessagingServiceImpl::DidWriteNotificationData, |
| 475 weak_factory_.GetWeakPtr(), |
| 476 requesting_origin, notification_data, |
| 477 message_handled_closure)))); |
| 478 } |
| 479 |
| 480 void PushMessagingServiceImpl::DidWriteNotificationData( |
| 481 const GURL& requesting_origin, |
| 482 const content::PlatformNotificationData& notification_data, |
| 483 const base::Closure& message_handled_closure, |
| 484 bool success, |
| 485 int64_t persistent_notification_id) { |
| 486 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 487 if (!success) { |
| 488 DLOG(ERROR) << "Writing forced notification to database should rarely fail"; |
| 489 message_handled_closure.Run(); |
| 490 return; |
| 491 } |
| 492 PlatformNotificationServiceImpl::GetInstance()->DisplayPersistentNotification( |
440 profile_, | 493 profile_, |
441 service_worker_registration_id, | 494 persistent_notification_id, |
442 requesting_origin, | 495 requesting_origin, |
443 SkBitmap() /* icon */, | 496 SkBitmap() /* icon */, |
444 notification_data); | 497 notification_data); |
445 message_handled_closure.Run(); | 498 message_handled_closure.Run(); |
446 } | 499 } |
447 | 500 |
448 void PushMessagingServiceImpl::SetMessageCallbackForTesting( | 501 void PushMessagingServiceImpl::SetMessageCallbackForTesting( |
449 const base::Closure& callback) { | 502 const base::Closure& callback) { |
450 message_callback_for_testing_ = callback; | 503 message_callback_for_testing_ = callback; |
451 } | 504 } |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 CONTENT_SETTING_ALLOW; | 873 CONTENT_SETTING_ALLOW; |
821 } | 874 } |
822 | 875 |
823 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { | 876 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { |
824 gcm::GCMProfileService* gcm_profile_service = | 877 gcm::GCMProfileService* gcm_profile_service = |
825 gcm::GCMProfileServiceFactory::GetForProfile(profile_); | 878 gcm::GCMProfileServiceFactory::GetForProfile(profile_); |
826 CHECK(gcm_profile_service); | 879 CHECK(gcm_profile_service); |
827 CHECK(gcm_profile_service->driver()); | 880 CHECK(gcm_profile_service->driver()); |
828 return gcm_profile_service->driver(); | 881 return gcm_profile_service->driver(); |
829 } | 882 } |
OLD | NEW |