• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/drive/drive_notification_manager.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "chrome/browser/drive/drive_notification_observer.h"
9 #include "chrome/browser/invalidation/invalidation_service.h"
10 #include "chrome/browser/invalidation/invalidation_service_factory.h"
11 #include "google/cacheinvalidation/types.pb.h"
12 #include "sync/notifier/object_id_invalidation_map.h"
13 
14 namespace drive {
15 
16 namespace {
17 
18 // The polling interval time is used when XMPP is disabled.
19 const int kFastPollingIntervalInSecs = 60;
20 
21 // The polling interval time is used when XMPP is enabled.  Theoretically
22 // polling should be unnecessary if XMPP is enabled, but just in case.
23 const int kSlowPollingIntervalInSecs = 300;
24 
25 // The sync invalidation object ID for Google Drive.
26 const char kDriveInvalidationObjectId[] = "CHANGELOG";
27 
28 }  // namespace
29 
DriveNotificationManager(invalidation::InvalidationService * invalidation_service)30 DriveNotificationManager::DriveNotificationManager(
31     invalidation::InvalidationService* invalidation_service)
32     : invalidation_service_(invalidation_service),
33       push_notification_registered_(false),
34       push_notification_enabled_(false),
35       observers_notified_(false),
36       polling_timer_(true /* retain_user_task */, false /* is_repeating */),
37       weak_ptr_factory_(this) {
38   DCHECK(invalidation_service_);
39   RegisterDriveNotifications();
40   RestartPollingTimer();
41 }
42 
~DriveNotificationManager()43 DriveNotificationManager::~DriveNotificationManager() {}
44 
Shutdown()45 void DriveNotificationManager::Shutdown() {
46   // Unregister for Drive notifications.
47   if (!invalidation_service_ || !push_notification_registered_)
48     return;
49 
50   // We unregister the handler without updating unregistering our IDs on
51   // purpose.  See the class comment on the InvalidationService interface for
52   // more information.
53   invalidation_service_->UnregisterInvalidationHandler(this);
54   invalidation_service_ = NULL;
55 }
56 
OnInvalidatorStateChange(syncer::InvalidatorState state)57 void DriveNotificationManager::OnInvalidatorStateChange(
58     syncer::InvalidatorState state) {
59   push_notification_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
60   if (push_notification_enabled_) {
61     DVLOG(1) << "XMPP Notifications enabled";
62   } else {
63     DVLOG(1) << "XMPP Notifications disabled (state=" << state << ")";
64   }
65   FOR_EACH_OBSERVER(DriveNotificationObserver, observers_,
66                     OnPushNotificationEnabled(push_notification_enabled_));
67 }
68 
OnIncomingInvalidation(const syncer::ObjectIdInvalidationMap & invalidation_map)69 void DriveNotificationManager::OnIncomingInvalidation(
70     const syncer::ObjectIdInvalidationMap& invalidation_map) {
71   DVLOG(2) << "XMPP Drive Notification Received";
72   syncer::ObjectIdSet ids = invalidation_map.GetObjectIds();
73   DCHECK_EQ(1U, ids.size());
74   const invalidation::ObjectId object_id(
75       ipc::invalidation::ObjectSource::COSMO_CHANGELOG,
76       kDriveInvalidationObjectId);
77   DCHECK_EQ(1U, ids.count(object_id));
78 
79   // This effectively disables 'local acks'.  It tells the invalidations system
80   // to not bother saving invalidations across restarts for us.
81   // See crbug.com/320878.
82   invalidation_map.AcknowledgeAll();
83   NotifyObserversToUpdate(NOTIFICATION_XMPP);
84 }
85 
AddObserver(DriveNotificationObserver * observer)86 void DriveNotificationManager::AddObserver(
87     DriveNotificationObserver* observer) {
88   observers_.AddObserver(observer);
89 }
90 
RemoveObserver(DriveNotificationObserver * observer)91 void DriveNotificationManager::RemoveObserver(
92     DriveNotificationObserver* observer) {
93   observers_.RemoveObserver(observer);
94 }
95 
RestartPollingTimer()96 void DriveNotificationManager::RestartPollingTimer() {
97   const int interval_secs = (push_notification_enabled_ ?
98                              kSlowPollingIntervalInSecs :
99                              kFastPollingIntervalInSecs);
100   polling_timer_.Stop();
101   polling_timer_.Start(
102       FROM_HERE,
103       base::TimeDelta::FromSeconds(interval_secs),
104       base::Bind(&DriveNotificationManager::NotifyObserversToUpdate,
105                  weak_ptr_factory_.GetWeakPtr(),
106                  NOTIFICATION_POLLING));
107 }
108 
NotifyObserversToUpdate(NotificationSource source)109 void DriveNotificationManager::NotifyObserversToUpdate(
110     NotificationSource source) {
111   DVLOG(1) << "Notifying observers: " << NotificationSourceToString(source);
112   FOR_EACH_OBSERVER(DriveNotificationObserver, observers_,
113                     OnNotificationReceived());
114   if (!observers_notified_) {
115     UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationInitiallyEnabled",
116                           push_notification_enabled_);
117   }
118   observers_notified_ = true;
119 
120   // Note that polling_timer_ is not a repeating timer. Restarting manually
121   // here is better as XMPP may be received right before the polling timer is
122   // fired (i.e. we don't notify observers twice in a row).
123   RestartPollingTimer();
124 }
125 
RegisterDriveNotifications()126 void DriveNotificationManager::RegisterDriveNotifications() {
127   DCHECK(!push_notification_enabled_);
128 
129   if (!invalidation_service_)
130     return;
131 
132   invalidation_service_->RegisterInvalidationHandler(this);
133   syncer::ObjectIdSet ids;
134   ids.insert(invalidation::ObjectId(
135       ipc::invalidation::ObjectSource::COSMO_CHANGELOG,
136       kDriveInvalidationObjectId));
137   invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
138   push_notification_registered_ = true;
139   OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
140 
141   UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationRegistered",
142                         push_notification_registered_);
143 }
144 
145 // static
NotificationSourceToString(NotificationSource source)146 std::string DriveNotificationManager::NotificationSourceToString(
147     NotificationSource source) {
148   switch (source) {
149     case NOTIFICATION_XMPP:
150       return "NOTIFICATION_XMPP";
151     case NOTIFICATION_POLLING:
152       return "NOTIFICATION_POLLING";
153   }
154 
155   NOTREACHED();
156   return "";
157 }
158 
159 }  // namespace drive
160