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

Unified Diff: content/browser/battery_status/battery_status_manager_win.cc

Issue 447853002: Battery Status API: implementation for Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/battery_status/battery_status_manager_win.cc
diff --git a/content/browser/battery_status/battery_status_manager_win.cc b/content/browser/battery_status/battery_status_manager_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d64b80d1efbb3c254726cd818d69e97b7a569885
--- /dev/null
+++ b/content/browser/battery_status/battery_status_manager_win.cc
@@ -0,0 +1,232 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/battery_status/battery_status_manager.h"
+
+#include <windows.h>
+#include "base/memory/ref_counted.h"
+#include "base/win/windows_version.h"
+#include "base/win/wrapped_window_proc.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/WebBatteryStatus.h"
+
+namespace content {
+
+namespace {
+
+typedef BatteryStatusService::BatteryUpdateCallback BatteryCallback;
+
+const wchar_t kWindowClassName[] = L"BatteryStatusMessageWindow";
+
+void ComputeWebBatteryStatus(const SYSTEM_POWER_STATUS& win_status,
+ blink::WebBatteryStatus& status) {
+ bool on_battery = win_status.ACLineStatus == 0;
+ status.charging = !on_battery; // not offline
mlamouri (slow - plz ping) 2014/08/07 16:40:47 Couldn't you do: status.charging = win_status.ACL
timvolodine 2014/08/11 19:43:41 Done.
+ // Set level if available. Otherwise keep the default value which is 1.
+ if (win_status.BatteryLifePercent != 255) {
+ // Convert percentage to a value between 0 and 1 with 3 significant digits.
+ status.level = round(win_status.BatteryLifePercent * 10) / 1000.f;
+ }
+ if (on_battery) {
+ // Set dischargingTime if available otherwise keep the default value,
+ // which is +Infinity.
+ if (win_status.BatteryLifeTime != -1)
+ status.dischargingTime = win_status.BatteryLifeTime;
+ status.chargingTime = std::numeric_limits<double>::infinity();
+ } else {
+ // Set chargingTime to +Infinity if not fully charged, otherwise leave the
+ // default value, which is 0.
+ if (status.level < 1)
+ status.chargingTime = std::numeric_limits<double>::infinity();
mlamouri (slow - plz ping) 2014/08/07 16:40:47 Can't you use status.BatteryFullLifeTime?
timvolodine 2014/08/11 19:43:41 according to the documentation BatteryFullLifeTime
+ }
+}
+
+// Message-only window for handling battery changes on Windows.
+class BatteryStatusObserver
+ : public base::RefCountedThreadSafe<BatteryStatusObserver> {
+ public:
+ explicit BatteryStatusObserver(const BatteryCallback& callback)
+ : register_func_(NULL),
+ unregister_func_(NULL),
+ instance_(NULL),
+ message_hwnd_(NULL),
+ power_handle_(NULL),
+ battery_change_handle_(NULL),
+ callback_(callback) {
+ InitPowerSettingFunctions();
+ }
+
+ virtual ~BatteryStatusObserver() { DCHECK(!message_hwnd_); }
+
+ void Start() {
+ // Need to start on the UI thread to receive battery status notifications.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&BatteryStatusObserver::StartOnUI, this));
+ }
+
+ void Stop() {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&BatteryStatusObserver::StopOnUI, this));
+ }
+
+ private:
+
+ void StartOnUI() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (message_hwnd_)
+ return;
+
+ if (CreateMessageWindow()) {
+ BatteryChanged();
+ // RegisterPowerSettingNotification function work from Windows Vista
+ // onwards. However even without them we will receive notifications,
+ // e.g. when a power source is connected.
+ power_handle_ =
+ RegisterPowerSettingNotification(&GUID_ACDC_POWER_SOURCE);
+ battery_change_handle_ =
+ RegisterPowerSettingNotification(&GUID_BATTERY_PERCENTAGE_REMAINING);
+ } else {
+ // Could not create a message window, execute callback with the default
+ // values.
+ callback_.Run(blink::WebBatteryStatus());
+ }
+
+ }
+
+ void StopOnUI() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!message_hwnd_)
+ return;
+
+ if (power_handle_)
+ UnregisterPowerSettingNotification(power_handle_);
+ if (battery_change_handle_)
+ UnregisterPowerSettingNotification(battery_change_handle_);
+ DestroyWindow(message_hwnd_);
+ UnregisterClass(kWindowClassName, instance_);
+ message_hwnd_ = NULL;
+ }
+
+ static LRESULT CALLBACK WndProcThunk(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ BatteryStatusObserver* msg_wnd = reinterpret_cast<BatteryStatusObserver*>(
+ GetWindowLongPtr(hwnd, GWLP_USERDATA));
+ switch(message) {
+ case WM_POWERBROADCAST:
+ if (wparam == PBT_APMPOWERSTATUSCHANGE ||
+ wparam == PBT_POWERSETTINGCHANGE) {
+ msg_wnd->BatteryChanged();
+ }
+ return true;
+ default:
+ return ::DefWindowProc(hwnd, message, wparam, lparam);
+ }
+ }
+
+ void BatteryChanged() {
+ blink::WebBatteryStatus status;
+ SYSTEM_POWER_STATUS win_status;
+ if (GetSystemPowerStatus(&win_status))
+ ComputeWebBatteryStatus(win_status, status);
+
+ callback_.Run(status);
+ }
+
+ HPOWERNOTIFY RegisterPowerSettingNotification(LPCGUID power_setting) {
+ return register_func_ ? register_func_(message_hwnd_, power_setting,
+ DEVICE_NOTIFY_WINDOW_HANDLE)
+ : NULL;
+ }
+
+ BOOL UnregisterPowerSettingNotification(HPOWERNOTIFY handle) {
+ return unregister_func_ ? unregister_func_(handle) : FALSE;
+ }
+
+ void InitPowerSettingFunctions() {
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return;
mlamouri (slow - plz ping) 2014/08/07 16:40:47 If that means that we don't get any event before V
timvolodine 2014/08/11 19:43:41 Done. added a crbug.
+
+ HMODULE user32 = GetModuleHandleA("user32.dll");
scottmg 2014/08/08 21:32:19 I believe user32 is delayload, so you can just run
timvolodine 2014/08/11 19:43:41 Done.
+ register_func_ = reinterpret_cast<RegisterPowerSettingNotificationFunc>(
+ GetProcAddress(user32, "RegisterPowerSettingNotification"));
+ unregister_func_ = reinterpret_cast<UnregisterPowerSettingNotificationFunc>(
+ GetProcAddress(user32, "UnregisterPowerSettingNotification"));
+ DCHECK(register_func_ && unregister_func_);
+ }
+
+ bool CreateMessageWindow() {
scottmg 2014/08/08 21:32:19 can we use base::win::MessageWindow here?
timvolodine 2014/08/11 19:43:41 yes. thanks for noticing this, done.
+ WNDCLASSEX window_class;
+ base::win::InitializeWindowClass(kWindowClassName,
+ &base::win::WrappedWindowProc<BatteryStatusObserver::WndProcThunk>,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, &window_class);
+ instance_ = window_class.hInstance;
+ ATOM clazz = RegisterClassEx(&window_class);
+ DCHECK(clazz);
+ message_hwnd_ = CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName,
+ NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance_, NULL);
+ if (!message_hwnd_)
+ return false;
+ SetWindowLongPtr(message_hwnd_, GWLP_USERDATA,
+ reinterpret_cast<LONG_PTR>(this));
+ return true;
+ }
+
+ typedef HPOWERNOTIFY (WINAPI* RegisterPowerSettingNotificationFunc)
+ (HANDLE recipient, LPCGUID id, DWORD flags);
+ RegisterPowerSettingNotificationFunc register_func_;
+
+ typedef BOOL (WINAPI* UnregisterPowerSettingNotificationFunc)
+ (HPOWERNOTIFY handle);
+ UnregisterPowerSettingNotificationFunc unregister_func_;
+
+ HMODULE instance_;
+ HWND message_hwnd_;
+ HPOWERNOTIFY power_handle_;
+ HPOWERNOTIFY battery_change_handle_;
+ BatteryCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver);
+};
+
+class BatteryStatusManagerWin : public BatteryStatusManager {
+ public:
+ explicit BatteryStatusManagerWin(const BatteryCallback& callback)
+ : battery_observer_(new BatteryStatusObserver(callback)) {}
+ virtual ~BatteryStatusManagerWin() { battery_observer_->Stop(); }
+
+ public:
+ // BatteryStatusManager:
+ virtual bool StartListeningBatteryChange() OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ battery_observer_->Start();
+ return true;
+ }
+
+ virtual void StopListeningBatteryChange() OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ battery_observer_->Stop();
+ }
+
+ private:
+ scoped_refptr<BatteryStatusObserver> battery_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerWin);
+};
+
+} // namespace
+
+// static
+scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
+ const BatteryStatusService::BatteryUpdateCallback& callback) {
+ return scoped_ptr<BatteryStatusManager>(
+ new BatteryStatusManagerWin(callback));
+}
+
+} // namespace content
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698