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 12namespace extensions { 13 14namespace { 15 16const char kPowerSaveBlockerReason[] = "extension"; 17 18content::PowerSaveBlocker::PowerSaveBlockerType 19LevelToPowerSaveBlockerType(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 34PowerApiManager* PowerApiManager::GetInstance() { 35 return Singleton<PowerApiManager>::get(); 36} 37 38void PowerApiManager::AddRequest(const std::string& extension_id, 39 api::power::Level level) { 40 extension_levels_[extension_id] = level; 41 UpdatePowerSaveBlocker(); 42} 43 44void PowerApiManager::RemoveRequest(const std::string& extension_id) { 45 extension_levels_.erase(extension_id); 46 UpdatePowerSaveBlocker(); 47} 48 49void PowerApiManager::SetCreateBlockerFunctionForTesting( 50 CreateBlockerFunction function) { 51 create_blocker_function_ = !function.is_null() ? function : 52 base::Bind(&content::PowerSaveBlocker::Create); 53} 54 55void 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 72PowerApiManager::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 81PowerApiManager::~PowerApiManager() {} 82 83void 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