| 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
|
| index f6043b495bd9650c7b37f2ebd8947aa640847c15..0306d111fe66e95f69e299af9d68056c0989f568 100644
|
| --- a/chrome/browser/services/gcm/push_messaging_service_impl.cc
|
| +++ b/chrome/browser/services/gcm/push_messaging_service_impl.cc
|
| @@ -7,40 +7,170 @@
|
| #include <vector>
|
|
|
| #include "base/bind.h"
|
| +#include "base/command_line.h"
|
| +#include "base/prefs/pref_service.h"
|
| +#include "base/strings/string_util.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/common/chrome_switches.h"
|
| +#include "chrome/common/pref_names.h"
|
| #include "components/gcm_driver/gcm_driver.h"
|
| +#include "components/pref_registry/pref_registry_syncable.h"
|
|
|
| namespace gcm {
|
|
|
| +namespace {
|
| +const char kAppIdPrefix[] = "push:";
|
| +const int kMaxRegistrations = 1000000;
|
| +} // namespace
|
| +
|
| +// static
|
| +void PushMessagingServiceImpl::RegisterProfilePrefs(
|
| + user_prefs::PrefRegistrySyncable* registry) {
|
| + registry->RegisterIntegerPref(
|
| + prefs::kPushMessagingRegistrationCount,
|
| + 0,
|
| + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
|
| +}
|
| +
|
| +// static
|
| +void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) {
|
| + // TODO(mvanouwerkerk): Make sure to remove this check at the same time as
|
| + // push graduates from experimental in Blink.
|
| + if (!CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableExperimentalWebPlatformFeatures)) {
|
| + return;
|
| + }
|
| + // TODO(johnme): Consider whether push should be enabled in incognito. If it
|
| + // does get enabled, then be careful that you're reading the pref from the
|
| + // right profile, as prefs defined in a regular profile are visible in the
|
| + // corresponding incognito profile unless overrriden.
|
| + if (!profile || profile->IsOffTheRecord() ||
|
| + profile->GetPrefs()->GetInteger(prefs::kPushMessagingRegistrationCount) <=
|
| + 0) {
|
| + return;
|
| + }
|
| + // Create the GCMProfileService, and hence instantiate this class.
|
| + GCMProfileService* gcm_service =
|
| + gcm::GCMProfileServiceFactory::GetForProfile(profile);
|
| + PushMessagingServiceImpl* push_service =
|
| + static_cast<PushMessagingServiceImpl*>(
|
| + gcm_service->push_messaging_service());
|
| + // Register ourselves as an app handler.
|
| + gcm_service->driver()->AddAppHandler(kAppIdPrefix, push_service);
|
| +}
|
| +
|
| PushMessagingServiceImpl::PushMessagingServiceImpl(
|
| - GCMProfileService* gcm_profile_service)
|
| + GCMProfileService* gcm_profile_service,
|
| + Profile* profile)
|
| : gcm_profile_service_(gcm_profile_service),
|
| - weak_factory_(this) {}
|
| + profile_(profile),
|
| + weak_factory_(this) {
|
| +}
|
| +
|
| +PushMessagingServiceImpl::~PushMessagingServiceImpl() {
|
| + // TODO(johnme): If it's possible for this to be destroyed before GCMDriver,
|
| + // then we should call RemoveAppHandler.
|
| +}
|
| +
|
| +bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {
|
| + // TODO(mvanouwerkerk): Finalize and centralize format of Push API app_id.
|
| + return StartsWithASCII(app_id, kAppIdPrefix, true);
|
| +}
|
| +
|
| +void PushMessagingServiceImpl::ShutdownHandler() {
|
| + // TODO(johnme): Do any necessary cleanup.
|
| +}
|
|
|
| -PushMessagingServiceImpl::~PushMessagingServiceImpl() {}
|
| +void PushMessagingServiceImpl::OnMessage(
|
| + const std::string& app_id,
|
| + const GCMClient::IncomingMessage& message) {
|
| + // 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, 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.
|
| + GCMClient::MessageData::const_iterator it = message.data.find("data");
|
| + if (it != message.data.end()) {
|
| + const std::string& data ALLOW_UNUSED = it->second;
|
| + // TODO(mvanouwerkerk): Fire push event with data on the Service Worker
|
| + // corresponding to app_id (and remove ALLOW_UNUSED above).
|
| + } else {
|
| + // Drop the message, as it is invalid.
|
| + // TODO(mvanouwerkerk): Show a warning in the developer console of the
|
| + // Service Worker corresponding to app_id.
|
| + // TODO(johnme): Add diagnostic observers (e.g. UMA and an internals page)
|
| + // to know when bad things happen.
|
| + }
|
| +}
|
| +
|
| +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::Register(
|
| const std::string& app_id,
|
| const std::string& sender_id,
|
| const content::PushMessagingService::RegisterCallback& callback) {
|
| - // The GCMDriver could be NULL if GCMProfileService has been shut down.
|
| - if (!gcm_profile_service_->driver())
|
| + if (!gcm_profile_service_->driver()) {
|
| + NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?";
|
| + }
|
| +
|
| + if (profile_->GetPrefs()->GetInteger(
|
| + prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) {
|
| + DidRegister(app_id, callback, "", GCMClient::UNKNOWN_ERROR);
|
| return;
|
| + }
|
| +
|
| + // If this is registering for the first time then the driver does not have
|
| + // this as an app handler and registration would fail.
|
| + if (gcm_profile_service_->driver()->GetAppHandler(kAppIdPrefix) != this)
|
| + gcm_profile_service_->driver()->AddAppHandler(kAppIdPrefix, this);
|
| +
|
| std::vector<std::string> sender_ids(1, sender_id);
|
| gcm_profile_service_->driver()->Register(
|
| app_id,
|
| sender_ids,
|
| base::Bind(&PushMessagingServiceImpl::DidRegister,
|
| weak_factory_.GetWeakPtr(),
|
| + app_id,
|
| callback));
|
| }
|
|
|
| void PushMessagingServiceImpl::DidRegister(
|
| + const std::string& app_id,
|
| const content::PushMessagingService::RegisterCallback& callback,
|
| const std::string& registration_id,
|
| GCMClient::Result result) {
|
| GURL endpoint = GURL("https://android.googleapis.com/gcm/send");
|
| - callback.Run(endpoint, registration_id, result == GCMClient::SUCCESS);
|
| + bool success = (result == GCMClient::SUCCESS);
|
| + callback.Run(endpoint, registration_id, success);
|
| + if (success) {
|
| + // TODO(johnme): Make sure the pref doesn't get out of sync after crashes.
|
| + int registration_count = profile_->GetPrefs()->GetInteger(
|
| + prefs::kPushMessagingRegistrationCount);
|
| + profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount,
|
| + registration_count + 1);
|
| + }
|
| }
|
|
|
| +// TODO(johnme): Unregister should decrement the pref, and call
|
| +// RemoveAppHandler if the count drops to zero.
|
| +
|
| } // namespace gcm
|
|
|