Tighten DCHECK to clarify that users of syncable storage can't request more quota.
[chromium-blink-merge.git] / device / battery / battery_status_manager_win.cc
blob6ad13da8a4b6e68c2711d6271d69eb4ba622a4eb
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"
7 #include "base/bind.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"
15 namespace device {
17 namespace {
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
24 // values.
25 enum NumberBatteriesType {
26 UNKNOWN_BATTERIES = 0,
27 NO_BATTERY = 1,
28 ONE_OR_MORE_BATTERIES = 2,
29 BATTERY_TYPES_COUNT = 3,
32 void UpdateNumberBatteriesHistogram(NumberBatteriesType count) {
33 UMA_HISTOGRAM_ENUMERATION("BatteryStatus.NumberBatteriesWin",
34 count,
35 BATTERY_TYPES_COUNT);
38 void UpdateNumberBatteriesHistogram() {
39 SYSTEM_POWER_STATUS win_status;
40 if (!GetSystemPowerStatus(&win_status)) {
41 UpdateNumberBatteriesHistogram(UNKNOWN_BATTERIES);
42 return;
45 if (win_status.BatteryFlag == 255)
46 UpdateNumberBatteriesHistogram(UNKNOWN_BATTERIES);
47 else if (win_status.BatteryFlag == 128)
48 UpdateNumberBatteriesHistogram(NO_BATTERY);
49 else
50 UpdateNumberBatteriesHistogram(ONE_OR_MORE_BATTERIES);
53 // Message-only window for handling battery changes on Windows.
54 class BatteryStatusObserver {
55 public:
56 explicit BatteryStatusObserver(const BatteryCallback& callback)
57 : power_handle_(NULL),
58 battery_change_handle_(NULL),
59 callback_(callback) {
62 ~BatteryStatusObserver() { DCHECK(!window_); }
64 void Start() {
65 if (CreateMessageWindow()) {
66 BatteryChanged();
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.
72 power_handle_ =
73 RegisterNotification(&GUID_ACDC_POWER_SOURCE);
74 battery_change_handle_ =
75 RegisterNotification(&GUID_BATTERY_PERCENTAGE_REMAINING);
76 } else {
77 // Could not create a message window, execute callback with the default
78 // values.
79 callback_.Run(BatteryStatus());
82 UpdateNumberBatteriesHistogram();
85 void Stop() {
86 if (power_handle_) {
87 UnregisterNotification(power_handle_);
88 power_handle_ = NULL;
90 if (battery_change_handle_) {
91 UnregisterNotification(battery_change_handle_);
92 battery_change_handle_ = NULL;
94 window_.reset();
97 private:
98 void BatteryChanged() {
99 SYSTEM_POWER_STATUS win_status;
100 if (GetSystemPowerStatus(&win_status))
101 callback_.Run(ComputeWebBatteryStatus(win_status));
102 else
103 callback_.Run(BatteryStatus());
106 bool HandleMessage(UINT message,
107 WPARAM wparam,
108 LPARAM lparam,
109 LRESULT* result) {
110 switch(message) {
111 case WM_POWERBROADCAST:
112 if (wparam == PBT_APMPOWERSTATUSCHANGE ||
113 wparam == PBT_POWERSETTINGCHANGE) {
114 BatteryChanged();
116 *result = NULL;
117 return true;
118 default:
119 return false;
123 HPOWERNOTIFY RegisterNotification(LPCGUID power_setting) {
124 if (base::win::GetVersion() < base::win::VERSION_VISTA)
125 return NULL;
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)
133 return FALSE;
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;
145 window_.reset();
146 return false;
148 return true;
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 {
160 public:
161 explicit BatteryStatusManagerWin(const BatteryCallback& callback)
162 : battery_observer_(new BatteryStatusObserver(callback)) {}
163 virtual ~BatteryStatusManagerWin() { battery_observer_->Stop(); }
165 public:
166 // BatteryStatusManager:
167 virtual bool StartListeningBatteryChange() override {
168 battery_observer_->Start();
169 return true;
172 virtual void StopListeningBatteryChange() override {
173 battery_observer_->Stop();
176 private:
177 scoped_ptr<BatteryStatusObserver> battery_observer_;
179 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin);
182 } // namespace
184 BatteryStatus ComputeWebBatteryStatus(const SYSTEM_POWER_STATUS& win_status) {
185 BatteryStatus status;
186 status.charging = win_status.ACLineStatus != WIN_AC_LINE_STATUS_OFFLINE;
188 // Set level if available. Otherwise keep the default value which is 1.
189 if (win_status.BatteryLifePercent != 255) {
190 // Convert percentage to a value between 0 and 1 with 2 significant digits.
191 status.level = static_cast<double>(win_status.BatteryLifePercent) / 100.;
194 if (!status.charging) {
195 // Set discharging_time if available otherwise keep the default value,
196 // which is +Infinity.
197 if (win_status.BatteryLifeTime != (DWORD)-1)
198 status.discharging_time = win_status.BatteryLifeTime;
199 status.charging_time = std::numeric_limits<double>::infinity();
200 } else {
201 // Set charging_time to +Infinity if not fully charged, otherwise leave the
202 // default value, which is 0.
203 if (status.level < 1)
204 status.charging_time = std::numeric_limits<double>::infinity();
206 return status;
209 // static
210 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
211 const BatteryStatusService::BatteryUpdateCallback& callback) {
212 return scoped_ptr<BatteryStatusManager>(
213 new BatteryStatusManagerWin(callback));
216 } // namespace device