Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "content/browser/battery_status/battery_status_manager.h" | |
| 6 | |
| 7 #include <windows.h> | |
| 8 #include "base/memory/ref_counted.h" | |
| 9 #include "base/win/windows_version.h" | |
| 10 #include "base/win/wrapped_window_proc.h" | |
| 11 #include "content/public/browser/browser_thread.h" | |
| 12 #include "third_party/WebKit/public/platform/WebBatteryStatus.h" | |
| 13 | |
| 14 namespace content { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback; | |
| 19 | |
| 20 const wchar_t kWindowClassName[] = L"BatteryStatusMessageWindow"; | |
| 21 | |
| 22 void ComputeWebBatteryStatus(const SYSTEM_POWER_STATUS& win_status, | |
| 23 blink::WebBatteryStatus& status) { | |
| 24 bool on_battery = win_status.ACLineStatus == 0; | |
| 25 status.charging = !on_battery; // not offline | |
|
mlamouri (slow - plz ping)
2014/08/07 16:40:47
Couldn't you do:
status.charging = win_status.ACL
timvolodine
2014/08/11 19:43:41
Done.
| |
| 26 // Set level if available. Otherwise keep the default value which is 1. | |
| 27 if (win_status.BatteryLifePercent != 255) { | |
| 28 // Convert percentage to a value between 0 and 1 with 3 significant digits. | |
| 29 status.level = round(win_status.BatteryLifePercent * 10) / 1000.f; | |
| 30 } | |
| 31 if (on_battery) { | |
| 32 // Set dischargingTime if available otherwise keep the default value, | |
| 33 // which is +Infinity. | |
| 34 if (win_status.BatteryLifeTime != -1) | |
| 35 status.dischargingTime = win_status.BatteryLifeTime; | |
| 36 status.chargingTime = std::numeric_limits<double>::infinity(); | |
| 37 } else { | |
| 38 // Set chargingTime to +Infinity if not fully charged, otherwise leave the | |
| 39 // default value, which is 0. | |
| 40 if (status.level < 1) | |
| 41 status.chargingTime = std::numeric_limits<double>::infinity(); | |
|
mlamouri (slow - plz ping)
2014/08/07 16:40:47
Can't you use status.BatteryFullLifeTime?
timvolodine
2014/08/11 19:43:41
according to the documentation BatteryFullLifeTime
| |
| 42 } | |
| 43 } | |
| 44 | |
| 45 // Message-only window for handling battery changes on Windows. | |
| 46 class BatteryStatusObserver | |
| 47 : public base::RefCountedThreadSafe<BatteryStatusObserver> { | |
| 48 public: | |
| 49 explicit BatteryStatusObserver(const BatteryCallback& callback) | |
| 50 : register_func_(NULL), | |
| 51 unregister_func_(NULL), | |
| 52 instance_(NULL), | |
| 53 message_hwnd_(NULL), | |
| 54 power_handle_(NULL), | |
| 55 battery_change_handle_(NULL), | |
| 56 callback_(callback) { | |
| 57 InitPowerSettingFunctions(); | |
| 58 } | |
| 59 | |
| 60 virtual ~BatteryStatusObserver() { DCHECK(!message_hwnd_); } | |
| 61 | |
| 62 void Start() { | |
| 63 // Need to start on the UI thread to receive battery status notifications. | |
| 64 BrowserThread::PostTask( | |
| 65 BrowserThread::UI, | |
| 66 FROM_HERE, | |
| 67 base::Bind(&BatteryStatusObserver::StartOnUI, this)); | |
| 68 } | |
| 69 | |
| 70 void Stop() { | |
| 71 BrowserThread::PostTask( | |
| 72 BrowserThread::UI, | |
| 73 FROM_HERE, | |
| 74 base::Bind(&BatteryStatusObserver::StopOnUI, this)); | |
| 75 } | |
| 76 | |
| 77 private: | |
| 78 | |
| 79 void StartOnUI() { | |
| 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 81 if (message_hwnd_) | |
| 82 return; | |
| 83 | |
| 84 if (CreateMessageWindow()) { | |
| 85 BatteryChanged(); | |
| 86 // RegisterPowerSettingNotification function work from Windows Vista | |
| 87 // onwards. However even without them we will receive notifications, | |
| 88 // e.g. when a power source is connected. | |
| 89 power_handle_ = | |
| 90 RegisterPowerSettingNotification(&GUID_ACDC_POWER_SOURCE); | |
| 91 battery_change_handle_ = | |
| 92 RegisterPowerSettingNotification(&GUID_BATTERY_PERCENTAGE_REMAINING); | |
| 93 } else { | |
| 94 // Could not create a message window, execute callback with the default | |
| 95 // values. | |
| 96 callback_.Run(blink::WebBatteryStatus()); | |
| 97 } | |
| 98 | |
| 99 } | |
| 100 | |
| 101 void StopOnUI() { | |
| 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 103 if (!message_hwnd_) | |
| 104 return; | |
| 105 | |
| 106 if (power_handle_) | |
| 107 UnregisterPowerSettingNotification(power_handle_); | |
| 108 if (battery_change_handle_) | |
| 109 UnregisterPowerSettingNotification(battery_change_handle_); | |
| 110 DestroyWindow(message_hwnd_); | |
| 111 UnregisterClass(kWindowClassName, instance_); | |
| 112 message_hwnd_ = NULL; | |
| 113 } | |
| 114 | |
| 115 static LRESULT CALLBACK WndProcThunk(HWND hwnd, | |
| 116 UINT message, | |
| 117 WPARAM wparam, | |
| 118 LPARAM lparam) { | |
| 119 BatteryStatusObserver* msg_wnd = reinterpret_cast<BatteryStatusObserver*>( | |
| 120 GetWindowLongPtr(hwnd, GWLP_USERDATA)); | |
| 121 switch(message) { | |
| 122 case WM_POWERBROADCAST: | |
| 123 if (wparam == PBT_APMPOWERSTATUSCHANGE || | |
| 124 wparam == PBT_POWERSETTINGCHANGE) { | |
| 125 msg_wnd->BatteryChanged(); | |
| 126 } | |
| 127 return true; | |
| 128 default: | |
| 129 return ::DefWindowProc(hwnd, message, wparam, lparam); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void BatteryChanged() { | |
| 134 blink::WebBatteryStatus status; | |
| 135 SYSTEM_POWER_STATUS win_status; | |
| 136 if (GetSystemPowerStatus(&win_status)) | |
| 137 ComputeWebBatteryStatus(win_status, status); | |
| 138 | |
| 139 callback_.Run(status); | |
| 140 } | |
| 141 | |
| 142 HPOWERNOTIFY RegisterPowerSettingNotification(LPCGUID power_setting) { | |
| 143 return register_func_ ? register_func_(message_hwnd_, power_setting, | |
| 144 DEVICE_NOTIFY_WINDOW_HANDLE) | |
| 145 : NULL; | |
| 146 } | |
| 147 | |
| 148 BOOL UnregisterPowerSettingNotification(HPOWERNOTIFY handle) { | |
| 149 return unregister_func_ ? unregister_func_(handle) : FALSE; | |
| 150 } | |
| 151 | |
| 152 void InitPowerSettingFunctions() { | |
| 153 if (base::win::GetVersion() < base::win::VERSION_VISTA) | |
| 154 return; | |
|
mlamouri (slow - plz ping)
2014/08/07 16:40:47
If that means that we don't get any event before V
timvolodine
2014/08/11 19:43:41
Done. added a crbug.
| |
| 155 | |
| 156 HMODULE user32 = GetModuleHandleA("user32.dll"); | |
|
scottmg
2014/08/08 21:32:19
I believe user32 is delayload, so you can just run
timvolodine
2014/08/11 19:43:41
Done.
| |
| 157 register_func_ = reinterpret_cast<RegisterPowerSettingNotificationFunc>( | |
| 158 GetProcAddress(user32, "RegisterPowerSettingNotification")); | |
| 159 unregister_func_ = reinterpret_cast<UnregisterPowerSettingNotificationFunc>( | |
| 160 GetProcAddress(user32, "UnregisterPowerSettingNotification")); | |
| 161 DCHECK(register_func_ && unregister_func_); | |
| 162 } | |
| 163 | |
| 164 bool CreateMessageWindow() { | |
|
scottmg
2014/08/08 21:32:19
can we use base::win::MessageWindow here?
timvolodine
2014/08/11 19:43:41
yes. thanks for noticing this, done.
| |
| 165 WNDCLASSEX window_class; | |
| 166 base::win::InitializeWindowClass(kWindowClassName, | |
| 167 &base::win::WrappedWindowProc<BatteryStatusObserver::WndProcThunk>, | |
| 168 0, 0, 0, NULL, NULL, NULL, NULL, NULL, &window_class); | |
| 169 instance_ = window_class.hInstance; | |
| 170 ATOM clazz = RegisterClassEx(&window_class); | |
| 171 DCHECK(clazz); | |
| 172 message_hwnd_ = CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName, | |
| 173 NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance_, NULL); | |
| 174 if (!message_hwnd_) | |
| 175 return false; | |
| 176 SetWindowLongPtr(message_hwnd_, GWLP_USERDATA, | |
| 177 reinterpret_cast<LONG_PTR>(this)); | |
| 178 return true; | |
| 179 } | |
| 180 | |
| 181 typedef HPOWERNOTIFY (WINAPI* RegisterPowerSettingNotificationFunc) | |
| 182 (HANDLE recipient, LPCGUID id, DWORD flags); | |
| 183 RegisterPowerSettingNotificationFunc register_func_; | |
| 184 | |
| 185 typedef BOOL (WINAPI* UnregisterPowerSettingNotificationFunc) | |
| 186 (HPOWERNOTIFY handle); | |
| 187 UnregisterPowerSettingNotificationFunc unregister_func_; | |
| 188 | |
| 189 HMODULE instance_; | |
| 190 HWND message_hwnd_; | |
| 191 HPOWERNOTIFY power_handle_; | |
| 192 HPOWERNOTIFY battery_change_handle_; | |
| 193 BatteryCallback callback_; | |
| 194 | |
| 195 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver); | |
| 196 }; | |
| 197 | |
| 198 class BatteryStatusManagerWin : public BatteryStatusManager { | |
| 199 public: | |
| 200 explicit BatteryStatusManagerWin(const BatteryCallback& callback) | |
| 201 : battery_observer_(new BatteryStatusObserver(callback)) {} | |
| 202 virtual ~BatteryStatusManagerWin() { battery_observer_->Stop(); } | |
| 203 | |
| 204 public: | |
| 205 // BatteryStatusManager: | |
| 206 virtual bool StartListeningBatteryChange() OVERRIDE { | |
| 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 208 battery_observer_->Start(); | |
| 209 return true; | |
| 210 } | |
| 211 | |
| 212 virtual void StopListeningBatteryChange() OVERRIDE { | |
| 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 214 battery_observer_->Stop(); | |
| 215 } | |
| 216 | |
| 217 private: | |
| 218 scoped_refptr<BatteryStatusObserver> battery_observer_; | |
| 219 | |
| 220 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin); | |
| 221 }; | |
| 222 | |
| 223 } // namespace | |
| 224 | |
| 225 // static | |
| 226 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create( | |
| 227 const BatteryStatusService::BatteryUpdateCallback& callback) { | |
| 228 return scoped_ptr<BatteryStatusManager>( | |
| 229 new BatteryStatusManagerWin(callback)); | |
| 230 } | |
| 231 | |
| 232 } // namespace content | |
| OLD | NEW |