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_win.h" | |
6 | |
7 #include "base/memory/ref_counted.h" | |
8 #include "base/strings/string16.h" | |
9 #include "base/win/message_window.h" | |
10 #include "base/win/windows_version.h" | |
11 #include "content/browser/battery_status/battery_status_manager.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 | |
14 namespace content { | |
15 | |
16 namespace { | |
17 | |
18 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback; | |
19 | |
20 const wchar_t kWindowClassName[] = L"BatteryStatusMessageWindow"; | |
21 | |
22 // Message-only window for handling battery changes on Windows. | |
23 class BatteryStatusObserver | |
24 : public base::RefCountedThreadSafe<BatteryStatusObserver> { | |
25 public: | |
26 explicit BatteryStatusObserver(const BatteryCallback& callback) | |
27 : power_handle_(NULL), | |
28 battery_change_handle_(NULL), | |
29 callback_(callback) { | |
30 } | |
31 | |
32 virtual ~BatteryStatusObserver() { DCHECK(!window_); } | |
33 | |
34 void Start() { | |
35 // Need to start on the UI thread to receive battery status notifications. | |
36 BrowserThread::PostTask( | |
37 BrowserThread::UI, | |
38 FROM_HERE, | |
39 base::Bind(&BatteryStatusObserver::StartOnUI, this)); | |
40 } | |
41 | |
42 void Stop() { | |
43 BrowserThread::PostTask( | |
44 BrowserThread::UI, | |
45 FROM_HERE, | |
46 base::Bind(&BatteryStatusObserver::StopOnUI, this)); | |
47 } | |
48 | |
49 private: | |
50 void StartOnUI() { | |
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
52 if (window_) | |
53 return; | |
54 | |
55 if (CreateMessageWindow()) { | |
56 BatteryChanged(); | |
57 // RegisterPowerSettingNotification function work from Windows Vista | |
58 // onwards. However even without them we will receive notifications, | |
59 // e.g. when a power source is connected. | |
60 // TODO(timvolodine) : consider polling for battery changes on windows | |
61 // versions prior to Vista, see crbug.com/402466. | |
62 power_handle_ = | |
63 RegisterPowerSettingNotification(&GUID_ACDC_POWER_SOURCE); | |
64 battery_change_handle_ = | |
65 RegisterPowerSettingNotification(&GUID_BATTERY_PERCENTAGE_REMAINING); | |
66 } else { | |
67 // Could not create a message window, execute callback with the default | |
68 // values. | |
69 callback_.Run(blink::WebBatteryStatus()); | |
70 } | |
71 } | |
72 | |
73 void StopOnUI() { | |
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
75 if (!window_) | |
76 return; | |
77 | |
78 if (power_handle_) | |
79 UnregisterPowerSettingNotification(power_handle_); | |
80 if (battery_change_handle_) | |
81 UnregisterPowerSettingNotification(battery_change_handle_); | |
82 window_.reset(); | |
83 } | |
84 | |
85 void BatteryChanged() { | |
86 blink::WebBatteryStatus status; | |
87 SYSTEM_POWER_STATUS win_status; | |
88 if (GetSystemPowerStatus(&win_status)) | |
89 status = ComputeWebBatteryStatus(win_status); | |
90 | |
91 callback_.Run(status); | |
92 } | |
93 | |
94 bool HandleMessage(UINT message, | |
95 WPARAM wparam, | |
96 LPARAM lparam, | |
97 LRESULT* result) { | |
98 switch(message) { | |
99 case WM_POWERBROADCAST: | |
100 if (wparam == PBT_APMPOWERSTATUSCHANGE || | |
101 wparam == PBT_POWERSETTINGCHANGE) { | |
102 BatteryChanged(); | |
103 } | |
104 *result = NULL; | |
105 return true; | |
106 default: | |
107 return false; | |
108 } | |
109 } | |
110 | |
111 HPOWERNOTIFY RegisterPowerSettingNotification(LPCGUID power_setting) { | |
112 if (base::win::GetVersion() < base::win::VERSION_VISTA) | |
113 return NULL; | |
114 | |
115 typedef HPOWERNOTIFY (WINAPI* RegisterPowerSettingNotificationFunc) | |
scottmg
2014/08/13 23:39:52
per previous comment, you don't need GetProcAddres
timvolodine
2014/08/14 15:34:34
great, it magically works :) thanks.
Done.
| |
116 (HANDLE recipient, LPCGUID id, DWORD flags); | |
117 | |
118 RegisterPowerSettingNotificationFunc register_func_ = | |
scottmg
2014/08/13 23:39:52
(don't need it, but no trailing _ on locals)
timvolodine
2014/08/14 15:34:34
Done.
| |
119 reinterpret_cast<RegisterPowerSettingNotificationFunc>( | |
120 GetProcAddress(GetModuleHandleA("user32.dll"), | |
121 "RegisterPowerSettingNotification")); | |
122 | |
123 return register_func_ ? register_func_(window_->hwnd(), power_setting, | |
124 DEVICE_NOTIFY_WINDOW_HANDLE) | |
125 : NULL; | |
126 } | |
127 | |
128 BOOL UnregisterPowerSettingNotification(HPOWERNOTIFY handle) { | |
129 if (base::win::GetVersion() < base::win::VERSION_VISTA) | |
130 return FALSE; | |
131 | |
132 typedef BOOL (WINAPI* UnregisterPowerSettingNotificationFunc) | |
133 (HPOWERNOTIFY handle); | |
134 | |
135 UnregisterPowerSettingNotificationFunc unregister_func_ = | |
scottmg
2014/08/13 23:39:52
same here
timvolodine
2014/08/14 15:34:34
Done.
| |
136 reinterpret_cast<UnregisterPowerSettingNotificationFunc>( | |
137 GetProcAddress(GetModuleHandleA("user32.dll"), | |
138 "UnregisterPowerSettingNotification")); | |
139 | |
140 return unregister_func_ ? unregister_func_(handle) : FALSE; | |
141 } | |
142 | |
143 bool CreateMessageWindow() { | |
cpu_(ooo_6.6-7.5)
2014/08/13 23:29:06
do we need to create a new window? I thought we al
timvolodine
2014/08/14 15:34:34
not sure what window singleton you are referring t
| |
144 window_.reset(new base::win::MessageWindow()); | |
145 if (!window_->CreateNamed(base::Bind(&BatteryStatusObserver::HandleMessage, | |
146 base::Unretained(this)), | |
147 base::string16(kWindowClassName))) { | |
148 LOG(ERROR) << "Failed to create message window: " << kWindowClassName; | |
149 window_.reset(); | |
150 return false; | |
151 } | |
152 return true; | |
153 } | |
154 | |
155 HPOWERNOTIFY power_handle_; | |
156 HPOWERNOTIFY battery_change_handle_; | |
157 BatteryCallback callback_; | |
158 scoped_ptr<base::win::MessageWindow> window_; | |
159 | |
160 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver); | |
161 }; | |
162 | |
163 class BatteryStatusManagerWin : public BatteryStatusManager { | |
164 public: | |
165 explicit BatteryStatusManagerWin(const BatteryCallback& callback) | |
166 : battery_observer_(new BatteryStatusObserver(callback)) {} | |
167 virtual ~BatteryStatusManagerWin() { battery_observer_->Stop(); } | |
168 | |
169 public: | |
170 // BatteryStatusManager: | |
171 virtual bool StartListeningBatteryChange() OVERRIDE { | |
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
173 battery_observer_->Start(); | |
174 return true; | |
175 } | |
176 | |
177 virtual void StopListeningBatteryChange() OVERRIDE { | |
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
179 battery_observer_->Stop(); | |
180 } | |
181 | |
182 private: | |
183 scoped_refptr<BatteryStatusObserver> battery_observer_; | |
184 | |
185 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin); | |
186 }; | |
187 | |
188 } // namespace | |
189 | |
190 blink::WebBatteryStatus ComputeWebBatteryStatus( | |
191 const SYSTEM_POWER_STATUS& win_status) { | |
192 blink::WebBatteryStatus status; | |
193 status.charging = win_status.ACLineStatus != WIN_AC_LINE_STATUS_OFFLINE; | |
194 // Set level if available. Otherwise keep the default value which is 1. | |
195 if (win_status.BatteryLifePercent != 255) { | |
196 // Convert percentage to a value between 0 and 1 with 2 significant digits. | |
197 status.level = static_cast<double>(win_status.BatteryLifePercent) / 100.; | |
198 } | |
199 if (!status.charging) { | |
200 // Set dischargingTime if available otherwise keep the default value, | |
201 // which is +Infinity. | |
202 if (win_status.BatteryLifeTime != (DWORD)-1) | |
203 status.dischargingTime = win_status.BatteryLifeTime; | |
204 status.chargingTime = std::numeric_limits<double>::infinity(); | |
205 } else { | |
206 // Set chargingTime to +Infinity if not fully charged, otherwise leave the | |
207 // default value, which is 0. | |
208 if (status.level < 1) | |
209 status.chargingTime = std::numeric_limits<double>::infinity(); | |
210 } | |
211 return status; | |
212 } | |
213 | |
214 // static | |
215 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create( | |
216 const BatteryStatusService::BatteryUpdateCallback& callback) { | |
217 return scoped_ptr<BatteryStatusManager>( | |
218 new BatteryStatusManagerWin(callback)); | |
219 } | |
220 | |
221 } // namespace content | |
OLD | NEW |