1 // Copyright (c) 2012 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/extensions/api/idle/idle_manager.h" 6 7 #include <utility> 8 9 #include "base/stl_util.h" 10 #include "chrome/browser/extensions/api/idle/idle_api_constants.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/common/extensions/api/idle.h" 13 #include "chrome/common/extensions/extension_constants.h" 14 #include "extensions/browser/event_router.h" 15 #include "extensions/browser/extension_registry.h" 16 #include "extensions/common/extension.h" 17 18 namespace keys = extensions::idle_api_constants; 19 namespace idle = extensions::api::idle; 20 21 namespace extensions { 22 23 namespace { 24 25 const int kDefaultIdleThreshold = 60; 26 const int kPollInterval = 1; 27 28 class DefaultEventDelegate : public IdleManager::EventDelegate { 29 public: 30 explicit DefaultEventDelegate(Profile* profile); 31 virtual ~DefaultEventDelegate(); 32 33 virtual void OnStateChanged(const std::string& extension_id, 34 IdleState new_state) OVERRIDE; 35 virtual void RegisterObserver(EventRouter::Observer* observer) OVERRIDE; 36 virtual void UnregisterObserver(EventRouter::Observer* observer) OVERRIDE; 37 38 private: 39 Profile* profile_; 40 }; 41 42 DefaultEventDelegate::DefaultEventDelegate(Profile* profile) 43 : profile_(profile) { 44 } 45 46 DefaultEventDelegate::~DefaultEventDelegate() { 47 } 48 49 void DefaultEventDelegate::OnStateChanged(const std::string& extension_id, 50 IdleState new_state) { 51 scoped_ptr<base::ListValue> args(new base::ListValue()); 52 args->Append(IdleManager::CreateIdleValue(new_state)); 53 scoped_ptr<Event> event(new Event(idle::OnStateChanged::kEventName, 54 args.Pass())); 55 event->restrict_to_browser_context = profile_; 56 EventRouter::Get(profile_) 57 ->DispatchEventToExtension(extension_id, event.Pass()); 58 } 59 60 void DefaultEventDelegate::RegisterObserver( 61 EventRouter::Observer* observer) { 62 EventRouter::Get(profile_) 63 ->RegisterObserver(observer, idle::OnStateChanged::kEventName); 64 } 65 66 void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer* observer) { 67 EventRouter::Get(profile_)->UnregisterObserver(observer); 68 } 69 70 class DefaultIdleProvider : public IdleManager::IdleTimeProvider { 71 public: 72 DefaultIdleProvider(); 73 virtual ~DefaultIdleProvider(); 74 75 virtual void CalculateIdleState(int idle_threshold, 76 IdleCallback notify) OVERRIDE; 77 virtual void CalculateIdleTime(IdleTimeCallback notify) OVERRIDE; 78 virtual bool CheckIdleStateIsLocked() OVERRIDE; 79 }; 80 81 DefaultIdleProvider::DefaultIdleProvider() { 82 } 83 84 DefaultIdleProvider::~DefaultIdleProvider() { 85 } 86 87 void DefaultIdleProvider::CalculateIdleState(int idle_threshold, 88 IdleCallback notify) { 89 ::CalculateIdleState(idle_threshold, notify); 90 } 91 92 void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) { 93 ::CalculateIdleTime(notify); 94 } 95 96 bool DefaultIdleProvider::CheckIdleStateIsLocked() { 97 return ::CheckIdleStateIsLocked(); 98 } 99 100 IdleState IdleTimeToIdleState(bool locked, int idle_time, int idle_threshold) { 101 IdleState state; 102 103 if (locked) { 104 state = IDLE_STATE_LOCKED; 105 } else if (idle_time >= idle_threshold) { 106 state = IDLE_STATE_IDLE; 107 } else { 108 state = IDLE_STATE_ACTIVE; 109 } 110 return state; 111 } 112 113 } // namespace 114 115 IdleMonitor::IdleMonitor(IdleState initial_state) 116 : last_state(initial_state), 117 listeners(0), 118 threshold(kDefaultIdleThreshold) { 119 } 120 121 IdleManager::IdleManager(Profile* profile) 122 : profile_(profile), 123 last_state_(IDLE_STATE_ACTIVE), 124 idle_time_provider_(new DefaultIdleProvider()), 125 event_delegate_(new DefaultEventDelegate(profile)), 126 extension_registry_observer_(this), 127 weak_factory_(this) { 128 } 129 130 IdleManager::~IdleManager() { 131 } 132 133 void IdleManager::Init() { 134 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 135 event_delegate_->RegisterObserver(this); 136 } 137 138 void IdleManager::Shutdown() { 139 DCHECK(thread_checker_.CalledOnValidThread()); 140 event_delegate_->UnregisterObserver(this); 141 } 142 143 void IdleManager::OnExtensionUnloaded(content::BrowserContext* browser_context, 144 const Extension* extension, 145 UnloadedExtensionInfo::Reason reason) { 146 DCHECK(thread_checker_.CalledOnValidThread()); 147 monitors_.erase(extension->id()); 148 } 149 150 void IdleManager::OnListenerAdded(const EventListenerInfo& details) { 151 DCHECK(thread_checker_.CalledOnValidThread()); 152 153 ++GetMonitor(details.extension_id)->listeners; 154 StartPolling(); 155 } 156 157 void IdleManager::OnListenerRemoved(const EventListenerInfo& details) { 158 DCHECK(thread_checker_.CalledOnValidThread()); 159 160 // During unload the monitor could already have been deleted. No need to do 161 // anything in that case. 162 MonitorMap::iterator it = monitors_.find(details.extension_id); 163 if (it != monitors_.end()) { 164 DCHECK_GT(it->second.listeners, 0); 165 // Note: Deliberately leave the listener count as 0 rather than erase()ing 166 // this record so that the threshold doesn't get reset when all listeners 167 // are removed. 168 --it->second.listeners; 169 } 170 } 171 172 void IdleManager::QueryState(int threshold, QueryStateCallback notify) { 173 DCHECK(thread_checker_.CalledOnValidThread()); 174 idle_time_provider_->CalculateIdleState(threshold, notify); 175 } 176 177 void IdleManager::SetThreshold(const std::string& extension_id, 178 int threshold) { 179 DCHECK(thread_checker_.CalledOnValidThread()); 180 GetMonitor(extension_id)->threshold = threshold; 181 } 182 183 // static 184 base::StringValue* IdleManager::CreateIdleValue(IdleState idle_state) { 185 const char* description; 186 187 if (idle_state == IDLE_STATE_ACTIVE) { 188 description = keys::kStateActive; 189 } else if (idle_state == IDLE_STATE_IDLE) { 190 description = keys::kStateIdle; 191 } else { 192 description = keys::kStateLocked; 193 } 194 195 return new base::StringValue(description); 196 } 197 198 void IdleManager::SetEventDelegateForTest( 199 scoped_ptr<EventDelegate> event_delegate) { 200 DCHECK(thread_checker_.CalledOnValidThread()); 201 event_delegate_ = event_delegate.Pass(); 202 } 203 204 void IdleManager::SetIdleTimeProviderForTest( 205 scoped_ptr<IdleTimeProvider> idle_time_provider) { 206 DCHECK(thread_checker_.CalledOnValidThread()); 207 idle_time_provider_ = idle_time_provider.Pass(); 208 } 209 210 IdleMonitor* IdleManager::GetMonitor(const std::string& extension_id) { 211 DCHECK(thread_checker_.CalledOnValidThread()); 212 MonitorMap::iterator it = monitors_.find(extension_id); 213 214 if (it == monitors_.end()) { 215 it = monitors_.insert(std::make_pair(extension_id, 216 IdleMonitor(last_state_))).first; 217 } 218 return &it->second; 219 } 220 221 void IdleManager::StartPolling() { 222 DCHECK(thread_checker_.CalledOnValidThread()); 223 if (!poll_timer_.IsRunning()) { 224 poll_timer_.Start(FROM_HERE, 225 base::TimeDelta::FromSeconds(kPollInterval), 226 this, 227 &IdleManager::UpdateIdleState); 228 } 229 } 230 231 void IdleManager::StopPolling() { 232 DCHECK(thread_checker_.CalledOnValidThread()); 233 poll_timer_.Stop(); 234 } 235 236 void IdleManager::UpdateIdleState() { 237 DCHECK(thread_checker_.CalledOnValidThread()); 238 idle_time_provider_->CalculateIdleTime( 239 base::Bind( 240 &IdleManager::UpdateIdleStateCallback, 241 weak_factory_.GetWeakPtr())); 242 } 243 244 void IdleManager::UpdateIdleStateCallback(int idle_time) { 245 DCHECK(thread_checker_.CalledOnValidThread()); 246 bool locked = idle_time_provider_->CheckIdleStateIsLocked(); 247 int listener_count = 0; 248 249 // Remember this state for initializing new event listeners. 250 last_state_ = IdleTimeToIdleState(locked, 251 idle_time, 252 kDefaultIdleThreshold); 253 254 for (MonitorMap::iterator it = monitors_.begin(); 255 it != monitors_.end(); ++it) { 256 IdleMonitor& monitor = it->second; 257 IdleState new_state = 258 IdleTimeToIdleState(locked, idle_time, monitor.threshold); 259 // TODO(kalman): Use EventRouter::HasListeners for these sorts of checks. 260 if (monitor.listeners > 0 && monitor.last_state != new_state) 261 event_delegate_->OnStateChanged(it->first, new_state); 262 monitor.last_state = new_state; 263 listener_count += monitor.listeners; 264 } 265 266 if (listener_count == 0) 267 StopPolling(); 268 } 269 270 } // namespace extensions 271