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