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