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/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"
18 namespace keys = extensions::idle_api_constants;
19 namespace idle = extensions::api::idle;
21 namespace extensions {
25 const int kDefaultIdleThreshold = 60;
26 const int kPollInterval = 1;
28 class DefaultEventDelegate : public IdleManager::EventDelegate {
30 explicit DefaultEventDelegate(Profile* profile);
31 ~DefaultEventDelegate() override;
33 void OnStateChanged(const std::string& extension_id,
34 IdleState new_state) override;
35 void RegisterObserver(EventRouter::Observer* observer) override;
36 void UnregisterObserver(EventRouter::Observer* observer) override;
42 DefaultEventDelegate::DefaultEventDelegate(Profile* profile)
46 DefaultEventDelegate::~DefaultEventDelegate() {
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,
55 event->restrict_to_browser_context = profile_;
56 EventRouter::Get(profile_)
57 ->DispatchEventToExtension(extension_id, event.Pass());
60 void DefaultEventDelegate::RegisterObserver(
61 EventRouter::Observer* observer) {
62 EventRouter::Get(profile_)
63 ->RegisterObserver(observer, idle::OnStateChanged::kEventName);
66 void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer* observer) {
67 EventRouter::Get(profile_)->UnregisterObserver(observer);
70 class DefaultIdleProvider : public IdleManager::IdleTimeProvider {
72 DefaultIdleProvider();
73 ~DefaultIdleProvider() override;
75 void CalculateIdleState(int idle_threshold, IdleCallback notify) override;
76 void CalculateIdleTime(IdleTimeCallback notify) override;
77 bool CheckIdleStateIsLocked() override;
80 DefaultIdleProvider::DefaultIdleProvider() {
83 DefaultIdleProvider::~DefaultIdleProvider() {
86 void DefaultIdleProvider::CalculateIdleState(int idle_threshold,
87 IdleCallback notify) {
88 ::CalculateIdleState(idle_threshold, notify);
91 void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
92 ::CalculateIdleTime(notify);
95 bool DefaultIdleProvider::CheckIdleStateIsLocked() {
96 return ::CheckIdleStateIsLocked();
99 IdleState IdleTimeToIdleState(bool locked, int idle_time, int idle_threshold) {
103 state = IDLE_STATE_LOCKED;
104 } else if (idle_time >= idle_threshold) {
105 state = IDLE_STATE_IDLE;
107 state = IDLE_STATE_ACTIVE;
114 IdleMonitor::IdleMonitor(IdleState initial_state)
115 : last_state(initial_state),
117 threshold(kDefaultIdleThreshold) {
120 IdleManager::IdleManager(Profile* profile)
122 last_state_(IDLE_STATE_ACTIVE),
123 idle_time_provider_(new DefaultIdleProvider()),
124 event_delegate_(new DefaultEventDelegate(profile)),
125 extension_registry_observer_(this),
126 weak_factory_(this) {
129 IdleManager::~IdleManager() {
132 void IdleManager::Init() {
133 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
134 event_delegate_->RegisterObserver(this);
137 void IdleManager::Shutdown() {
138 DCHECK(thread_checker_.CalledOnValidThread());
139 event_delegate_->UnregisterObserver(this);
142 void IdleManager::OnExtensionUnloaded(content::BrowserContext* browser_context,
143 const Extension* extension,
144 UnloadedExtensionInfo::Reason reason) {
145 DCHECK(thread_checker_.CalledOnValidThread());
146 monitors_.erase(extension->id());
149 void IdleManager::OnListenerAdded(const EventListenerInfo& details) {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 ++GetMonitor(details.extension_id)->listeners;
156 void IdleManager::OnListenerRemoved(const EventListenerInfo& details) {
157 DCHECK(thread_checker_.CalledOnValidThread());
159 // During unload the monitor could already have been deleted. No need to do
160 // anything in that case.
161 MonitorMap::iterator it = monitors_.find(details.extension_id);
162 if (it != monitors_.end()) {
163 DCHECK_GT(it->second.listeners, 0);
164 // Note: Deliberately leave the listener count as 0 rather than erase()ing
165 // this record so that the threshold doesn't get reset when all listeners
167 --it->second.listeners;
171 void IdleManager::QueryState(int threshold, QueryStateCallback notify) {
172 DCHECK(thread_checker_.CalledOnValidThread());
173 idle_time_provider_->CalculateIdleState(threshold, notify);
176 void IdleManager::SetThreshold(const std::string& extension_id,
178 DCHECK(thread_checker_.CalledOnValidThread());
179 GetMonitor(extension_id)->threshold = threshold;
183 base::StringValue* IdleManager::CreateIdleValue(IdleState idle_state) {
184 const char* description;
186 if (idle_state == IDLE_STATE_ACTIVE) {
187 description = keys::kStateActive;
188 } else if (idle_state == IDLE_STATE_IDLE) {
189 description = keys::kStateIdle;
191 description = keys::kStateLocked;
194 return new base::StringValue(description);
197 void IdleManager::SetEventDelegateForTest(
198 scoped_ptr<EventDelegate> event_delegate) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 event_delegate_ = event_delegate.Pass();
203 void IdleManager::SetIdleTimeProviderForTest(
204 scoped_ptr<IdleTimeProvider> idle_time_provider) {
205 DCHECK(thread_checker_.CalledOnValidThread());
206 idle_time_provider_ = idle_time_provider.Pass();
209 IdleMonitor* IdleManager::GetMonitor(const std::string& extension_id) {
210 DCHECK(thread_checker_.CalledOnValidThread());
211 MonitorMap::iterator it = monitors_.find(extension_id);
213 if (it == monitors_.end()) {
214 it = monitors_.insert(std::make_pair(extension_id,
215 IdleMonitor(last_state_))).first;
220 void IdleManager::StartPolling() {
221 DCHECK(thread_checker_.CalledOnValidThread());
222 if (!poll_timer_.IsRunning()) {
223 poll_timer_.Start(FROM_HERE,
224 base::TimeDelta::FromSeconds(kPollInterval),
226 &IdleManager::UpdateIdleState);
230 void IdleManager::StopPolling() {
231 DCHECK(thread_checker_.CalledOnValidThread());
235 void IdleManager::UpdateIdleState() {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 idle_time_provider_->CalculateIdleTime(
239 &IdleManager::UpdateIdleStateCallback,
240 weak_factory_.GetWeakPtr()));
243 void IdleManager::UpdateIdleStateCallback(int idle_time) {
244 DCHECK(thread_checker_.CalledOnValidThread());
245 bool locked = idle_time_provider_->CheckIdleStateIsLocked();
246 int listener_count = 0;
248 // Remember this state for initializing new event listeners.
249 last_state_ = IdleTimeToIdleState(locked,
251 kDefaultIdleThreshold);
253 for (MonitorMap::iterator it = monitors_.begin();
254 it != monitors_.end(); ++it) {
255 IdleMonitor& monitor = it->second;
256 IdleState new_state =
257 IdleTimeToIdleState(locked, idle_time, monitor.threshold);
258 // TODO(kalman): Use EventRouter::HasListeners for these sorts of checks.
259 if (monitor.listeners > 0 && monitor.last_state != new_state)
260 event_delegate_->OnStateChanged(it->first, new_state);
261 monitor.last_state = new_state;
262 listener_count += monitor.listeners;
265 if (listener_count == 0)
269 } // namespace extensions