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 "chrome/browser/profiles/profile.h" 12 #include "google/cacheinvalidation/types.pb.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(Profile* profile) 31 : profile_(profile), 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 RegisterDriveNotifications(); 38 RestartPollingTimer(); 39 } 40 41 DriveNotificationManager::~DriveNotificationManager() {} 42 43 void DriveNotificationManager::Shutdown() { 44 // Unregister for Drive notifications. 45 invalidation::InvalidationService* invalidation_service = 46 invalidation::InvalidationServiceFactory::GetForProfile(profile_); 47 if (!invalidation_service || !push_notification_registered_) { 48 return; 49 } 50 51 // We unregister the handler without updating unregistering our IDs on 52 // purpose. See the class comment on the InvalidationService interface for 53 // more information. 54 invalidation_service->UnregisterInvalidationHandler(this); 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 DCHECK_EQ(1U, invalidation_map.size()); 73 const invalidation::ObjectId object_id( 74 ipc::invalidation::ObjectSource::COSMO_CHANGELOG, 75 kDriveInvalidationObjectId); 76 DCHECK_EQ(1U, invalidation_map.count(object_id)); 77 78 // TODO(dcheng): Only acknowledge the invalidation once the fetch has 79 // completed. http://crbug.com/156843 80 invalidation::InvalidationService* invalidation_service = 81 invalidation::InvalidationServiceFactory::GetForProfile(profile_); 82 DCHECK(invalidation_service); 83 invalidation_service->AcknowledgeInvalidation( 84 invalidation_map.begin()->first, 85 invalidation_map.begin()->second.ack_handle); 86 87 NotifyObserversToUpdate(NOTIFICATION_XMPP); 88 } 89 90 void DriveNotificationManager::AddObserver( 91 DriveNotificationObserver* observer) { 92 observers_.AddObserver(observer); 93 } 94 95 void DriveNotificationManager::RemoveObserver( 96 DriveNotificationObserver* observer) { 97 observers_.RemoveObserver(observer); 98 } 99 100 void DriveNotificationManager::RestartPollingTimer() { 101 const int interval_secs = (push_notification_enabled_ ? 102 kSlowPollingIntervalInSecs : 103 kFastPollingIntervalInSecs); 104 polling_timer_.Stop(); 105 polling_timer_.Start( 106 FROM_HERE, 107 base::TimeDelta::FromSeconds(interval_secs), 108 base::Bind(&DriveNotificationManager::NotifyObserversToUpdate, 109 weak_ptr_factory_.GetWeakPtr(), 110 NOTIFICATION_POLLING)); 111 } 112 113 void DriveNotificationManager::NotifyObserversToUpdate( 114 NotificationSource source) { 115 DVLOG(1) << "Notifying observers: " << NotificationSourceToString(source); 116 FOR_EACH_OBSERVER(DriveNotificationObserver, observers_, 117 OnNotificationReceived()); 118 if (!observers_notified_) { 119 UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationInitiallyEnabled", 120 push_notification_enabled_); 121 } 122 observers_notified_ = true; 123 124 // Note that polling_timer_ is not a repeating timer. Restarting manually 125 // here is better as XMPP may be received right before the polling timer is 126 // fired (i.e. we don't notify observers twice in a row). 127 RestartPollingTimer(); 128 } 129 130 void DriveNotificationManager::RegisterDriveNotifications() { 131 DCHECK(!push_notification_enabled_); 132 133 invalidation::InvalidationService* invalidation_service = 134 invalidation::InvalidationServiceFactory::GetForProfile(profile_); 135 if (!invalidation_service) 136 return; 137 138 invalidation_service->RegisterInvalidationHandler(this); 139 syncer::ObjectIdSet ids; 140 ids.insert(invalidation::ObjectId( 141 ipc::invalidation::ObjectSource::COSMO_CHANGELOG, 142 kDriveInvalidationObjectId)); 143 invalidation_service->UpdateRegisteredInvalidationIds(this, ids); 144 push_notification_registered_ = true; 145 OnInvalidatorStateChange(invalidation_service->GetInvalidatorState()); 146 147 UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationRegistered", 148 push_notification_registered_); 149 } 150 151 // static 152 std::string DriveNotificationManager::NotificationSourceToString( 153 NotificationSource source) { 154 switch (source) { 155 case NOTIFICATION_XMPP: 156 return "NOTIFICATION_XMPP"; 157 case NOTIFICATION_POLLING: 158 return "NOTIFICATION_POLLING"; 159 } 160 161 NOTREACHED(); 162 return ""; 163 } 164 165 } // namespace drive 166