- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / drive / drive_notification_manager.cc
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
13 namespace drive {
14
15 namespace {
16
17 // The polling interval time is used when XMPP is disabled.
18 const int kFastPollingIntervalInSecs = 60;
19
20 // The polling interval time is used when XMPP is enabled.  Theoretically
21 // polling should be unnecessary if XMPP is enabled, but just in case.
22 const int kSlowPollingIntervalInSecs = 300;
23
24 // The sync invalidation object ID for Google Drive.
25 const char kDriveInvalidationObjectId[] = "CHANGELOG";
26
27 }  // namespace
28
29 DriveNotificationManager::DriveNotificationManager(
30     invalidation::InvalidationService* invalidation_service)
31     : invalidation_service_(invalidation_service),
32       push_notification_registered_(false),
33       push_notification_enabled_(false),
34       observers_notified_(false),
35       polling_timer_(true /* retain_user_task */, false /* is_repeating */),
36       weak_ptr_factory_(this) {
37   DCHECK(invalidation_service_);
38   RegisterDriveNotifications();
39   RestartPollingTimer();
40 }
41
42 DriveNotificationManager::~DriveNotificationManager() {}
43
44 void DriveNotificationManager::Shutdown() {
45   // Unregister for Drive notifications.
46   if (!invalidation_service_ || !push_notification_registered_)
47     return;
48
49   // We unregister the handler without updating unregistering our IDs on
50   // purpose.  See the class comment on the InvalidationService interface for
51   // more information.
52   invalidation_service_->UnregisterInvalidationHandler(this);
53   invalidation_service_ = NULL;
54 }
55
56 void DriveNotificationManager::OnInvalidatorStateChange(
57     syncer::InvalidatorState state) {
58   push_notification_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
59   if (push_notification_enabled_) {
60     DVLOG(1) << "XMPP Notifications enabled";
61   } else {
62     DVLOG(1) << "XMPP Notifications disabled (state=" << state << ")";
63   }
64   FOR_EACH_OBSERVER(DriveNotificationObserver, observers_,
65                     OnPushNotificationEnabled(push_notification_enabled_));
66 }
67
68 void DriveNotificationManager::OnIncomingInvalidation(
69     const syncer::ObjectIdInvalidationMap& invalidation_map) {
70   DVLOG(2) << "XMPP Drive Notification Received";
71   syncer::ObjectIdSet ids = invalidation_map.GetObjectIds();
72   DCHECK_EQ(1U, ids.size());
73   const invalidation::ObjectId object_id(
74       ipc::invalidation::ObjectSource::COSMO_CHANGELOG,
75       kDriveInvalidationObjectId);
76   DCHECK_EQ(1U, ids.count(object_id));
77
78   // TODO(dcheng): Only acknowledge the invalidation once the fetch has
79   // completed. http://crbug.com/156843
80   DCHECK(invalidation_service_);
81   syncer::Invalidation inv = invalidation_map.ForObject(object_id).back();
82   invalidation_service_->AcknowledgeInvalidation(object_id, inv.ack_handle());
83
84   NotifyObserversToUpdate(NOTIFICATION_XMPP);
85 }
86
87 void DriveNotificationManager::AddObserver(
88     DriveNotificationObserver* observer) {
89   observers_.AddObserver(observer);
90 }
91
92 void DriveNotificationManager::RemoveObserver(
93     DriveNotificationObserver* observer) {
94   observers_.RemoveObserver(observer);
95 }
96
97 void DriveNotificationManager::RestartPollingTimer() {
98   const int interval_secs = (push_notification_enabled_ ?
99                              kSlowPollingIntervalInSecs :
100                              kFastPollingIntervalInSecs);
101   polling_timer_.Stop();
102   polling_timer_.Start(
103       FROM_HERE,
104       base::TimeDelta::FromSeconds(interval_secs),
105       base::Bind(&DriveNotificationManager::NotifyObserversToUpdate,
106                  weak_ptr_factory_.GetWeakPtr(),
107                  NOTIFICATION_POLLING));
108 }
109
110 void DriveNotificationManager::NotifyObserversToUpdate(
111     NotificationSource source) {
112   DVLOG(1) << "Notifying observers: " << NotificationSourceToString(source);
113   FOR_EACH_OBSERVER(DriveNotificationObserver, observers_,
114                     OnNotificationReceived());
115   if (!observers_notified_) {
116     UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationInitiallyEnabled",
117                           push_notification_enabled_);
118   }
119   observers_notified_ = true;
120
121   // Note that polling_timer_ is not a repeating timer. Restarting manually
122   // here is better as XMPP may be received right before the polling timer is
123   // fired (i.e. we don't notify observers twice in a row).
124   RestartPollingTimer();
125 }
126
127 void DriveNotificationManager::RegisterDriveNotifications() {
128   DCHECK(!push_notification_enabled_);
129
130   if (!invalidation_service_)
131     return;
132
133   invalidation_service_->RegisterInvalidationHandler(this);
134   syncer::ObjectIdSet ids;
135   ids.insert(invalidation::ObjectId(
136       ipc::invalidation::ObjectSource::COSMO_CHANGELOG,
137       kDriveInvalidationObjectId));
138   invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
139   push_notification_registered_ = true;
140   OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
141
142   UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationRegistered",
143                         push_notification_registered_);
144 }
145
146 // static
147 std::string DriveNotificationManager::NotificationSourceToString(
148     NotificationSource source) {
149   switch (source) {
150     case NOTIFICATION_XMPP:
151       return "NOTIFICATION_XMPP";
152     case NOTIFICATION_POLLING:
153       return "NOTIFICATION_POLLING";
154   }
155
156   NOTREACHED();
157   return "";
158 }
159
160 }  // namespace drive