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
DefaultEventDelegate(Profile * profile)42 DefaultEventDelegate::DefaultEventDelegate(Profile* profile)
43 : profile_(profile) {
44 }
45
~DefaultEventDelegate()46 DefaultEventDelegate::~DefaultEventDelegate() {
47 }
48
OnStateChanged(const std::string & extension_id,IdleState new_state)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
RegisterObserver(EventRouter::Observer * observer)60 void DefaultEventDelegate::RegisterObserver(
61 EventRouter::Observer* observer) {
62 EventRouter::Get(profile_)
63 ->RegisterObserver(observer, idle::OnStateChanged::kEventName);
64 }
65
UnregisterObserver(EventRouter::Observer * observer)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
DefaultIdleProvider()81 DefaultIdleProvider::DefaultIdleProvider() {
82 }
83
~DefaultIdleProvider()84 DefaultIdleProvider::~DefaultIdleProvider() {
85 }
86
CalculateIdleState(int idle_threshold,IdleCallback notify)87 void DefaultIdleProvider::CalculateIdleState(int idle_threshold,
88 IdleCallback notify) {
89 ::CalculateIdleState(idle_threshold, notify);
90 }
91
CalculateIdleTime(IdleTimeCallback notify)92 void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
93 ::CalculateIdleTime(notify);
94 }
95
CheckIdleStateIsLocked()96 bool DefaultIdleProvider::CheckIdleStateIsLocked() {
97 return ::CheckIdleStateIsLocked();
98 }
99
IdleTimeToIdleState(bool locked,int idle_time,int idle_threshold)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
IdleMonitor(IdleState initial_state)115 IdleMonitor::IdleMonitor(IdleState initial_state)
116 : last_state(initial_state),
117 listeners(0),
118 threshold(kDefaultIdleThreshold) {
119 }
120
IdleManager(Profile * profile)121 IdleManager::IdleManager(Profile* profile)
122 : profile_(profile),
123 last_state_(IDLE_STATE_ACTIVE),
124 weak_factory_(this),
125 idle_time_provider_(new DefaultIdleProvider()),
126 event_delegate_(new DefaultEventDelegate(profile)),
127 extension_registry_observer_(this) {
128 }
129
~IdleManager()130 IdleManager::~IdleManager() {
131 }
132
Init()133 void IdleManager::Init() {
134 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
135 event_delegate_->RegisterObserver(this);
136 }
137
Shutdown()138 void IdleManager::Shutdown() {
139 DCHECK(thread_checker_.CalledOnValidThread());
140 event_delegate_->UnregisterObserver(this);
141 }
142
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)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
OnListenerAdded(const EventListenerInfo & details)150 void IdleManager::OnListenerAdded(const EventListenerInfo& details) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152
153 ++GetMonitor(details.extension_id)->listeners;
154 StartPolling();
155 }
156
OnListenerRemoved(const EventListenerInfo & details)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
QueryState(int threshold,QueryStateCallback notify)172 void IdleManager::QueryState(int threshold, QueryStateCallback notify) {
173 DCHECK(thread_checker_.CalledOnValidThread());
174 idle_time_provider_->CalculateIdleState(threshold, notify);
175 }
176
SetThreshold(const std::string & extension_id,int threshold)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
CreateIdleValue(IdleState idle_state)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
SetEventDelegateForTest(scoped_ptr<EventDelegate> event_delegate)198 void IdleManager::SetEventDelegateForTest(
199 scoped_ptr<EventDelegate> event_delegate) {
200 DCHECK(thread_checker_.CalledOnValidThread());
201 event_delegate_ = event_delegate.Pass();
202 }
203
SetIdleTimeProviderForTest(scoped_ptr<IdleTimeProvider> idle_time_provider)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
GetMonitor(const std::string & extension_id)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
StartPolling()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
StopPolling()231 void IdleManager::StopPolling() {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 poll_timer_.Stop();
234 }
235
UpdateIdleState()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
UpdateIdleStateCallback(int idle_time)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