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 "extensions/browser/api/idle/idle_manager.h"
9 #include "base/stl_util.h"
10 #include "content/public/browser/browser_context.h"
11 #include "extensions/browser/api/idle/idle_api_constants.h"
12 #include "extensions/browser/event_router.h"
13 #include "extensions/browser/extension_registry.h"
14 #include "extensions/common/api/idle.h"
15 #include "extensions/common/extension.h"
17 namespace keys
= extensions::idle_api_constants
;
18 namespace idle
= extensions::core_api::idle
;
20 namespace extensions
{
24 const int kDefaultIdleThreshold
= 60;
25 const int kPollInterval
= 1;
27 class DefaultEventDelegate
: public IdleManager::EventDelegate
{
29 explicit DefaultEventDelegate(content::BrowserContext
* context
);
30 ~DefaultEventDelegate() override
;
32 void OnStateChanged(const std::string
& extension_id
,
33 ui::IdleState new_state
) override
;
34 void RegisterObserver(EventRouter::Observer
* observer
) override
;
35 void UnregisterObserver(EventRouter::Observer
* observer
) override
;
38 content::BrowserContext
* const context_
;
41 DefaultEventDelegate::DefaultEventDelegate(content::BrowserContext
* context
)
45 DefaultEventDelegate::~DefaultEventDelegate() {
48 void DefaultEventDelegate::OnStateChanged(const std::string
& extension_id
,
49 ui::IdleState new_state
) {
50 scoped_ptr
<base::ListValue
> args(new base::ListValue());
51 args
->Append(IdleManager::CreateIdleValue(new_state
));
52 scoped_ptr
<Event
> event(
53 new Event(idle::OnStateChanged::kEventName
, args
.Pass()));
54 event
->restrict_to_browser_context
= context_
;
55 EventRouter::Get(context_
)
56 ->DispatchEventToExtension(extension_id
, event
.Pass());
59 void DefaultEventDelegate::RegisterObserver(EventRouter::Observer
* observer
) {
60 EventRouter::Get(context_
)
61 ->RegisterObserver(observer
, idle::OnStateChanged::kEventName
);
64 void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer
* observer
) {
65 EventRouter::Get(context_
)->UnregisterObserver(observer
);
68 class DefaultIdleProvider
: public IdleManager::IdleTimeProvider
{
70 DefaultIdleProvider();
71 ~DefaultIdleProvider() override
;
73 void CalculateIdleState(int idle_threshold
, ui::IdleCallback notify
) override
;
74 void CalculateIdleTime(ui::IdleTimeCallback notify
) override
;
75 bool CheckIdleStateIsLocked() override
;
78 DefaultIdleProvider::DefaultIdleProvider() {
81 DefaultIdleProvider::~DefaultIdleProvider() {
84 void DefaultIdleProvider::CalculateIdleState(int idle_threshold
,
85 ui::IdleCallback notify
) {
86 ui::CalculateIdleState(idle_threshold
, notify
);
89 void DefaultIdleProvider::CalculateIdleTime(ui::IdleTimeCallback notify
) {
90 ui::CalculateIdleTime(notify
);
93 bool DefaultIdleProvider::CheckIdleStateIsLocked() {
94 return ui::CheckIdleStateIsLocked();
97 ui::IdleState
IdleTimeToIdleState(bool locked
,
103 state
= ui::IDLE_STATE_LOCKED
;
104 } else if (idle_time
>= idle_threshold
) {
105 state
= ui::IDLE_STATE_IDLE
;
107 state
= ui::IDLE_STATE_ACTIVE
;
114 IdleMonitor::IdleMonitor(ui::IdleState initial_state
)
115 : last_state(initial_state
),
117 threshold(kDefaultIdleThreshold
) {
120 IdleManager::IdleManager(content::BrowserContext
* context
)
122 last_state_(ui::IDLE_STATE_ACTIVE
),
123 idle_time_provider_(new DefaultIdleProvider()),
124 event_delegate_(new DefaultEventDelegate(context
)),
125 extension_registry_observer_(this),
126 weak_factory_(this) {
129 IdleManager::~IdleManager() {
132 void IdleManager::Init() {
133 extension_registry_observer_
.Add(ExtensionRegistry::Get(context_
));
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
, int threshold
) {
177 DCHECK(thread_checker_
.CalledOnValidThread());
178 GetMonitor(extension_id
)->threshold
= threshold
;
182 base::StringValue
* IdleManager::CreateIdleValue(ui::IdleState idle_state
) {
183 const char* description
;
185 if (idle_state
== ui::IDLE_STATE_ACTIVE
) {
186 description
= keys::kStateActive
;
187 } else if (idle_state
== ui::IDLE_STATE_IDLE
) {
188 description
= keys::kStateIdle
;
190 description
= keys::kStateLocked
;
193 return new base::StringValue(description
);
196 void IdleManager::SetEventDelegateForTest(
197 scoped_ptr
<EventDelegate
> event_delegate
) {
198 DCHECK(thread_checker_
.CalledOnValidThread());
199 event_delegate_
= event_delegate
.Pass();
202 void IdleManager::SetIdleTimeProviderForTest(
203 scoped_ptr
<IdleTimeProvider
> idle_time_provider
) {
204 DCHECK(thread_checker_
.CalledOnValidThread());
205 idle_time_provider_
= idle_time_provider
.Pass();
208 IdleMonitor
* IdleManager::GetMonitor(const std::string
& extension_id
) {
209 DCHECK(thread_checker_
.CalledOnValidThread());
210 MonitorMap::iterator it
= monitors_
.find(extension_id
);
212 if (it
== monitors_
.end()) {
213 it
= monitors_
.insert(std::make_pair(extension_id
,
214 IdleMonitor(last_state_
))).first
;
219 void IdleManager::StartPolling() {
220 DCHECK(thread_checker_
.CalledOnValidThread());
221 if (!poll_timer_
.IsRunning()) {
222 poll_timer_
.Start(FROM_HERE
, base::TimeDelta::FromSeconds(kPollInterval
),
223 this, &IdleManager::UpdateIdleState
);
227 void IdleManager::StopPolling() {
228 DCHECK(thread_checker_
.CalledOnValidThread());
232 void IdleManager::UpdateIdleState() {
233 DCHECK(thread_checker_
.CalledOnValidThread());
234 idle_time_provider_
->CalculateIdleTime(base::Bind(
235 &IdleManager::UpdateIdleStateCallback
, weak_factory_
.GetWeakPtr()));
238 void IdleManager::UpdateIdleStateCallback(int idle_time
) {
239 DCHECK(thread_checker_
.CalledOnValidThread());
240 bool locked
= idle_time_provider_
->CheckIdleStateIsLocked();
241 int listener_count
= 0;
243 // Remember this state for initializing new event listeners.
244 last_state_
= IdleTimeToIdleState(locked
, idle_time
, kDefaultIdleThreshold
);
246 for (MonitorMap::iterator it
= monitors_
.begin(); it
!= monitors_
.end();
248 IdleMonitor
& monitor
= it
->second
;
249 ui::IdleState new_state
=
250 IdleTimeToIdleState(locked
, idle_time
, monitor
.threshold
);
251 // TODO(kalman): Use EventRouter::HasListeners for these sorts of checks.
252 if (monitor
.listeners
> 0 && monitor
.last_state
!= new_state
)
253 event_delegate_
->OnStateChanged(it
->first
, new_state
);
254 monitor
.last_state
= new_state
;
255 listener_count
+= monitor
.listeners
;
258 if (listener_count
== 0)
262 } // namespace extensions