Home | History | Annotate | Download | only in drive
      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 "components/invalidation/invalidation_service.h"
     10 #include "google/cacheinvalidation/types.pb.h"
     11 #include "sync/notifier/object_id_invalidation_map.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   // This effectively disables 'local acks'.  It tells the invalidations system
     79   // to not bother saving invalidations across restarts for us.
     80   // See crbug.com/320878.
     81   invalidation_map.AcknowledgeAll();
     82   NotifyObserversToUpdate(NOTIFICATION_XMPP);
     83 }
     84 
     85 std::string DriveNotificationManager::GetOwnerName() const { return "Drive"; }
     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
    161