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

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

Issue 398683006: Battery Status API: implementation for Mac OS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed comments Created 6 years, 5 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_mac.cc
diff --git a/content/browser/battery_status/battery_status_manager_mac.cc b/content/browser/battery_status/battery_status_manager_mac.cc
new file mode 100644
index 0000000000000000000000000000000000000000..68d7e3b457a556f0e1c831c04aa43c4852a4e0c5
--- /dev/null
+++ b/content/browser/battery_status/battery_status_manager_mac.cc
@@ -0,0 +1,248 @@
+// 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 <CoreFoundation/CoreFoundation.h>
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPSKeys.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/WebBatteryStatus.h"
+
+namespace content {
+
+namespace {
+
+typedef const BatteryStatusService::BatteryUpdateCallback BatteryCallback;
+
+// Returns the value corresponding to |key| in the dictionary |description|.
+// Returns |default_value| if the dictionary does not contain |key|, the
+// corresponding value is NULL or it could not be converted to CFIndexType.
+static CFIndex GetValueAsCFIndex(CFDictionaryRef description,
Mark Mentovai 2014/07/24 01:32:22 This is already in an unnamed namespace, so the st
Mark Mentovai 2014/07/24 01:32:22 Why did you choose CFIndex as the type for the CFN
timvolodine 2014/07/24 16:03:19 Done.
timvolodine 2014/07/24 16:03:19 usually it is kCFNumberSInt64Type, but can also be
Mark Mentovai 2014/07/24 16:08:52 timvolodine wrote:
timvolodine 2014/07/24 16:33:42 yes, my point was that the actual values are small
Mark Mentovai 2014/07/24 17:03:46 timvolodine wrote:
timvolodine 2014/07/25 12:46:08 Ok, changed to SInt32. Technically casting a SInt
Mark Mentovai 2014/07/25 12:57:39 timvolodine wrote:
timvolodine 2014/07/25 13:13:17 right, thanks for the clarification and sorry for
+ CFStringRef key,
+ CFIndex default_value) {
+ CFNumberRef number =
+ base::mac::GetValueFromDictionary<CFNumberRef>(description, key);
+ CFIndex value;
+
+ if (number && CFNumberGetValue(number, kCFNumberCFIndexType, &value))
+ return value;
+
+ return default_value;
+}
+
+static Boolean GetValueAsBoolean(CFDictionaryRef description,
Mark Mentovai 2014/07/24 01:32:21 I think that this should return a bool and take a
timvolodine 2014/07/24 16:03:19 Done.
+ CFStringRef key,
+ Boolean default_value) {
+ CFBooleanRef boolean =
+ base::mac::GetValueFromDictionary<CFBooleanRef>(description, key);
+
+ return boolean ? CFBooleanGetValue(boolean) : default_value;
+}
+
+static void FetchBatteryStatus(CFDictionaryRef description,
+ blink::WebBatteryStatus& status) {
+ CFStringRef currentState =
Mark Mentovai 2014/07/24 01:32:22 Follow the C++ style guide. This should be named c
timvolodine 2014/07/24 16:03:19 Done.
+ base::mac::GetValueFromDictionary<CFStringRef>(description,
+ CFSTR(kIOPSPowerSourceStateKey));
+
+ bool on_battery_power = CFStringCompare(currentState,
Mark Mentovai 2014/07/24 01:32:22 I don’t think this is going to be too happy if cur
timvolodine 2014/07/24 16:03:19 actually kIOPSPowerSourceStateKey is a required ke
+ CFSTR(kIOPSBatteryPowerValue),
+ 0)
+ == kCFCompareEqualTo;
+ bool is_charging =
+ GetValueAsBoolean(description, CFSTR(kIOPSIsChargingKey), true);
Mark Mentovai 2014/07/24 01:32:22 Is true the best default here? I probably would ha
timvolodine 2014/07/24 16:03:19 kIOPSIsChargingKey is also required so hopefully n
+ bool is_charged =
+ GetValueAsBoolean(description, CFSTR(kIOPSIsChargedKey), false);
+
+ // Set charging to false if on battery power and not charging. Otherwise leave
+ // the default value, which is true.
+ if (on_battery_power && !is_charging)
Mark Mentovai 2014/07/24 01:32:22 Why not avoid the conditional and set this explici
timvolodine 2014/07/24 16:03:19 Done. Re other fields: normally speaking the idea
+ status.charging = false;
+
+ CFIndex current_capacity =
+ GetValueAsCFIndex(description, CFSTR(kIOPSCurrentCapacityKey), -1);
+ CFIndex max_capacity =
+ GetValueAsCFIndex(description, CFSTR(kIOPSMaxCapacityKey), -1);
+
+ // Set level if it is available and valid. Otherwise leave the default value,
+ // which is 1.
+ if (current_capacity != -1 && max_capacity != -1 &&
+ current_capacity <= max_capacity && max_capacity != 0)
+ status.level = current_capacity / static_cast<double>(max_capacity);
+
+ if (is_charging) {
+ CFIndex charging_time =
+ GetValueAsCFIndex(description, CFSTR(kIOPSTimeToFullChargeKey), -1);
+
+ // Battery is charging: set the charging time if it's available, otherwise
+ // set to +infinity.
+ status.chargingTime = (charging_time != -1)
+ ? base::TimeDelta::FromMinutes(charging_time).InSeconds()
+ : std::numeric_limits<double>::infinity();
+ } else {
+ // Battery is not charging.
+ // Set chargingTime to +infinity if the battery is not charged. Otherwise
+ // leave the default value, which is 0.
+ if (!is_charged)
+ status.chargingTime = std::numeric_limits<double>::infinity();
+
+ // Set dischargingTime if it's available and valid, i.e. when on battery
+ // power. Otherwise leave the default value, which is +infinity.
+ if (on_battery_power) {
+ CFIndex discharging_time =
+ GetValueAsCFIndex(description, CFSTR(kIOPSTimeToEmptyKey), -1);
+ if (discharging_time != -1) {
+ status.dischargingTime =
+ base::TimeDelta::FromMinutes(discharging_time).InSeconds();
+ }
+ }
+ }
+}
+
+static void OnBatteryStatusChanged(BatteryCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ blink::WebBatteryStatus status;
+ base::ScopedCFTypeRef<CFTypeRef> blob(IOPSCopyPowerSourcesInfo());
+ base::ScopedCFTypeRef<CFArrayRef> powerSourcesList(
Mark Mentovai 2014/07/24 01:32:22 Naming: power_sources_list.
timvolodine 2014/07/24 16:03:19 Done.
+ IOPSCopyPowerSourcesList(blob));
+ CFIndex count = CFArrayGetCount(powerSourcesList);
+
+ for (CFIndex i = 0; i < count; ++i) {
+ CFDictionaryRef description = IOPSGetPowerSourceDescription(blob,
+ CFArrayGetValueAtIndex(powerSourcesList, i));
Mark Mentovai 2014/07/24 01:32:21 if (!description) continue; can go here, you
timvolodine 2014/07/24 16:03:19 Done.
+
+ bool battery_present = GetValueAsBoolean(description,
+ CFSTR(kIOPSIsPresentKey),
+ false);
+
+ if (!description || !battery_present)
+ continue;
+
+ FetchBatteryStatus(description, status);
+ break;
Mark Mentovai 2014/07/24 01:32:22 In theory, there can be more than one battery. If
timvolodine 2014/07/24 16:03:19 that's right, I've added a comment. I am reluctant
Mark Mentovai 2014/07/24 16:08:52 timvolodine wrote:
timvolodine 2014/07/24 16:33:42 the current specification does not strictly impose
Mark Mentovai 2014/07/24 17:03:46 timvolodine wrote:
timvolodine 2014/07/25 12:46:08 Done.
+ }
+
+ callback.Run(status);
+}
+
+class BatteryStatusObserver
+ : public base::RefCountedThreadSafe<BatteryStatusObserver> {
+ public:
+ explicit BatteryStatusObserver(BatteryCallback& callback)
+ : callback_(callback) {}
+
+ void Start() {
+ // Need thread with UI-type message loop for notifications to run.
Mark Mentovai 2014/07/24 01:32:21 If you added two more words here, it’d be a comple
timvolodine 2014/07/24 16:03:19 Done.
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StartOnUI();
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&BatteryStatusObserver::StartOnUI, this));
+ }
+ }
+
+ void Stop() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StopOnUI();
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&BatteryStatusObserver::StopOnUI, this));
+ }
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<BatteryStatusObserver>;
+ virtual ~BatteryStatusObserver() { DCHECK(!notifier_run_loop_); }
+
+ void StartOnUI() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (notifier_run_loop_)
+ return;
+
+ OnBatteryStatusChangedUI((void*)&callback_);
Mark Mentovai 2014/07/24 01:32:22 Use cplusplus<style>(casts). See the style guide.
timvolodine 2014/07/24 16:03:19 Done.
+
+ notifier_run_loop_.reset(
+ IOPSNotificationCreateRunLoopSource(OnBatteryStatusChangedUI,
+ (void*)&callback_));
+ if (notifier_run_loop_) {
Mark Mentovai 2014/07/24 01:32:22 Do you need this conditional? If IOPSNotificationC
timvolodine 2014/07/24 16:03:19 I think we should avoid crashing the browser, inst
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), notifier_run_loop_,
+ kCFRunLoopDefaultMode);
+ }
+ }
+
+ void StopOnUI() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!notifier_run_loop_)
+ return;
+
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifier_run_loop_,
+ kCFRunLoopDefaultMode);
+ notifier_run_loop_.reset();
+ }
+
+ static void OnBatteryStatusChangedUI(void* callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Offload fetching of values and callback execution to the IO thread.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&OnBatteryStatusChanged,
+ *static_cast<BatteryCallback*>(callback)));
+ }
+
+ BatteryCallback callback_;
+ base::ScopedCFTypeRef<CFRunLoopSourceRef> notifier_run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver);
+};
+
+class BatteryStatusManagerMac : public BatteryStatusManager {
+ public:
+ explicit BatteryStatusManagerMac(BatteryCallback& callback)
+ : notifier_(new BatteryStatusObserver(callback)) {}
+
+ virtual ~BatteryStatusManagerMac() {
+ notifier_->Stop();
+ }
+
+ // BatteryStatusManager:
+ virtual bool StartListeningBatteryChange() OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ notifier_->Start();
+ return true;
+ }
+
+ virtual void StopListeningBatteryChange() OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ notifier_->Stop();
+ }
+
+ private:
+ scoped_refptr<BatteryStatusObserver> notifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerMac);
+};
+
+} // end namespace
+
+// static
+scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
+ const BatteryStatusService::BatteryUpdateCallback& callback) {
+ return scoped_ptr<BatteryStatusManager>(
+ new BatteryStatusManagerMac(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