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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 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::DidGetNotificationsShowingIOProxy, | |
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 void PushMessagingServiceImpl::DidGetNotificationsShowingIOProxy( | |
Peter Beverloo
2015/04/30 11:11:42
nit: // static
johnme
2015/04/30 13:30:12
Done.
| |
311 const base::WeakPtr<PushMessagingServiceImpl>& ui_weak_ptr, | |
312 const GURL& requesting_origin, | |
313 int64 service_worker_registration_id, | |
314 const base::Closure& message_handled_closure, | |
315 bool success, | |
316 const std::vector<content::NotificationDatabaseData>& data) { | |
317 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
318 BrowserThread::PostTask( | |
319 BrowserThread::UI, FROM_HERE, | |
320 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShowing, | |
321 ui_weak_ptr, | |
322 requesting_origin, service_worker_registration_id, | |
323 message_handled_closure, | |
324 success, data)); | |
325 } | |
326 | |
327 void PushMessagingServiceImpl::DidGetNotificationsShowing( | |
328 const GURL& requesting_origin, int64 service_worker_registration_id, | |
329 const base::Closure& message_handled_closure, | |
330 bool success, const std::vector<content::NotificationDatabaseData>& data) { | |
331 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
293 // TODO(johnme): Hiding an existing notification should also count as a useful | 332 // 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 | 333 // 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 | 334 // sending two messages in rapid succession which show then hide a |
296 // notification doesn't count. | 335 // notification doesn't count. |
336 int notification_count = success ? data.size() : 0; | |
297 bool notification_shown = notification_count > 0; | 337 bool notification_shown = notification_count > 0; |
298 | 338 |
299 bool notification_needed = true; | 339 bool notification_needed = true; |
300 // Sites with a currently visible tab don't need to show notifications. | 340 // Sites with a currently visible tab don't need to show notifications. |
301 #if defined(OS_ANDROID) | 341 #if defined(OS_ANDROID) |
302 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { | 342 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { |
303 Profile* profile = (*it)->GetProfile(); | 343 Profile* profile = (*it)->GetProfile(); |
304 content::WebContents* active_web_contents = | 344 content::WebContents* active_web_contents = |
305 (*it)->GetActiveWebContents(); | 345 (*it)->GetActiveWebContents(); |
306 #else | 346 #else |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
350 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, | 390 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, |
351 weak_factory_.GetWeakPtr(), | 391 weak_factory_.GetWeakPtr(), |
352 requesting_origin, service_worker_registration_id, | 392 requesting_origin, service_worker_registration_id, |
353 notification_shown, notification_needed, | 393 notification_shown, notification_needed, |
354 message_handled_closure)); | 394 message_handled_closure)); |
355 } else { | 395 } else { |
356 RecordUserVisibleStatus( | 396 RecordUserVisibleStatus( |
357 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); | 397 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); |
358 message_handled_closure.Run(); | 398 message_handled_closure.Run(); |
359 } | 399 } |
360 #else | |
361 message_handled_closure.Run(); | |
362 #endif // defined(ENABLE_NOTIFICATIONS) | |
363 } | 400 } |
364 | 401 |
365 static void IgnoreResult(bool unused) { | 402 static void IgnoreResult(bool unused) { |
366 } | 403 } |
367 | 404 |
368 void PushMessagingServiceImpl::DidGetNotificationsShown( | 405 void PushMessagingServiceImpl::DidGetNotificationsShown( |
369 const GURL& requesting_origin, int64 service_worker_registration_id, | 406 const GURL& requesting_origin, int64 service_worker_registration_id, |
370 bool notification_shown, bool notification_needed, | 407 bool notification_shown, bool notification_needed, |
371 const base::Closure& message_handled_closure, | 408 const base::Closure& message_handled_closure, |
372 const std::string& data, bool success, bool not_found) { | 409 const std::string& data, bool success, bool not_found) { |
410 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
373 content::ServiceWorkerContext* service_worker_context = | 411 content::ServiceWorkerContext* service_worker_context = |
374 content::BrowserContext::GetStoragePartitionForSite( | 412 content::BrowserContext::GetStoragePartitionForSite( |
375 profile_, requesting_origin)->GetServiceWorkerContext(); | 413 profile_, requesting_origin)->GetServiceWorkerContext(); |
376 | 414 |
377 // We remember whether the last (up to) 10 pushes showed notifications. | 415 // We remember whether the last (up to) 10 pushes showed notifications. |
378 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; | 416 const size_t MISSED_NOTIFICATIONS_LENGTH = 10; |
379 // data is a string like "0001000", where '0' means shown, and '1' means | 417 // data is a string like "0001000", where '0' means shown, and '1' means |
380 // needed but not shown. We manipulate it in bitset form. | 418 // needed but not shown. We manipulate it in bitset form. |
381 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); | 419 std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); |
382 | 420 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 // TODO(johnme): The generic notification should probably automatically | 460 // TODO(johnme): The generic notification should probably automatically |
423 // close itself when the next push message arrives? | 461 // close itself when the next push message arrives? |
424 content::PlatformNotificationData notification_data; | 462 content::PlatformNotificationData notification_data; |
425 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 | 463 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 |
426 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); | 464 notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); |
427 notification_data.direction = | 465 notification_data.direction = |
428 content::PlatformNotificationData::NotificationDirectionLeftToRight; | 466 content::PlatformNotificationData::NotificationDirectionLeftToRight; |
429 notification_data.body = | 467 notification_data.body = |
430 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); | 468 l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); |
431 notification_data.tag = kPushMessagingForcedNotificationTag; | 469 notification_data.tag = kPushMessagingForcedNotificationTag; |
432 notification_data.icon = GURL(); // TODO(johnme): Better icon? | 470 notification_data.icon = GURL(); |
433 notification_data.silent = true; | 471 notification_data.silent = true; |
434 PlatformNotificationServiceImpl* notification_service = | 472 |
435 PlatformNotificationServiceImpl::GetInstance(); | 473 content::NotificationDatabaseData database_data; |
436 notification_service->DisplayPersistentNotification( | 474 database_data.origin = requesting_origin; |
475 database_data.service_worker_registration_id = | |
476 service_worker_registration_id; | |
477 database_data.notification_data = notification_data; | |
478 | |
479 scoped_refptr<content::PlatformNotificationContext> notification_context = | |
480 content::BrowserContext::GetStoragePartitionForSite( | |
481 profile_, requesting_origin)->GetPlatformNotificationContext(); | |
482 BrowserThread::PostTask( | |
483 BrowserThread::IO, FROM_HERE, | |
484 base::Bind( | |
485 &content::PlatformNotificationContext::WriteNotificationData, | |
486 notification_context, | |
487 requesting_origin, database_data, | |
488 base::Bind(&PushMessagingServiceImpl::DidWriteNotificationDataIOProxy, | |
489 weak_factory_.GetWeakPtr(), | |
490 requesting_origin, notification_data, | |
491 message_handled_closure))); | |
492 } | |
493 | |
494 void PushMessagingServiceImpl::DidWriteNotificationDataIOProxy( | |
495 const base::WeakPtr<PushMessagingServiceImpl>& ui_weak_ptr, | |
496 const GURL& requesting_origin, | |
497 const content::PlatformNotificationData& notification_data, | |
498 const base::Closure& message_handled_closure, | |
499 bool success, | |
500 int64_t persistent_notification_id) { | |
501 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
502 BrowserThread::PostTask( | |
503 BrowserThread::UI, FROM_HERE, | |
504 base::Bind(&PushMessagingServiceImpl::DidWriteNotificationData, | |
505 ui_weak_ptr, | |
506 requesting_origin, notification_data, message_handled_closure, | |
507 success, persistent_notification_id)); | |
508 } | |
509 | |
510 void PushMessagingServiceImpl::DidWriteNotificationData( | |
511 const GURL& requesting_origin, | |
512 const content::PlatformNotificationData& notification_data, | |
513 const base::Closure& message_handled_closure, | |
514 bool success, | |
515 int64_t persistent_notification_id) { | |
516 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
517 if (!success) { | |
518 DLOG(ERROR) << "Writing forced notification to database should rarely fail"; | |
Peter Beverloo
2015/04/30 11:11:42
nit: s/rarely/not/.
johnme
2015/04/30 13:30:12
Done.
| |
519 message_handled_closure.Run(); | |
520 return; | |
521 } | |
522 PlatformNotificationServiceImpl::GetInstance()->DisplayPersistentNotification( | |
437 profile_, | 523 profile_, |
438 service_worker_registration_id, | 524 persistent_notification_id, |
439 requesting_origin, | 525 requesting_origin, |
440 SkBitmap() /* icon */, | 526 SkBitmap() /* icon */, |
441 notification_data); | 527 notification_data); |
442 message_handled_closure.Run(); | 528 message_handled_closure.Run(); |
443 } | 529 } |
444 | 530 |
445 void PushMessagingServiceImpl::SetMessageCallbackForTesting( | 531 void PushMessagingServiceImpl::SetMessageCallbackForTesting( |
446 const base::Closure& callback) { | 532 const base::Closure& callback) { |
447 message_callback_for_testing_ = callback; | 533 message_callback_for_testing_ = callback; |
448 } | 534 } |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
817 CONTENT_SETTING_ALLOW; | 903 CONTENT_SETTING_ALLOW; |
818 } | 904 } |
819 | 905 |
820 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { | 906 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const { |
821 gcm::GCMProfileService* gcm_profile_service = | 907 gcm::GCMProfileService* gcm_profile_service = |
822 gcm::GCMProfileServiceFactory::GetForProfile(profile_); | 908 gcm::GCMProfileServiceFactory::GetForProfile(profile_); |
823 CHECK(gcm_profile_service); | 909 CHECK(gcm_profile_service); |
824 CHECK(gcm_profile_service->driver()); | 910 CHECK(gcm_profile_service->driver()); |
825 return gcm_profile_service->driver(); | 911 return gcm_profile_service->driver(); |
826 } | 912 } |
OLD | NEW |