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 "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/common/extensions/extension.h"
     10 #include "content/public/browser/notification_service.h"
     11 
     12 namespace extensions {
     13 
     14 namespace {
     15 
     16 const char kPowerSaveBlockerReason[] = "extension";
     17 
     18 content::PowerSaveBlocker::PowerSaveBlockerType
     19 LevelToPowerSaveBlockerType(api::power::Level level) {
     20   switch (level) {
     21     case api::power::LEVEL_SYSTEM:
     22       return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
     23     case api::power::LEVEL_DISPLAY:  // fallthrough
     24     case api::power::LEVEL_NONE:
     25       return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
     26   }
     27   NOTREACHED() << "Unhandled level " << level;
     28   return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
     29 }
     30 
     31 }  // namespace
     32 
     33 // static
     34 PowerApiManager* PowerApiManager::GetInstance() {
     35   return Singleton<PowerApiManager>::get();
     36 }
     37 
     38 void PowerApiManager::AddRequest(const std::string& extension_id,
     39                                  api::power::Level level) {
     40   extension_levels_[extension_id] = level;
     41   UpdatePowerSaveBlocker();
     42 }
     43 
     44 void PowerApiManager::RemoveRequest(const std::string& extension_id) {
     45   extension_levels_.erase(extension_id);
     46   UpdatePowerSaveBlocker();
     47 }
     48 
     49 void PowerApiManager::SetCreateBlockerFunctionForTesting(
     50     CreateBlockerFunction function) {
     51   create_blocker_function_ = !function.is_null() ? function :
     52       base::Bind(&content::PowerSaveBlocker::Create);
     53 }
     54 
     55 void PowerApiManager::Observe(int type,
     56                               const content::NotificationSource& source,
     57                               const content::NotificationDetails& details) {
     58   switch (type) {
     59     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
     60       RemoveRequest(content::Details<extensions::UnloadedExtensionInfo>(
     61           details)->extension->id());
     62       UpdatePowerSaveBlocker();
     63       break;
     64     case chrome::NOTIFICATION_APP_TERMINATING:
     65       power_save_blocker_.reset();
     66       break;
     67     default:
     68       NOTREACHED() << "Unexpected notification " << type;
     69   }
     70 }
     71 
     72 PowerApiManager::PowerApiManager()
     73     : create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)),
     74       current_level_(api::power::LEVEL_SYSTEM) {
     75   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
     76                   content::NotificationService::AllSources());
     77   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
     78                  content::NotificationService::AllSources());
     79 }
     80 
     81 PowerApiManager::~PowerApiManager() {}
     82 
     83 void PowerApiManager::UpdatePowerSaveBlocker() {
     84   if (extension_levels_.empty()) {
     85     power_save_blocker_.reset();
     86     return;
     87   }
     88 
     89   api::power::Level new_level = api::power::LEVEL_SYSTEM;
     90   for (ExtensionLevelMap::const_iterator it = extension_levels_.begin();
     91        it != extension_levels_.end(); ++it) {
     92     if (it->second == api::power::LEVEL_DISPLAY)
     93       new_level = it->second;
     94   }
     95 
     96   // If the level changed and we need to create a new blocker, do a swap
     97   // to ensure that there isn't a brief period where power management is
     98   // unblocked.
     99   if (!power_save_blocker_ || new_level != current_level_) {
    100     content::PowerSaveBlocker::PowerSaveBlockerType type =
    101         LevelToPowerSaveBlockerType(new_level);
    102     scoped_ptr<content::PowerSaveBlocker> new_blocker(
    103         create_blocker_function_.Run(type, kPowerSaveBlockerReason));
    104     power_save_blocker_.swap(new_blocker);
    105     current_level_ = new_level;
    106   }
    107 }
    108 
    109 }  // namespace extensions
    110