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_
);
90 if (battery_change_handle_
) {
91 UnregisterNotification(battery_change_handle_
);
92 battery_change_handle_
= NULL
;
98 void BatteryChanged() {
99 SYSTEM_POWER_STATUS win_status
;
100 if (GetSystemPowerStatus(&win_status
))
101 callback_
.Run(ComputeWebBatteryStatus(win_status
));
103 callback_
.Run(BatteryStatus());
106 bool HandleMessage(UINT message
,
111 case WM_POWERBROADCAST
:
112 if (wparam
== PBT_APMPOWERSTATUSCHANGE
||
113 wparam
== PBT_POWERSETTINGCHANGE
) {
123 HPOWERNOTIFY
RegisterNotification(LPCGUID power_setting
) {
124 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
127 return RegisterPowerSettingNotification(window_
->hwnd(), power_setting
,
128 DEVICE_NOTIFY_WINDOW_HANDLE
);
131 BOOL
UnregisterNotification(HPOWERNOTIFY handle
) {
132 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
135 return UnregisterPowerSettingNotification(handle
);
138 bool CreateMessageWindow() {
139 // TODO(timvolodine): consider reusing the message window of PowerMonitor.
140 window_
.reset(new base::win::MessageWindow());
141 if (!window_
->CreateNamed(base::Bind(&BatteryStatusObserver::HandleMessage
,
142 base::Unretained(this)),
143 base::string16(kWindowClassName
))) {
144 LOG(ERROR
) << "Failed to create message window: " << kWindowClassName
;
151 HPOWERNOTIFY power_handle_
;
152 HPOWERNOTIFY battery_change_handle_
;
153 BatteryCallback callback_
;
154 scoped_ptr
<base::win::MessageWindow
> window_
;
156 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver
);
159 class BatteryStatusManagerWin
: public BatteryStatusManager
{
161 explicit BatteryStatusManagerWin(const BatteryCallback
& callback
)
162 : battery_observer_(new BatteryStatusObserver(callback
)) {}
163 ~BatteryStatusManagerWin() override
{ battery_observer_
->Stop(); }
166 // BatteryStatusManager:
167 bool StartListeningBatteryChange() override
{
168 battery_observer_
->Start();
172 void StopListeningBatteryChange() override
{ battery_observer_
->Stop(); }
175 scoped_ptr
<BatteryStatusObserver
> battery_observer_
;
177 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin
);
182 BatteryStatus
ComputeWebBatteryStatus(const SYSTEM_POWER_STATUS
& win_status
) {
183 BatteryStatus status
;
184 status
.charging
= win_status
.ACLineStatus
!= WIN_AC_LINE_STATUS_OFFLINE
;
186 // Set level if available. Otherwise keep the default value which is 1.
187 if (win_status
.BatteryLifePercent
!= 255) {
188 // Convert percentage to a value between 0 and 1 with 2 significant digits.
189 status
.level
= static_cast<double>(win_status
.BatteryLifePercent
) / 100.;
192 if (!status
.charging
) {
193 // Set discharging_time if available otherwise keep the default value,
194 // which is +Infinity.
195 if (win_status
.BatteryLifeTime
!= (DWORD
)-1)
196 status
.discharging_time
= win_status
.BatteryLifeTime
;
197 status
.charging_time
= std::numeric_limits
<double>::infinity();
199 // Set charging_time to +Infinity if not fully charged, otherwise leave the
200 // default value, which is 0.
201 if (status
.level
< 1)
202 status
.charging_time
= std::numeric_limits
<double>::infinity();
208 scoped_ptr
<BatteryStatusManager
> BatteryStatusManager::Create(
209 const BatteryStatusService::BatteryUpdateCallback
& callback
) {
210 return scoped_ptr
<BatteryStatusManager
>(
211 new BatteryStatusManagerWin(callback
));
214 } // namespace device