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.
5 #include "chrome/browser/extensions/api/idle/idle_manager.h"
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/profiles/profile.h"
13 #include "chrome/common/extensions/api/idle.h"
14 #include "chrome/common/extensions/extension_constants.h"
15 #include "content/public/browser/notification_details.h"
16 #include "content/public/browser/notification_source.h"
17 #include "extensions/browser/event_router.h"
18 #include "extensions/browser/extension_system.h"
19 #include "extensions/common/extension.h"
21 namespace keys = extensions::idle_api_constants;
22 namespace idle = extensions::api::idle;
24 namespace extensions {
28 const int kDefaultIdleThreshold = 60;
29 const int kPollInterval = 1;
31 class DefaultEventDelegate : public IdleManager::EventDelegate {
33 explicit DefaultEventDelegate(Profile* profile);
34 virtual ~DefaultEventDelegate();
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;
45 DefaultEventDelegate::DefaultEventDelegate(Profile* profile)
49 DefaultEventDelegate::~DefaultEventDelegate() {
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,
58 event->restrict_to_browser_context = profile_;
59 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
60 extension_id, event.Pass());
63 void DefaultEventDelegate::RegisterObserver(
64 EventRouter::Observer* observer) {
65 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
66 observer, idle::OnStateChanged::kEventName);
69 void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer* observer) {
70 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(observer);
74 class DefaultIdleProvider : public IdleManager::IdleTimeProvider {
76 DefaultIdleProvider();
77 virtual ~DefaultIdleProvider();
79 virtual void CalculateIdleState(int idle_threshold,
80 IdleCallback notify) OVERRIDE;
81 virtual void CalculateIdleTime(IdleTimeCallback notify) OVERRIDE;
82 virtual bool CheckIdleStateIsLocked() OVERRIDE;
85 DefaultIdleProvider::DefaultIdleProvider() {
88 DefaultIdleProvider::~DefaultIdleProvider() {
91 void DefaultIdleProvider::CalculateIdleState(int idle_threshold,
92 IdleCallback notify) {
93 ::CalculateIdleState(idle_threshold, notify);
96 void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
97 ::CalculateIdleTime(notify);
100 bool DefaultIdleProvider::CheckIdleStateIsLocked() {
101 return ::CheckIdleStateIsLocked();
104 IdleState IdleTimeToIdleState(bool locked, int idle_time, int idle_threshold) {
108 state = IDLE_STATE_LOCKED;
109 } else if (idle_time >= idle_threshold) {
110 state = IDLE_STATE_IDLE;
112 state = IDLE_STATE_ACTIVE;
119 IdleMonitor::IdleMonitor(IdleState initial_state)
120 : last_state(initial_state),
122 threshold(kDefaultIdleThreshold) {
125 IdleManager::IdleManager(Profile* profile)
127 last_state_(IDLE_STATE_ACTIVE),
129 idle_time_provider_(new DefaultIdleProvider()),
130 event_delegate_(new DefaultEventDelegate(profile)) {
133 IdleManager::~IdleManager() {
136 void IdleManager::Init() {
137 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
138 content::Source<Profile>(profile_->GetOriginalProfile()));
139 event_delegate_->RegisterObserver(this);
142 void IdleManager::Shutdown() {
143 DCHECK(thread_checker_.CalledOnValidThread());
144 event_delegate_->UnregisterObserver(this);
147 void IdleManager::Observe(int type,
148 const content::NotificationSource& source,
149 const content::NotificationDetails& details) {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
153 const Extension* extension =
154 content::Details<extensions::UnloadedExtensionInfo>(details)->extension;
155 monitors_.erase(extension->id());
161 void IdleManager::OnListenerAdded(const EventListenerInfo& details) {
162 DCHECK(thread_checker_.CalledOnValidThread());
164 ++GetMonitor(details.extension_id)->listeners;
168 void IdleManager::OnListenerRemoved(const EventListenerInfo& details) {
169 DCHECK(thread_checker_.CalledOnValidThread());
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;
180 void IdleManager::QueryState(int threshold, QueryStateCallback notify) {
181 DCHECK(thread_checker_.CalledOnValidThread());
182 idle_time_provider_->CalculateIdleState(threshold, notify);
185 void IdleManager::SetThreshold(const std::string& extension_id,
187 DCHECK(thread_checker_.CalledOnValidThread());
188 GetMonitor(extension_id)->threshold = threshold;
192 base::StringValue* IdleManager::CreateIdleValue(IdleState idle_state) {
193 const char* description;
195 if (idle_state == IDLE_STATE_ACTIVE) {
196 description = keys::kStateActive;
197 } else if (idle_state == IDLE_STATE_IDLE) {
198 description = keys::kStateIdle;
200 description = keys::kStateLocked;
203 return new base::StringValue(description);
206 void IdleManager::SetEventDelegateForTest(
207 scoped_ptr<EventDelegate> event_delegate) {
208 DCHECK(thread_checker_.CalledOnValidThread());
209 event_delegate_ = event_delegate.Pass();
212 void IdleManager::SetIdleTimeProviderForTest(
213 scoped_ptr<IdleTimeProvider> idle_time_provider) {
214 DCHECK(thread_checker_.CalledOnValidThread());
215 idle_time_provider_ = idle_time_provider.Pass();
218 IdleMonitor* IdleManager::GetMonitor(const std::string& extension_id) {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 MonitorMap::iterator it = monitors_.find(extension_id);
222 if (it == monitors_.end()) {
223 it = monitors_.insert(std::make_pair(extension_id,
224 IdleMonitor(last_state_))).first;
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),
235 &IdleManager::UpdateIdleState);
239 void IdleManager::StopPolling() {
240 DCHECK(thread_checker_.CalledOnValidThread());
244 void IdleManager::UpdateIdleState() {
245 DCHECK(thread_checker_.CalledOnValidThread());
246 idle_time_provider_->CalculateIdleTime(
248 &IdleManager::UpdateIdleStateCallback,
249 weak_factory_.GetWeakPtr()));
252 void IdleManager::UpdateIdleStateCallback(int idle_time) {
253 DCHECK(thread_checker_.CalledOnValidThread());
254 bool locked = idle_time_provider_->CheckIdleStateIsLocked();
255 int listener_count = 0;
257 // Remember this state for initializing new event listeners.
258 last_state_ = IdleTimeToIdleState(locked,
260 kDefaultIdleThreshold);
262 for (MonitorMap::iterator it = monitors_.begin();
263 it != monitors_.end(); ++it) {
264 if (it->second.listeners < 1)
269 IdleState new_state = IdleTimeToIdleState(locked,
271 it->second.threshold);
273 if (new_state != it->second.last_state) {
274 it->second.last_state = new_state;
275 event_delegate_->OnStateChanged(it->first, new_state);
279 if (listener_count == 0) {
284 } // namespace extensions