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

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

Issue 685703002: Reland "Replace Chrome IPC with Mojo IPC for querying BatteryStatus service" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Tim's comments. Created 6 years, 1 month 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
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_win.h"
6
7 #include "base/memory/ref_counted.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string16.h"
10 #include "base/win/message_window.h"
11 #include "base/win/windows_version.h"
12 #include "content/browser/battery_status/battery_status_manager.h"
13 #include "content/public/browser/browser_thread.h"
14
15 namespace content {
16
17 namespace {
18
19 typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback;
20
21 const wchar_t kWindowClassName[] = L"BatteryStatusMessageWindow";
22
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,
30 };
31
32 void UpdateNumberBatteriesHistogram(NumberBatteriesType count) {
33 UMA_HISTOGRAM_ENUMERATION("BatteryStatus.NumberBatteriesWin",
34 count,
35 BATTERY_TYPES_COUNT);
36 }
37
38 void UpdateNumberBatteriesHistogram() {
39 SYSTEM_POWER_STATUS win_status;
40 if (!GetSystemPowerStatus(&win_status)) {
41 UpdateNumberBatteriesHistogram(UNKNOWN_BATTERIES);
42 return;
43 }
44
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);
51 }
52
53 // Message-only window for handling battery changes on Windows.
54 class BatteryStatusObserver
55 : public base::RefCountedThreadSafe<BatteryStatusObserver> {
56 public:
57 explicit BatteryStatusObserver(const BatteryCallback& callback)
58 : power_handle_(NULL),
59 battery_change_handle_(NULL),
60 callback_(callback) {
61 }
62
63 virtual ~BatteryStatusObserver() { DCHECK(!window_); }
64
65 void Start() {
66 // Need to start on the UI thread to receive battery status notifications.
67 BrowserThread::PostTask(
68 BrowserThread::UI,
69 FROM_HERE,
70 base::Bind(&BatteryStatusObserver::StartOnUI, this));
71 }
72
73 void Stop() {
74 BrowserThread::PostTask(
75 BrowserThread::UI,
76 FROM_HERE,
77 base::Bind(&BatteryStatusObserver::StopOnUI, this));
78 }
79
80 private:
81 void StartOnUI() {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83 if (window_)
84 return;
85
86 if (CreateMessageWindow()) {
87 BatteryChanged();
88 // RegisterPowerSettingNotification function work from Windows Vista
89 // onwards. However even without them we will receive notifications,
90 // e.g. when a power source is connected.
91 // TODO(timvolodine) : consider polling for battery changes on windows
92 // versions prior to Vista, see crbug.com/402466.
93 power_handle_ =
94 RegisterNotification(&GUID_ACDC_POWER_SOURCE);
95 battery_change_handle_ =
96 RegisterNotification(&GUID_BATTERY_PERCENTAGE_REMAINING);
97 } else {
98 // Could not create a message window, execute callback with the default
99 // values.
100 callback_.Run(blink::WebBatteryStatus());
101 }
102
103 UpdateNumberBatteriesHistogram();
104 }
105
106 void StopOnUI() {
107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
108 if (!window_)
109 return;
110
111 if (power_handle_)
112 UnregisterNotification(power_handle_);
113 if (battery_change_handle_)
114 UnregisterNotification(battery_change_handle_);
115 window_.reset();
116 }
117
118 void BatteryChanged() {
119 SYSTEM_POWER_STATUS win_status;
120 if (GetSystemPowerStatus(&win_status))
121 callback_.Run(ComputeWebBatteryStatus(win_status));
122 else
123 callback_.Run(blink::WebBatteryStatus());
124 }
125
126 bool HandleMessage(UINT message,
127 WPARAM wparam,
128 LPARAM lparam,
129 LRESULT* result) {
130 switch(message) {
131 case WM_POWERBROADCAST:
132 if (wparam == PBT_APMPOWERSTATUSCHANGE ||
133 wparam == PBT_POWERSETTINGCHANGE) {
134 BatteryChanged();
135 }
136 *result = NULL;
137 return true;
138 default:
139 return false;
140 }
141 }
142
143 HPOWERNOTIFY RegisterNotification(LPCGUID power_setting) {
144 if (base::win::GetVersion() < base::win::VERSION_VISTA)
145 return NULL;
146
147 return RegisterPowerSettingNotification(window_->hwnd(), power_setting,
148 DEVICE_NOTIFY_WINDOW_HANDLE);
149 }
150
151 BOOL UnregisterNotification(HPOWERNOTIFY handle) {
152 if (base::win::GetVersion() < base::win::VERSION_VISTA)
153 return FALSE;
154
155 return UnregisterPowerSettingNotification(handle);
156 }
157
158 bool CreateMessageWindow() {
159 // TODO(timvolodine): consider reusing the message window of PowerMonitor.
160 window_.reset(new base::win::MessageWindow());
161 if (!window_->CreateNamed(base::Bind(&BatteryStatusObserver::HandleMessage,
162 base::Unretained(this)),
163 base::string16(kWindowClassName))) {
164 LOG(ERROR) << "Failed to create message window: " << kWindowClassName;
165 window_.reset();
166 return false;
167 }
168 return true;
169 }
170
171 HPOWERNOTIFY power_handle_;
172 HPOWERNOTIFY battery_change_handle_;
173 BatteryCallback callback_;
174 scoped_ptr<base::win::MessageWindow> window_;
175
176 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver);
177 };
178
179 class BatteryStatusManagerWin : public BatteryStatusManager {
180 public:
181 explicit BatteryStatusManagerWin(const BatteryCallback& callback)
182 : battery_observer_(new BatteryStatusObserver(callback)) {}
183 virtual ~BatteryStatusManagerWin() { battery_observer_->Stop(); }
184
185 public:
186 // BatteryStatusManager:
187 virtual bool StartListeningBatteryChange() override {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
189 battery_observer_->Start();
190 return true;
191 }
192
193 virtual void StopListeningBatteryChange() override {
194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
195 battery_observer_->Stop();
196 }
197
198 private:
199 scoped_refptr<BatteryStatusObserver> battery_observer_;
200
201 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin);
202 };
203
204 } // namespace
205
206 blink::WebBatteryStatus ComputeWebBatteryStatus(
207 const SYSTEM_POWER_STATUS& win_status) {
208 blink::WebBatteryStatus status;
209 status.charging = win_status.ACLineStatus != WIN_AC_LINE_STATUS_OFFLINE;
210
211 // Set level if available. Otherwise keep the default value which is 1.
212 if (win_status.BatteryLifePercent != 255) {
213 // Convert percentage to a value between 0 and 1 with 2 significant digits.
214 status.level = static_cast<double>(win_status.BatteryLifePercent) / 100.;
215 }
216
217 if (!status.charging) {
218 // Set dischargingTime if available otherwise keep the default value,
219 // which is +Infinity.
220 if (win_status.BatteryLifeTime != (DWORD)-1)
221 status.dischargingTime = win_status.BatteryLifeTime;
222 status.chargingTime = std::numeric_limits<double>::infinity();
223 } else {
224 // Set chargingTime to +Infinity if not fully charged, otherwise leave the
225 // default value, which is 0.
226 if (status.level < 1)
227 status.chargingTime = std::numeric_limits<double>::infinity();
228 }
229 return status;
230 }
231
232 // static
233 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
234 const BatteryStatusService::BatteryUpdateCallback& callback) {
235 return scoped_ptr<BatteryStatusManager>(
236 new BatteryStatusManagerWin(callback));
237 }
238
239 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698