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 "device/battery/battery_status_manager_win.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string16.h"
11 #include "base/win/message_window.h"
12 #include "base/win/windows_version.h"
13 #include "device/battery/battery_status_manager.h"
19 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback
;
21 const wchar_t kWindowClassName
[] = L
"BatteryStatusMessageWindow";
23 // This enum is used for histogram. Don't change the order of the existing
25 enum NumberBatteriesType
{
26 UNKNOWN_BATTERIES
= 0,
28 ONE_OR_MORE_BATTERIES
= 2,
29 BATTERY_TYPES_COUNT
= 3,
32 void UpdateNumberBatteriesHistogram(NumberBatteriesType count
) {
33 UMA_HISTOGRAM_ENUMERATION("BatteryStatus.NumberBatteriesWin",
38 void UpdateNumberBatteriesHistogram() {
39 SYSTEM_POWER_STATUS win_status
;
40 if (!GetSystemPowerStatus(&win_status
)) {
41 UpdateNumberBatteriesHistogram(UNKNOWN_BATTERIES
);
45 if (win_status
.BatteryFlag
== 255)
46 UpdateNumberBatteriesHistogram(UNKNOWN_BATTERIES
);
47 else if (win_status
.BatteryFlag
== 128)
48 UpdateNumberBatteriesHistogram(NO_BATTERY
);
50 UpdateNumberBatteriesHistogram(ONE_OR_MORE_BATTERIES
);
53 // Message-only window for handling battery changes on Windows.
54 class BatteryStatusObserver
{
56 explicit BatteryStatusObserver(const BatteryCallback
& callback
)
57 : power_handle_(NULL
),
58 battery_change_handle_(NULL
),
62 ~BatteryStatusObserver() { DCHECK(!window_
); }
65 if (CreateMessageWindow()) {
67 // RegisterPowerSettingNotification function work from Windows Vista
68 // onwards. However even without them we will receive notifications,
69 // e.g. when a power source is connected.
70 // TODO(timvolodine) : consider polling for battery changes on windows
71 // versions prior to Vista, see crbug.com/402466.
73 RegisterNotification(&GUID_ACDC_POWER_SOURCE
);
74 battery_change_handle_
=
75 RegisterNotification(&GUID_BATTERY_PERCENTAGE_REMAINING
);
77 // Could not create a message window, execute callback with the default
79 callback_
.Run(BatteryStatus());
82 UpdateNumberBatteriesHistogram();
87 UnregisterNotification(power_handle_
);
88 if (battery_change_handle_
)
89 UnregisterNotification(battery_change_handle_
);
94 void BatteryChanged() {
95 SYSTEM_POWER_STATUS win_status
;
96 if (GetSystemPowerStatus(&win_status
))
97 callback_
.Run(ComputeWebBatteryStatus(win_status
));
99 callback_
.Run(BatteryStatus());
102 bool HandleMessage(UINT message
,
107 case WM_POWERBROADCAST
:
108 if (wparam
== PBT_APMPOWERSTATUSCHANGE
||
109 wparam
== PBT_POWERSETTINGCHANGE
) {
119 HPOWERNOTIFY
RegisterNotification(LPCGUID power_setting
) {
120 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
123 return RegisterPowerSettingNotification(window_
->hwnd(), power_setting
,
124 DEVICE_NOTIFY_WINDOW_HANDLE
);
127 BOOL
UnregisterNotification(HPOWERNOTIFY handle
) {
128 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
131 return UnregisterPowerSettingNotification(handle
);
134 bool CreateMessageWindow() {
135 // TODO(timvolodine): consider reusing the message window of PowerMonitor.
136 window_
.reset(new base::win::MessageWindow());
137 if (!window_
->CreateNamed(base::Bind(&BatteryStatusObserver::HandleMessage
,
138 base::Unretained(this)),
139 base::string16(kWindowClassName
))) {
140 LOG(ERROR
) << "Failed to create message window: " << kWindowClassName
;
147 HPOWERNOTIFY power_handle_
;
148 HPOWERNOTIFY battery_change_handle_
;
149 BatteryCallback callback_
;
150 scoped_ptr
<base::win::MessageWindow
> window_
;
152 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver
);
155 class BatteryStatusManagerWin
: public BatteryStatusManager
{
157 explicit BatteryStatusManagerWin(const BatteryCallback
& callback
)
158 : battery_observer_(new BatteryStatusObserver(callback
)) {}
159 virtual ~BatteryStatusManagerWin() { battery_observer_
->Stop(); }
162 // BatteryStatusManager:
163 virtual bool StartListeningBatteryChange() override
{
164 battery_observer_
->Start();
168 virtual void StopListeningBatteryChange() override
{
169 battery_observer_
->Stop();
173 scoped_ptr
<BatteryStatusObserver
> battery_observer_
;
175 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin
);
180 BatteryStatus
ComputeWebBatteryStatus(const SYSTEM_POWER_STATUS
& win_status
) {
181 BatteryStatus status
;
182 status
.charging
= win_status
.ACLineStatus
!= WIN_AC_LINE_STATUS_OFFLINE
;
184 // Set level if available. Otherwise keep the default value which is 1.
185 if (win_status
.BatteryLifePercent
!= 255) {
186 // Convert percentage to a value between 0 and 1 with 2 significant digits.
187 status
.level
= static_cast<double>(win_status
.BatteryLifePercent
) / 100.;
190 if (!status
.charging
) {
191 // Set discharging_time if available otherwise keep the default value,
192 // which is +Infinity.
193 if (win_status
.BatteryLifeTime
!= (DWORD
)-1)
194 status
.discharging_time
= win_status
.BatteryLifeTime
;
195 status
.charging_time
= std::numeric_limits
<double>::infinity();
197 // Set charging_time to +Infinity if not fully charged, otherwise leave the
198 // default value, which is 0.
199 if (status
.level
< 1)
200 status
.charging_time
= std::numeric_limits
<double>::infinity();
206 scoped_ptr
<BatteryStatusManager
> BatteryStatusManager::Create(
207 const BatteryStatusService::BatteryUpdateCallback
& callback
) {
208 return scoped_ptr
<BatteryStatusManager
>(
209 new BatteryStatusManagerWin(callback
));
212 } // namespace device