Index: chrome/browser/services/gcm/push_messaging_service_impl.cc |
diff --git a/chrome/browser/services/gcm/push_messaging_service_impl.cc b/chrome/browser/services/gcm/push_messaging_service_impl.cc |
deleted file mode 100644 |
index b0cc76d2dfc9e7047f48987da0260ccbc6276968..0000000000000000000000000000000000000000 |
--- a/chrome/browser/services/gcm/push_messaging_service_impl.cc |
+++ /dev/null |
@@ -1,791 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/services/gcm/push_messaging_service_impl.h" |
- |
-#include <bitset> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/prefs/pref_service.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/notifications/notification_ui_manager.h" |
-#include "chrome/browser/notifications/platform_notification_service_impl.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/services/gcm/gcm_profile_service.h" |
-#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" |
-#include "chrome/browser/services/gcm/push_messaging_application_id.h" |
-#include "chrome/browser/services/gcm/push_messaging_constants.h" |
-#include "chrome/browser/services/gcm/push_messaging_permission_context.h" |
-#include "chrome/browser/services/gcm/push_messaging_permission_context_factory.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "chrome/common/pref_names.h" |
-#include "chrome/grit/generated_resources.h" |
-#include "components/content_settings/core/browser/host_content_settings_map.h" |
-#include "components/content_settings/core/common/permission_request_id.h" |
-#include "components/gcm_driver/gcm_driver.h" |
-#include "components/pref_registry/pref_registry_syncable.h" |
-#include "content/public/browser/browser_context.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/render_frame_host.h" |
-#include "content/public/browser/service_worker_context.h" |
-#include "content/public/browser/storage_partition.h" |
-#include "content/public/browser/web_contents.h" |
-#include "content/public/common/child_process_host.h" |
-#include "content/public/common/content_switches.h" |
-#include "content/public/common/platform_notification_data.h" |
-#include "content/public/common/push_messaging_status.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
-#include "ui/base/l10n/l10n_util.h" |
- |
-#if defined(OS_ANDROID) |
-#include "chrome/browser/ui/android/tab_model/tab_model.h" |
-#include "chrome/browser/ui/android/tab_model/tab_model_list.h" |
-#else |
-#include "chrome/browser/ui/browser.h" |
-#include "chrome/browser/ui/browser_iterator.h" |
-#include "chrome/browser/ui/tabs/tab_strip_model.h" |
-#endif |
- |
-namespace gcm { |
- |
-namespace { |
-const int kMaxRegistrations = 1000000; |
- |
-void RecordDeliveryStatus(content::PushDeliveryStatus status) { |
- UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", |
- status, |
- content::PUSH_DELIVERY_STATUS_LAST + 1); |
-} |
- |
-void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { |
- UMA_HISTOGRAM_ENUMERATION("PushMessaging.UserVisibleStatus", |
- status, |
- content::PUSH_USER_VISIBLE_STATUS_LAST + 1); |
-} |
- |
-blink::WebPushPermissionStatus ToPushPermission(ContentSetting setting) { |
- switch (setting) { |
- case CONTENT_SETTING_ALLOW: |
- return blink::WebPushPermissionStatusGranted; |
- case CONTENT_SETTING_BLOCK: |
- return blink::WebPushPermissionStatusDenied; |
- case CONTENT_SETTING_ASK: |
- return blink::WebPushPermissionStatusDefault; |
- default: |
- NOTREACHED(); |
- return blink::WebPushPermissionStatusDenied; |
- } |
-} |
- |
-} // namespace |
- |
-// static |
-void PushMessagingServiceImpl::RegisterProfilePrefs( |
- user_prefs::PrefRegistrySyncable* registry) { |
- registry->RegisterIntegerPref( |
- prefs::kPushMessagingRegistrationCount, |
- 0, |
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
- PushMessagingApplicationId::RegisterProfilePrefs(registry); |
-} |
- |
-// static |
-void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) { |
- // TODO(johnme): Consider whether push should be enabled in incognito. |
- if (!profile || profile->IsOffTheRecord()) |
- return; |
- |
- // TODO(johnme): If push becomes enabled in incognito (and this still uses a |
- // pref), be careful that this pref is read from the right profile, as prefs |
- // defined in a regular profile are visible in the corresponding incognito |
- // profile unless overridden. |
- // TODO(johnme): Make sure this pref doesn't get out of sync after crashes. |
- int count = profile->GetPrefs()->GetInteger( |
- prefs::kPushMessagingRegistrationCount); |
- if (count <= 0) |
- return; |
- |
- // Create the GCMProfileService, and hence instantiate this class. |
- GCMProfileService* gcm_service = |
- GCMProfileServiceFactory::GetForProfile(profile); |
- PushMessagingServiceImpl* push_service = |
- static_cast<PushMessagingServiceImpl*>( |
- gcm_service->push_messaging_service()); |
- |
- push_service->IncreasePushRegistrationCount(count, false /* is_pending */); |
-} |
- |
-PushMessagingServiceImpl::PushMessagingServiceImpl( |
- GCMProfileService* gcm_profile_service, |
- Profile* profile) |
- : gcm_profile_service_(gcm_profile_service), |
- profile_(profile), |
- push_registration_count_(0), |
- pending_push_registration_count_(0), |
- weak_factory_(this) { |
- // In some tests, we might end up with |profile_| being null at this point. |
- // When that is the case |profile_| will be set in SetProfileForTesting(), at |
- // which point the service will start to observe HostContentSettingsMap. |
- if (profile_) |
- profile_->GetHostContentSettingsMap()->AddObserver(this); |
-} |
- |
-PushMessagingServiceImpl::~PushMessagingServiceImpl() { |
- // TODO(johnme): If it's possible for this to be destroyed before GCMDriver, |
- // then we should call RemoveAppHandler. |
- profile_->GetHostContentSettingsMap()->RemoveObserver(this); |
-} |
- |
-void PushMessagingServiceImpl::IncreasePushRegistrationCount(int add, |
- bool is_pending) { |
- DCHECK(add > 0); |
- if (push_registration_count_ + pending_push_registration_count_ == 0) { |
- gcm_profile_service_->driver()->AddAppHandler( |
- kPushMessagingApplicationIdPrefix, this); |
- } |
- if (is_pending) { |
- pending_push_registration_count_ += add; |
- } else { |
- push_registration_count_ += add; |
- profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, |
- push_registration_count_); |
- } |
-} |
- |
-void PushMessagingServiceImpl::DecreasePushRegistrationCount(int subtract, |
- bool was_pending) { |
- DCHECK(subtract > 0); |
- if (was_pending) { |
- pending_push_registration_count_ -= subtract; |
- DCHECK(pending_push_registration_count_ >= 0); |
- } else { |
- push_registration_count_ -= subtract; |
- DCHECK(push_registration_count_ >= 0); |
- profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount, |
- push_registration_count_); |
- } |
- if (push_registration_count_ + pending_push_registration_count_ == 0) { |
- gcm_profile_service_->driver()->RemoveAppHandler( |
- kPushMessagingApplicationIdPrefix); |
- } |
-} |
- |
-bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { |
- return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); |
-} |
- |
-void PushMessagingServiceImpl::ShutdownHandler() { |
- // TODO(johnme): Do any necessary cleanup. |
-} |
- |
-// OnMessage methods ----------------------------------------------------------- |
- |
-void PushMessagingServiceImpl::OnMessage( |
- const std::string& app_id, |
- const GCMClient::IncomingMessage& message) { |
- PushMessagingApplicationId application_id = |
- PushMessagingApplicationId::Get(profile_, app_id); |
- // Drop message and unregister if app id was unknown (maybe recently deleted). |
- if (!application_id.IsValid()) { |
- DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, |
- content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); |
- return; |
- } |
- // Drop message and unregister if |origin| has lost push permission. |
- if (!HasPermission(application_id.origin())) { |
- DeliverMessageCallback(app_id, application_id.origin(), |
- application_id.service_worker_registration_id(), |
- message, |
- content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); |
- return; |
- } |
- |
- // The Push API only exposes a single string of data in the push event fired |
- // on the Service Worker. When developers send messages using GCM to the Push |
- // API and want to include a message payload, they must pass a single key- |
- // value pair, where the key is "data" and the value is the string they want |
- // to be passed to their Service Worker. For example, they could send the |
- // following JSON using the HTTPS GCM API: |
- // { |
- // "registration_ids": ["FOO", "BAR"], |
- // "data": { |
- // "data": "BAZ", |
- // }, |
- // "delay_while_idle": true, |
- // } |
- // TODO(johnme): Make sure this is clearly documented for developers. |
- std::string data; |
- // TODO(peter): Message payloads are disabled pending mandatory encryption. |
- // https://crbug.com/449184 |
- if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kEnablePushMessagePayload)) { |
- GCMClient::MessageData::const_iterator it = message.data.find("data"); |
- if (it != message.data.end()) |
- data = it->second; |
- } |
- |
- content::BrowserContext::DeliverPushMessage( |
- profile_, |
- application_id.origin(), |
- application_id.service_worker_registration_id(), |
- data, |
- base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, |
- weak_factory_.GetWeakPtr(), |
- application_id.app_id_guid(), application_id.origin(), |
- application_id.service_worker_registration_id(), message)); |
-} |
- |
-void PushMessagingServiceImpl::DeliverMessageCallback( |
- const std::string& app_id_guid, |
- const GURL& requesting_origin, |
- int64 service_worker_registration_id, |
- const GCMClient::IncomingMessage& message, |
- content::PushDeliveryStatus status) { |
- // TODO(mvanouwerkerk): Show a warning in the developer console of the |
- // Service Worker corresponding to app_id (and/or on an internals page). |
- // TODO(mvanouwerkerk): Is there a way to recover from failure? |
- switch (status) { |
- // Call RequireUserVisibleUX if the message was delivered to the Service |
- // Worker JS, even if the website's event handler failed (to prevent sites |
- // deliberately failing in order to avoid having to show notifications). |
- case content::PUSH_DELIVERY_STATUS_SUCCESS: |
- case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: |
- RequireUserVisibleUX(requesting_origin, service_worker_registration_id); |
- break; |
- case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: |
- case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: |
- break; |
- case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: |
- case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: |
- case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: |
- Unregister(app_id_guid, message.sender_id, true /* retry_on_failure */, |
- UnregisterCallback()); |
- break; |
- } |
- RecordDeliveryStatus(status); |
-} |
- |
-void PushMessagingServiceImpl::RequireUserVisibleUX( |
- const GURL& requesting_origin, int64 service_worker_registration_id) { |
-#if defined(ENABLE_NOTIFICATIONS) |
- // TODO(johnme): Relax this heuristic slightly. |
- PlatformNotificationServiceImpl* notification_service = |
- PlatformNotificationServiceImpl::GetInstance(); |
- // Can't use g_browser_process->notification_ui_manager(), since the test uses |
- // PlatformNotificationServiceImpl::SetNotificationUIManagerForTesting. |
- // TODO(peter): Remove the need to use both APIs here once Notification.get() |
- // is supported. |
- int notification_count = notification_service->GetNotificationUIManager()-> |
- GetAllIdsByProfileAndSourceOrigin(profile_, requesting_origin).size(); |
- // TODO(johnme): Hiding an existing notification should also count as a useful |
- // user-visible action done in response to a push message - but make sure that |
- // sending two messages in rapid succession which show then hide a |
- // notification doesn't count. |
- bool notification_shown = notification_count > 0; |
- |
- bool notification_needed = true; |
- // Sites with a currently visible tab don't need to show notifications. |
-#if defined(OS_ANDROID) |
- for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { |
- Profile* profile = (*it)->GetProfile(); |
- content::WebContents* active_web_contents = |
- (*it)->GetActiveWebContents(); |
-#else |
- for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
- Profile* profile = it->profile(); |
- content::WebContents* active_web_contents = |
- it->tab_strip_model()->GetActiveWebContents(); |
-#endif |
- if (!active_web_contents || !active_web_contents->GetMainFrame()) |
- continue; |
- |
- // Don't leak information from other profiles. |
- if (profile != profile_) |
- continue; |
- |
- // Ignore minimized windows etc. |
- switch (active_web_contents->GetMainFrame()->GetVisibilityState()) { |
- case blink::WebPageVisibilityStateHidden: |
- case blink::WebPageVisibilityStatePrerender: |
- continue; |
- case blink::WebPageVisibilityStateVisible: |
- break; |
- } |
- |
- // Use the visible URL since that's the one the user is aware of (and it |
- // doesn't matter whether the page loaded successfully). |
- const GURL& active_url = active_web_contents->GetVisibleURL(); |
- if (requesting_origin == active_url.GetOrigin()) { |
- notification_needed = false; |
- break; |
- } |
-#if defined(OS_ANDROID) |
- } |
-#else |
- } |
-#endif |
- |
- // Don't track push messages that didn't show a notification but were exempt |
- // from needing to do so. |
- if (notification_shown || notification_needed) { |
- content::ServiceWorkerContext* service_worker_context = |
- content::BrowserContext::GetStoragePartitionForSite( |
- profile_, requesting_origin)->GetServiceWorkerContext(); |
- |
- PushMessagingService::GetNotificationsShownByLastFewPushes( |
- service_worker_context, service_worker_registration_id, |
- base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, |
- weak_factory_.GetWeakPtr(), |
- requesting_origin, service_worker_registration_id, |
- notification_shown, notification_needed)); |
- } else { |
- RecordUserVisibleStatus( |
- content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); |
- } |
-#endif // defined(ENABLE_NOTIFICATIONS) |
-} |
- |
-static void IgnoreResult(bool unused) { |
-} |
- |
-void PushMessagingServiceImpl::DidGetNotificationsShown( |
- const GURL& requesting_origin, int64 service_worker_registration_id, |
- bool notification_shown, bool notification_needed, |
- const std::string& data, bool success, bool not_found) { |
- content::ServiceWorkerContext* service_worker_context = |
- content::BrowserContext::GetStoragePartitionForSite( |
- profile_, requesting_origin)->GetServiceWorkerContext(); |
- |
- // We remember whether the last (up to) 10 pushes showed notifications. |
- const size_t MISSED_NOTIFICATIONS_LENGTH = 10; |
- // data is a string like "0001000", where '0' means shown, and '1' means |
- // needed but not shown. We manipulate it in bitset form. |
- std::bitset<MISSED_NOTIFICATIONS_LENGTH> missed_notifications(data); |
- |
- bool needed_but_not_shown = notification_needed && !notification_shown; |
- |
- // New entries go at the end, and old ones are shifted off the beginning once |
- // the history length is exceeded. |
- missed_notifications <<= 1; |
- missed_notifications[0] = needed_but_not_shown; |
- std::string updated_data(missed_notifications. |
- to_string<char, std::string::traits_type, std::string::allocator_type>()); |
- PushMessagingService::SetNotificationsShownByLastFewPushes( |
- service_worker_context, service_worker_registration_id, |
- requesting_origin, updated_data, |
- base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. |
- |
- if (notification_shown) { |
- RecordUserVisibleStatus( |
- notification_needed |
- ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN |
- : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); |
- return; |
- } |
- if (needed_but_not_shown) { |
- if (missed_notifications.count() <= 1) { |
- RecordUserVisibleStatus( |
- content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); |
- return; |
- } |
- RecordUserVisibleStatus( |
- content:: |
- PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); |
- // The site failed to show a notification when one was needed, and they have |
- // already failed once in the previous 10 push messages, so we will show a |
- // generic notification. See https://crbug.com/437277. |
- // TODO(johnme): The generic notification should probably automatically |
- // close itself when the next push message arrives? |
- content::PlatformNotificationData notification_data; |
- // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 |
- notification_data.title = base::UTF8ToUTF16(requesting_origin.host()); |
- notification_data.direction = |
- content::PlatformNotificationData::NotificationDirectionLeftToRight; |
- notification_data.body = |
- l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY); |
- notification_data.tag = |
- base::ASCIIToUTF16(kPushMessagingForcedNotificationTag); |
- notification_data.icon = GURL(); // TODO(johnme): Better icon? |
- PlatformNotificationServiceImpl* notification_service = |
- PlatformNotificationServiceImpl::GetInstance(); |
- notification_service->DisplayPersistentNotification( |
- profile_, |
- service_worker_registration_id, |
- requesting_origin, |
- SkBitmap() /* icon */, |
- notification_data); |
- } |
-} |
- |
-// Other GCMAppHandler methods ------------------------------------------------- |
- |
-void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { |
- // TODO(mvanouwerkerk): Fire push error event on the Service Worker |
- // corresponding to app_id. |
-} |
- |
-void PushMessagingServiceImpl::OnSendError( |
- const std::string& app_id, |
- const GCMClient::SendErrorDetails& send_error_details) { |
- NOTREACHED() << "The Push API shouldn't have sent messages upstream"; |
-} |
- |
-void PushMessagingServiceImpl::OnSendAcknowledged( |
- const std::string& app_id, |
- const std::string& message_id) { |
- NOTREACHED() << "The Push API shouldn't have sent messages upstream"; |
-} |
- |
-// GetPushEndpoint method ------------------------------------------------------ |
- |
-GURL PushMessagingServiceImpl::GetPushEndpoint() { |
- return GURL(std::string(kPushMessagingEndpoint)); |
-} |
- |
-// Register and GetPermissionStatus methods ------------------------------------ |
- |
-void PushMessagingServiceImpl::RegisterFromDocument( |
- const GURL& requesting_origin, |
- int64 service_worker_registration_id, |
- const std::string& sender_id, |
- int renderer_id, |
- int render_frame_id, |
- bool user_visible_only, |
- const content::PushMessagingService::RegisterCallback& callback) { |
- if (!gcm_profile_service_->driver()) { |
- NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; |
- return; |
- } |
- |
- PushMessagingApplicationId application_id = |
- PushMessagingApplicationId::Generate(requesting_origin, |
- service_worker_registration_id); |
- DCHECK(application_id.IsValid()); |
- |
- if (push_registration_count_ + pending_push_registration_count_ |
- >= kMaxRegistrations) { |
- RegisterEnd(callback, |
- std::string(), |
- content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); |
- return; |
- } |
- |
- content::RenderFrameHost* render_frame_host = |
- content::RenderFrameHost::FromID(renderer_id, render_frame_id); |
- if (!render_frame_host) |
- return; |
- |
- content::WebContents* web_contents = |
- content::WebContents::FromRenderFrameHost(render_frame_host); |
- if (!web_contents) |
- return; |
- |
- // TODO(miguelg) need to send this over IPC when bubble support is |
- // implemented. |
- int bridge_id = -1; |
- |
- const PermissionRequestID id( |
- renderer_id, web_contents->GetRoutingID(), bridge_id, GURL()); |
- |
- gcm::PushMessagingPermissionContext* permission_context = |
- gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); |
- |
- if (permission_context == NULL || !user_visible_only) { |
- RegisterEnd(callback, |
- std::string(), |
- content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); |
- return; |
- } |
- |
- // TODO(miguelg): Consider the value of |user_visible_only| when making |
- // the permission request. |
- // TODO(mlamouri): Move requesting Push permission over to using Mojo, and |
- // re-introduce the ability of |user_gesture| when bubbles require this. |
- // https://crbug.com/423770. |
- permission_context->RequestPermission( |
- web_contents, id, requesting_origin, true /* user_gesture */, |
- base::Bind(&PushMessagingServiceImpl::DidRequestPermission, |
- weak_factory_.GetWeakPtr(), application_id, sender_id, |
- callback)); |
-} |
- |
-void PushMessagingServiceImpl::RegisterFromWorker( |
- const GURL& requesting_origin, |
- int64 service_worker_registration_id, |
- const std::string& sender_id, |
- const content::PushMessagingService::RegisterCallback& register_callback) { |
- if (!gcm_profile_service_->driver()) { |
- NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; |
- return; |
- } |
- |
- PushMessagingApplicationId application_id = |
- PushMessagingApplicationId::Generate(requesting_origin, |
- service_worker_registration_id); |
- DCHECK(application_id.IsValid()); |
- |
- if (profile_->GetPrefs()->GetInteger( |
- prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) { |
- RegisterEnd(register_callback, std::string(), |
- content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); |
- return; |
- } |
- |
- GURL embedding_origin = requesting_origin; |
- blink::WebPushPermissionStatus permission_status = |
- PushMessagingServiceImpl::GetPermissionStatus(requesting_origin, |
- embedding_origin); |
- if (permission_status != blink::WebPushPermissionStatusGranted) { |
- RegisterEnd(register_callback, std::string(), |
- content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); |
- return; |
- } |
- |
- IncreasePushRegistrationCount(1, true /* is_pending */); |
- std::vector<std::string> sender_ids(1, sender_id); |
- gcm_profile_service_->driver()->Register( |
- application_id.app_id_guid(), sender_ids, |
- base::Bind(&PushMessagingServiceImpl::DidRegister, |
- weak_factory_.GetWeakPtr(), |
- application_id, register_callback)); |
-} |
- |
-blink::WebPushPermissionStatus PushMessagingServiceImpl::GetPermissionStatus( |
- const GURL& requesting_origin, |
- const GURL& embedding_origin) { |
- PushMessagingPermissionContext* permission_context = |
- PushMessagingPermissionContextFactory::GetForProfile(profile_); |
- return ToPushPermission(permission_context->GetPermissionStatus( |
- requesting_origin, embedding_origin)); |
-} |
- |
-void PushMessagingServiceImpl::RegisterEnd( |
- const content::PushMessagingService::RegisterCallback& callback, |
- const std::string& registration_id, |
- content::PushRegistrationStatus status) { |
- callback.Run(registration_id, status); |
-} |
- |
-void PushMessagingServiceImpl::DidRegister( |
- const PushMessagingApplicationId& application_id, |
- const content::PushMessagingService::RegisterCallback& callback, |
- const std::string& registration_id, |
- GCMClient::Result result) { |
- content::PushRegistrationStatus status = |
- content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; |
- switch (result) { |
- case GCMClient::SUCCESS: |
- status = content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE; |
- application_id.PersistToDisk(profile_); |
- IncreasePushRegistrationCount(1, false /* is_pending */); |
- break; |
- case GCMClient::INVALID_PARAMETER: |
- case GCMClient::GCM_DISABLED: |
- case GCMClient::ASYNC_OPERATION_PENDING: |
- case GCMClient::SERVER_ERROR: |
- case GCMClient::UNKNOWN_ERROR: |
- status = content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; |
- break; |
- case GCMClient::NETWORK_ERROR: |
- case GCMClient::TTL_EXCEEDED: |
- status = content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR; |
- break; |
- } |
- RegisterEnd(callback, registration_id, status); |
- DecreasePushRegistrationCount(1, true /* was_pending */); |
-} |
- |
-void PushMessagingServiceImpl::DidRequestPermission( |
- const PushMessagingApplicationId& application_id, |
- const std::string& sender_id, |
- const content::PushMessagingService::RegisterCallback& register_callback, |
- ContentSetting content_setting) { |
- if (content_setting != CONTENT_SETTING_ALLOW) { |
- RegisterEnd(register_callback, |
- std::string(), |
- content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); |
- return; |
- } |
- |
- // The GCMDriver could be NULL if GCMProfileService has been shut down. |
- if (!gcm_profile_service_->driver()) |
- return; |
- |
- IncreasePushRegistrationCount(1, true /* is_pending */); |
- std::vector<std::string> sender_ids(1, sender_id); |
- gcm_profile_service_->driver()->Register( |
- application_id.app_id_guid(), |
- sender_ids, |
- base::Bind(&PushMessagingServiceImpl::DidRegister, |
- weak_factory_.GetWeakPtr(), |
- application_id, register_callback)); |
-} |
- |
-// Unregister methods ---------------------------------------------------------- |
- |
-void PushMessagingServiceImpl::Unregister( |
- const GURL& requesting_origin, |
- int64 service_worker_registration_id, |
- const std::string& sender_id, |
- bool retry_on_failure, |
- const content::PushMessagingService::UnregisterCallback& callback) { |
- DCHECK(gcm_profile_service_->driver()); |
- |
- PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( |
- profile_, requesting_origin, service_worker_registration_id); |
- if (!application_id.IsValid()) { |
- if (!callback.is_null()) { |
- callback.Run( |
- content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); |
- } |
- return; |
- } |
- |
- Unregister(application_id.app_id_guid(), sender_id, retry_on_failure, |
- callback); |
-} |
- |
-void PushMessagingServiceImpl::Unregister( |
- const std::string& app_id_guid, |
- const std::string& sender_id, |
- bool retry_on_failure, |
- const content::PushMessagingService::UnregisterCallback& callback) { |
- DCHECK(gcm_profile_service_->driver()); |
- |
- if (retry_on_failure) { |
- // Delete the mapping for this app id, to guarantee that no messages get |
- // delivered in future (even if unregistration fails). |
- // TODO(johnme): Instead of deleting these app ids, store them elsewhere, |
- // and retry unregistration if it fails due to network errors. |
- PushMessagingApplicationId application_id = |
- PushMessagingApplicationId::Get(profile_, app_id_guid); |
- if (application_id.IsValid()) |
- application_id.DeleteFromDisk(profile_); |
- } |
- |
- const auto& unregister_callback = |
- base::Bind(&PushMessagingServiceImpl::DidUnregister, |
- weak_factory_.GetWeakPtr(), |
- app_id_guid, retry_on_failure, callback); |
-#if defined(OS_ANDROID) |
- // On Android the backend is different, and requires the original sender_id. |
- gcm_profile_service_->driver()->UnregisterWithSenderId(app_id_guid, sender_id, |
- unregister_callback); |
-#else |
- gcm_profile_service_->driver()->Unregister(app_id_guid, unregister_callback); |
-#endif |
-} |
- |
-void PushMessagingServiceImpl::DidUnregister( |
- const std::string& app_id_guid, |
- bool retry_on_failure, |
- const content::PushMessagingService::UnregisterCallback& callback, |
- GCMClient::Result result) { |
- if (result == GCMClient::SUCCESS) { |
- PushMessagingApplicationId application_id = |
- PushMessagingApplicationId::Get(profile_, app_id_guid); |
- if (!application_id.IsValid()) { |
- if (!callback.is_null()) { |
- callback.Run( |
- content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); |
- } |
- return; |
- } |
- |
- application_id.DeleteFromDisk(profile_); |
- DecreasePushRegistrationCount(1, false /* was_pending */); |
- } |
- |
- // Internal calls pass a null callback. |
- if (!callback.is_null()) { |
- switch (result) { |
- case GCMClient::SUCCESS: |
- callback.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED); |
- break; |
- case GCMClient::INVALID_PARAMETER: |
- case GCMClient::GCM_DISABLED: |
- case GCMClient::ASYNC_OPERATION_PENDING: |
- case GCMClient::SERVER_ERROR: |
- case GCMClient::UNKNOWN_ERROR: |
- callback.Run(content::PUSH_UNREGISTRATION_STATUS_SERVICE_ERROR); |
- break; |
- case GCMClient::NETWORK_ERROR: |
- case GCMClient::TTL_EXCEEDED: |
- callback.Run( |
- retry_on_failure |
- ? content:: |
- PUSH_UNREGISTRATION_STATUS_PENDING_WILL_RETRY_NETWORK_ERROR |
- : content::PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR); |
- break; |
- } |
- } |
-} |
- |
-// OnContentSettingChanged methods --------------------------------------------- |
- |
-void PushMessagingServiceImpl::OnContentSettingChanged( |
- const ContentSettingsPattern& primary_pattern, |
- const ContentSettingsPattern& secondary_pattern, |
- ContentSettingsType content_type, |
- std::string resource_identifier) { |
- if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING && |
- content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { |
- return; |
- } |
- |
- for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) { |
- // If |primary_pattern| is not valid, we should always check for a |
- // permission change because it can happen for example when the entire |
- // Push or Notifications permissions are cleared. |
- // Otherwise, the permission should be checked if the pattern matches the |
- // origin. |
- if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin())) |
- continue; |
- |
- if (HasPermission(id.origin())) |
- continue; |
- |
- PushMessagingService::GetSenderId( |
- profile_, id.origin(), id.service_worker_registration_id(), |
- base::Bind( |
- &PushMessagingServiceImpl::UnregisterBecausePermissionRevoked, |
- weak_factory_.GetWeakPtr(), id)); |
- } |
-} |
- |
-void PushMessagingServiceImpl::UnregisterBecausePermissionRevoked( |
- const PushMessagingApplicationId& id, |
- const std::string& sender_id, bool success, bool not_found) { |
- // Unregister the PushMessagingApplicationId with the push service. |
- Unregister(id.app_id_guid(), sender_id, true /* retry_on_failure */, |
- UnregisterCallback()); |
- |
- // Clear the associated service worker push registration id. |
- PushMessagingService::ClearPushRegistrationID( |
- profile_, id.origin(), id.service_worker_registration_id()); |
-} |
- |
-// Helper methods -------------------------------------------------------------- |
- |
-bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { |
- gcm::PushMessagingPermissionContext* permission_context = |
- gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); |
- DCHECK(permission_context); |
- |
- return permission_context->GetPermissionStatus(origin, origin) == |
- CONTENT_SETTING_ALLOW; |
-} |
- |
-void PushMessagingServiceImpl::SetProfileForTesting(Profile* profile) { |
- profile_ = profile; |
- profile_->GetHostContentSettingsMap()->AddObserver(this); |
-} |
- |
-} // namespace gcm |