Home | History | Annotate | Download | only in power
      1 // Copyright (c) 2013 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/power/power_api_manager.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "content/public/browser/notification_service.h"
     11 #include "extensions/browser/extension_registry.h"
     12 #include "extensions/common/extension.h"
     13 
     14 namespace extensions {
     15 
     16 namespace {
     17 
     18 const char kPowerSaveBlockerReason[] = "extension";
     19 
     20 content::PowerSaveBlocker::PowerSaveBlockerType
     21 LevelToPowerSaveBlockerType(api::power::Level level) {
     22   switch (level) {
     23     case api::power::LEVEL_SYSTEM:
     24       return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
     25     case api::power::LEVEL_DISPLAY:  // fallthrough
     26     case api::power::LEVEL_NONE:
     27       return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
     28   }
     29   NOTREACHED() << "Unhandled level " << level;
     30   return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
     31 }
     32 
     33 base::LazyInstance<BrowserContextKeyedAPIFactory<PowerApiManager> > g_factory =
     34     LAZY_INSTANCE_INITIALIZER;
     35 
     36 }  // namespace
     37 
     38 // static
     39 PowerApiManager* PowerApiManager::Get(content::BrowserContext* context) {
     40   return BrowserContextKeyedAPIFactory<PowerApiManager>::Get(context);
     41 }
     42 
     43 // static
     44 BrowserContextKeyedAPIFactory<PowerApiManager>*
     45 PowerApiManager::GetFactoryInstance() {
     46   return g_factory.Pointer();
     47 }
     48 
     49 void PowerApiManager::AddRequest(const std::string& extension_id,
     50                                  api::power::Level level) {
     51   extension_levels_[extension_id] = level;
     52   UpdatePowerSaveBlocker();
     53 }
     54 
     55 void PowerApiManager::RemoveRequest(const std::string& extension_id) {
     56   extension_levels_.erase(extension_id);
     57   UpdatePowerSaveBlocker();
     58 }
     59 
     60 void PowerApiManager::SetCreateBlockerFunctionForTesting(
     61     CreateBlockerFunction function) {
     62   create_blocker_function_ = !function.is_null() ? function :
     63       base::Bind(&content::PowerSaveBlocker::Create);
     64 }
     65 
     66 void PowerApiManager::Observe(int type,
     67                               const content::NotificationSource& source,
     68                               const content::NotificationDetails& details) {
     69   DCHECK_EQ(type, chrome::NOTIFICATION_APP_TERMINATING);
     70   power_save_blocker_.reset();
     71 }
     72 
     73 void PowerApiManager::OnExtensionUnloaded(
     74     content::BrowserContext* browser_context,
     75     const Extension* extension,
     76     UnloadedExtensionInfo::Reason reason) {
     77   RemoveRequest(extension->id());
     78   UpdatePowerSaveBlocker();
     79 }
     80 
     81 PowerApiManager::PowerApiManager(content::BrowserContext* context)
     82     : browser_context_(context),
     83       create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)),
     84       current_level_(api::power::LEVEL_SYSTEM) {
     85   ExtensionRegistry::Get(browser_context_)->AddObserver(this);
     86   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
     87                  content::NotificationService::AllSources());
     88 }
     89 
     90 PowerApiManager::~PowerApiManager() {}
     91 
     92 void PowerApiManager::UpdatePowerSaveBlocker() {
     93   if (extension_levels_.empty()) {
     94     power_save_blocker_.reset();
     95     return;
     96   }
     97 
     98   api::power::Level new_level = api::power::LEVEL_SYSTEM;
     99   for (ExtensionLevelMap::const_iterator it = extension_levels_.begin();
    100        it != extension_levels_.end(); ++it) {
    101     if (it->second == api::power::LEVEL_DISPLAY)
    102       new_level = it->second;
    103   }
    104 
    105   // If the level changed and we need to create a new blocker, do a swap
    106   // to ensure that there isn't a brief period where power management is
    107   // unblocked.
    108   if (!power_save_blocker_ || new_level != current_level_) {
    109     content::PowerSaveBlocker::PowerSaveBlockerType type =
    110         LevelToPowerSaveBlockerType(new_level);
    111     scoped_ptr<content::PowerSaveBlocker> new_blocker(
    112         create_blocker_function_.Run(type, kPowerSaveBlockerReason));
    113     power_save_blocker_.swap(new_blocker);
    114     current_level_ = new_level;
    115   }
    116 }
    117 
    118 void PowerApiManager::Shutdown() {
    119   // Unregister here rather than in the d'tor; otherwise this call will recreate
    120   // the already-deleted ExtensionRegistry.
    121   ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
    122 }
    123 
    124 }  // namespace extensions
    125