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 "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 
     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 
     43 DriveNotificationManager::~DriveNotificationManager() {}
     44 
     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 
     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 
     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 
     86 void DriveNotificationManager::AddObserver(
     87     DriveNotificationObserver* observer) {
     88   observers_.AddObserver(observer);
     89 }
     90 
     91 void DriveNotificationManager::RemoveObserver(
     92     DriveNotificationObserver* observer) {
     93   observers_.RemoveObserver(observer);
     94 }
     95 
     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 
    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 
    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
    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