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.
5 #include "content/browser/battery_status/battery_status_manager_win.h"
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"
18 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback
;
20 const wchar_t kWindowClassName
[] = L
"BatteryStatusMessageWindow";
22 // Message-only window for handling battery changes on Windows.
23 class BatteryStatusObserver
24 : public base::RefCountedThreadSafe
<BatteryStatusObserver
> {
26 explicit BatteryStatusObserver(const BatteryCallback
& callback
)
27 : power_handle_(NULL
),
28 battery_change_handle_(NULL
),
32 virtual ~BatteryStatusObserver() { DCHECK(!window_
); }
35 // Need to start on the UI thread to receive battery status notifications.
36 BrowserThread::PostTask(
39 base::Bind(&BatteryStatusObserver::StartOnUI
, this));
43 BrowserThread::PostTask(
46 base::Bind(&BatteryStatusObserver::StopOnUI
, this));
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
55 if (CreateMessageWindow()) {
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.
63 RegisterNotification(&GUID_ACDC_POWER_SOURCE
);
64 battery_change_handle_
=
65 RegisterNotification(&GUID_BATTERY_PERCENTAGE_REMAINING
);
67 // Could not create a message window, execute callback with the default
69 callback_
.Run(blink::WebBatteryStatus());
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
79 UnregisterNotification(power_handle_
);
80 if (battery_change_handle_
)
81 UnregisterNotification(battery_change_handle_
);
85 void BatteryChanged() {
86 SYSTEM_POWER_STATUS win_status
;
87 if (GetSystemPowerStatus(&win_status
))
88 callback_
.Run(ComputeWebBatteryStatus(win_status
));
90 callback_
.Run(blink::WebBatteryStatus());
93 bool HandleMessage(UINT message
,
98 case WM_POWERBROADCAST
:
99 if (wparam
== PBT_APMPOWERSTATUSCHANGE
||
100 wparam
== PBT_POWERSETTINGCHANGE
) {
110 HPOWERNOTIFY
RegisterNotification(LPCGUID power_setting
) {
111 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
114 return RegisterPowerSettingNotification(window_
->hwnd(), power_setting
,
115 DEVICE_NOTIFY_WINDOW_HANDLE
);
118 BOOL
UnregisterNotification(HPOWERNOTIFY handle
) {
119 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
122 return UnregisterPowerSettingNotification(handle
);
125 bool CreateMessageWindow() {
126 // TODO(timvolodine): consider reusing the message window of PowerMonitor.
127 window_
.reset(new base::win::MessageWindow());
128 if (!window_
->CreateNamed(base::Bind(&BatteryStatusObserver::HandleMessage
,
129 base::Unretained(this)),
130 base::string16(kWindowClassName
))) {
131 LOG(ERROR
) << "Failed to create message window: " << kWindowClassName
;
138 HPOWERNOTIFY power_handle_
;
139 HPOWERNOTIFY battery_change_handle_
;
140 BatteryCallback callback_
;
141 scoped_ptr
<base::win::MessageWindow
> window_
;
143 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver
);
146 class BatteryStatusManagerWin
: public BatteryStatusManager
{
148 explicit BatteryStatusManagerWin(const BatteryCallback
& callback
)
149 : battery_observer_(new BatteryStatusObserver(callback
)) {}
150 virtual ~BatteryStatusManagerWin() { battery_observer_
->Stop(); }
153 // BatteryStatusManager:
154 virtual bool StartListeningBatteryChange() OVERRIDE
{
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
156 battery_observer_
->Start();
160 virtual void StopListeningBatteryChange() OVERRIDE
{
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
162 battery_observer_
->Stop();
166 scoped_refptr
<BatteryStatusObserver
> battery_observer_
;
168 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin
);
173 blink::WebBatteryStatus
ComputeWebBatteryStatus(
174 const SYSTEM_POWER_STATUS
& win_status
) {
175 blink::WebBatteryStatus status
;
176 status
.charging
= win_status
.ACLineStatus
!= WIN_AC_LINE_STATUS_OFFLINE
;
178 // Set level if available. Otherwise keep the default value which is 1.
179 if (win_status
.BatteryLifePercent
!= 255) {
180 // Convert percentage to a value between 0 and 1 with 2 significant digits.
181 status
.level
= static_cast<double>(win_status
.BatteryLifePercent
) / 100.;
184 if (!status
.charging
) {
185 // Set dischargingTime if available otherwise keep the default value,
186 // which is +Infinity.
187 if (win_status
.BatteryLifeTime
!= (DWORD
)-1)
188 status
.dischargingTime
= win_status
.BatteryLifeTime
;
189 status
.chargingTime
= std::numeric_limits
<double>::infinity();
191 // Set chargingTime to +Infinity if not fully charged, otherwise leave the
192 // default value, which is 0.
193 if (status
.level
< 1)
194 status
.chargingTime
= std::numeric_limits
<double>::infinity();
200 scoped_ptr
<BatteryStatusManager
> BatteryStatusManager::Create(
201 const BatteryStatusService::BatteryUpdateCallback
& callback
) {
202 return scoped_ptr
<BatteryStatusManager
>(
203 new BatteryStatusManagerWin(callback
));
206 } // namespace content