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 "components/invalidation/object_id_invalidation_map.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 // 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