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