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