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 18namespace keys = extensions::idle_api_constants; 19namespace idle = extensions::api::idle; 20 21namespace extensions { 22 23namespace { 24 25const int kDefaultIdleThreshold = 60; 26const int kPollInterval = 1; 27 28class 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 42DefaultEventDelegate::DefaultEventDelegate(Profile* profile) 43 : profile_(profile) { 44} 45 46DefaultEventDelegate::~DefaultEventDelegate() { 47} 48 49void 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 60void DefaultEventDelegate::RegisterObserver( 61 EventRouter::Observer* observer) { 62 EventRouter::Get(profile_) 63 ->RegisterObserver(observer, idle::OnStateChanged::kEventName); 64} 65 66void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer* observer) { 67 EventRouter::Get(profile_)->UnregisterObserver(observer); 68} 69 70class 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 81DefaultIdleProvider::DefaultIdleProvider() { 82} 83 84DefaultIdleProvider::~DefaultIdleProvider() { 85} 86 87void DefaultIdleProvider::CalculateIdleState(int idle_threshold, 88 IdleCallback notify) { 89 ::CalculateIdleState(idle_threshold, notify); 90} 91 92void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) { 93 ::CalculateIdleTime(notify); 94} 95 96bool DefaultIdleProvider::CheckIdleStateIsLocked() { 97 return ::CheckIdleStateIsLocked(); 98} 99 100IdleState 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 115IdleMonitor::IdleMonitor(IdleState initial_state) 116 : last_state(initial_state), 117 listeners(0), 118 threshold(kDefaultIdleThreshold) { 119} 120 121IdleManager::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 130IdleManager::~IdleManager() { 131} 132 133void IdleManager::Init() { 134 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 135 event_delegate_->RegisterObserver(this); 136} 137 138void IdleManager::Shutdown() { 139 DCHECK(thread_checker_.CalledOnValidThread()); 140 event_delegate_->UnregisterObserver(this); 141} 142 143void 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 150void IdleManager::OnListenerAdded(const EventListenerInfo& details) { 151 DCHECK(thread_checker_.CalledOnValidThread()); 152 153 ++GetMonitor(details.extension_id)->listeners; 154 StartPolling(); 155} 156 157void 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 172void IdleManager::QueryState(int threshold, QueryStateCallback notify) { 173 DCHECK(thread_checker_.CalledOnValidThread()); 174 idle_time_provider_->CalculateIdleState(threshold, notify); 175} 176 177void 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 184base::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 198void IdleManager::SetEventDelegateForTest( 199 scoped_ptr<EventDelegate> event_delegate) { 200 DCHECK(thread_checker_.CalledOnValidThread()); 201 event_delegate_ = event_delegate.Pass(); 202} 203 204void IdleManager::SetIdleTimeProviderForTest( 205 scoped_ptr<IdleTimeProvider> idle_time_provider) { 206 DCHECK(thread_checker_.CalledOnValidThread()); 207 idle_time_provider_ = idle_time_provider.Pass(); 208} 209 210IdleMonitor* 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 221void 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 231void IdleManager::StopPolling() { 232 DCHECK(thread_checker_.CalledOnValidThread()); 233 poll_timer_.Stop(); 234} 235 236void IdleManager::UpdateIdleState() { 237 DCHECK(thread_checker_.CalledOnValidThread()); 238 idle_time_provider_->CalculateIdleTime( 239 base::Bind( 240 &IdleManager::UpdateIdleStateCallback, 241 weak_factory_.GetWeakPtr())); 242} 243 244void 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