Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: content/browser/battery_status/battery_status_manager_win.cc

Issue 447853002: Battery Status API: implementation for Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698