Home | History | Annotate | Download | only in idle
      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 
     45 DefaultEventDelegate::DefaultEventDelegate(Profile* profile)
     46     : profile_(profile) {
     47 }
     48 
     49 DefaultEventDelegate::~DefaultEventDelegate() {
     50 }
     51 
     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 
     63 void DefaultEventDelegate::RegisterObserver(
     64     EventRouter::Observer* observer) {
     65   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
     66       observer, idle::OnStateChanged::kEventName);
     67 }
     68 
     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 
     85 DefaultIdleProvider::DefaultIdleProvider() {
     86 }
     87 
     88 DefaultIdleProvider::~DefaultIdleProvider() {
     89 }
     90 
     91 void DefaultIdleProvider::CalculateIdleState(int idle_threshold,
     92                                              IdleCallback notify) {
     93   ::CalculateIdleState(idle_threshold, notify);
     94 }
     95 
     96 void DefaultIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
     97   ::CalculateIdleTime(notify);
     98 }
     99 
    100 bool DefaultIdleProvider::CheckIdleStateIsLocked() {
    101   return ::CheckIdleStateIsLocked();
    102 }
    103 
    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 
    119 IdleMonitor::IdleMonitor(IdleState initial_state)
    120     : last_state(initial_state),
    121       listeners(0),
    122       threshold(kDefaultIdleThreshold) {
    123 }
    124 
    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 
    133 IdleManager::~IdleManager() {
    134 }
    135 
    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 
    142 void IdleManager::Shutdown() {
    143   DCHECK(thread_checker_.CalledOnValidThread());
    144   event_delegate_->UnregisterObserver(this);
    145 }
    146 
    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 
    161 void IdleManager::OnListenerAdded(const EventListenerInfo& details) {
    162   DCHECK(thread_checker_.CalledOnValidThread());
    163 
    164   ++GetMonitor(details.extension_id)->listeners;
    165   StartPolling();
    166 }
    167 
    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 
    180 void IdleManager::QueryState(int threshold, QueryStateCallback notify) {
    181   DCHECK(thread_checker_.CalledOnValidThread());
    182   idle_time_provider_->CalculateIdleState(threshold, notify);
    183 }
    184 
    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
    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 
    206 void IdleManager::SetEventDelegateForTest(
    207     scoped_ptr<EventDelegate> event_delegate) {
    208   DCHECK(thread_checker_.CalledOnValidThread());
    209   event_delegate_ = event_delegate.Pass();
    210 }
    211 
    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 
    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 
    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 
    239 void IdleManager::StopPolling() {
    240   DCHECK(thread_checker_.CalledOnValidThread());
    241   poll_timer_.Stop();
    242 }
    243 
    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 
    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