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.
5 #include "chrome/browser/drive/drive_notification_manager.h"
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"
18 // The polling interval time is used when XMPP is disabled.
19 const int kFastPollingIntervalInSecs
= 60;
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;
25 // The sync invalidation object ID for Google Drive.
26 const char kDriveInvalidationObjectId
[] = "CHANGELOG";
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();
43 DriveNotificationManager::~DriveNotificationManager() {}
45 void DriveNotificationManager::Shutdown() {
46 // Unregister for Drive notifications.
47 if (!invalidation_service_
|| !push_notification_registered_
)
50 // We unregister the handler without updating unregistering our IDs on
51 // purpose. See the class comment on the InvalidationService interface for
53 invalidation_service_
->UnregisterInvalidationHandler(this);
54 invalidation_service_
= NULL
;
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";
63 DVLOG(1) << "XMPP Notifications disabled (state=" << state
<< ")";
65 FOR_EACH_OBSERVER(DriveNotificationObserver
, observers_
,
66 OnPushNotificationEnabled(push_notification_enabled_
));
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
));
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
);
86 std::string
DriveNotificationManager::GetOwnerName() const { return "Drive"; }
88 void DriveNotificationManager::AddObserver(
89 DriveNotificationObserver
* observer
) {
90 observers_
.AddObserver(observer
);
93 void DriveNotificationManager::RemoveObserver(
94 DriveNotificationObserver
* observer
) {
95 observers_
.RemoveObserver(observer
);
98 void DriveNotificationManager::RestartPollingTimer() {
99 const int interval_secs
= (push_notification_enabled_
?
100 kSlowPollingIntervalInSecs
:
101 kFastPollingIntervalInSecs
);
102 polling_timer_
.Stop();
103 polling_timer_
.Start(
105 base::TimeDelta::FromSeconds(interval_secs
),
106 base::Bind(&DriveNotificationManager::NotifyObserversToUpdate
,
107 weak_ptr_factory_
.GetWeakPtr(),
108 NOTIFICATION_POLLING
));
111 void DriveNotificationManager::NotifyObserversToUpdate(
112 NotificationSource source
) {
113 DVLOG(1) << "Notifying observers: " << NotificationSourceToString(source
);
114 FOR_EACH_OBSERVER(DriveNotificationObserver
, observers_
,
115 OnNotificationReceived());
116 if (!observers_notified_
) {
117 UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationInitiallyEnabled",
118 push_notification_enabled_
);
120 observers_notified_
= true;
122 // Note that polling_timer_ is not a repeating timer. Restarting manually
123 // here is better as XMPP may be received right before the polling timer is
124 // fired (i.e. we don't notify observers twice in a row).
125 RestartPollingTimer();
128 void DriveNotificationManager::RegisterDriveNotifications() {
129 DCHECK(!push_notification_enabled_
);
131 if (!invalidation_service_
)
134 invalidation_service_
->RegisterInvalidationHandler(this);
135 syncer::ObjectIdSet ids
;
136 ids
.insert(invalidation::ObjectId(
137 ipc::invalidation::ObjectSource::COSMO_CHANGELOG
,
138 kDriveInvalidationObjectId
));
139 invalidation_service_
->UpdateRegisteredInvalidationIds(this, ids
);
140 push_notification_registered_
= true;
141 OnInvalidatorStateChange(invalidation_service_
->GetInvalidatorState());
143 UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationRegistered",
144 push_notification_registered_
);
148 std::string
DriveNotificationManager::NotificationSourceToString(
149 NotificationSource source
) {
151 case NOTIFICATION_XMPP
:
152 return "NOTIFICATION_XMPP";
153 case NOTIFICATION_POLLING
:
154 return "NOTIFICATION_POLLING";