 Chromium Code Reviews
 Chromium Code Reviews Issue 398683006:
  Battery Status API: implementation for Mac OS.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 398683006:
  Battery Status API: implementation for Mac OS.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| (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.h" | |
| 6 | |
| 7 #include <CoreFoundation/CoreFoundation.h> | |
| 8 #include <IOKit/ps/IOPowerSources.h> | |
| 9 #include <IOKit/ps/IOPSKeys.h> | |
| 10 | |
| 11 #include "base/mac/foundation_util.h" | |
| 12 #include "base/mac/scoped_cftyperef.h" | |
| 13 #include "base/memory/ref_counted.h" | |
| 14 #include "base/time/time.h" | |
| 15 #include "content/public/browser/browser_thread.h" | |
| 16 #include "third_party/WebKit/public/platform/WebBatteryStatus.h" | |
| 17 | |
| 18 namespace content { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 typedef const BatteryStatusService::BatteryUpdateCallback BatteryCallback; | |
| 23 | |
| 24 // Returns the value corresponding to |key| in the dictionary |description|. | |
| 25 // Returns |default_value| if the dictionary does not contain |key|, the | |
| 26 // corresponding value is NULL or it could not be converted to CFIndexType. | |
| 27 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
 | |
| 28 CFStringRef key, | |
| 29 CFIndex default_value) { | |
| 30 CFNumberRef number = | |
| 31 base::mac::GetValueFromDictionary<CFNumberRef>(description, key); | |
| 32 CFIndex value; | |
| 33 | |
| 34 if (number && CFNumberGetValue(number, kCFNumberCFIndexType, &value)) | |
| 35 return value; | |
| 36 | |
| 37 return default_value; | |
| 38 } | |
| 39 | |
| 40 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.
 | |
| 41 CFStringRef key, | |
| 42 Boolean default_value) { | |
| 43 CFBooleanRef boolean = | |
| 44 base::mac::GetValueFromDictionary<CFBooleanRef>(description, key); | |
| 45 | |
| 46 return boolean ? CFBooleanGetValue(boolean) : default_value; | |
| 47 } | |
| 48 | |
| 49 static void FetchBatteryStatus(CFDictionaryRef description, | |
| 50 blink::WebBatteryStatus& status) { | |
| 51 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.
 | |
| 52 base::mac::GetValueFromDictionary<CFStringRef>(description, | |
| 53 CFSTR(kIOPSPowerSourceStateKey)); | |
| 54 | |
| 55 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
 | |
| 56 CFSTR(kIOPSBatteryPowerValue), | |
| 57 0) | |
| 58 == kCFCompareEqualTo; | |
| 59 bool is_charging = | |
| 60 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
 | |
| 61 bool is_charged = | |
| 62 GetValueAsBoolean(description, CFSTR(kIOPSIsChargedKey), false); | |
| 63 | |
| 64 // Set charging to false if on battery power and not charging. Otherwise leave | |
| 65 // the default value, which is true. | |
| 66 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
 | |
| 67 status.charging = false; | |
| 68 | |
| 69 CFIndex current_capacity = | |
| 70 GetValueAsCFIndex(description, CFSTR(kIOPSCurrentCapacityKey), -1); | |
| 71 CFIndex max_capacity = | |
| 72 GetValueAsCFIndex(description, CFSTR(kIOPSMaxCapacityKey), -1); | |
| 73 | |
| 74 // Set level if it is available and valid. Otherwise leave the default value, | |
| 75 // which is 1. | |
| 76 if (current_capacity != -1 && max_capacity != -1 && | |
| 77 current_capacity <= max_capacity && max_capacity != 0) | |
| 78 status.level = current_capacity / static_cast<double>(max_capacity); | |
| 79 | |
| 80 if (is_charging) { | |
| 81 CFIndex charging_time = | |
| 82 GetValueAsCFIndex(description, CFSTR(kIOPSTimeToFullChargeKey), -1); | |
| 83 | |
| 84 // Battery is charging: set the charging time if it's available, otherwise | |
| 85 // set to +infinity. | |
| 86 status.chargingTime = (charging_time != -1) | |
| 87 ? base::TimeDelta::FromMinutes(charging_time).InSeconds() | |
| 88 : std::numeric_limits<double>::infinity(); | |
| 89 } else { | |
| 90 // Battery is not charging. | |
| 91 // Set chargingTime to +infinity if the battery is not charged. Otherwise | |
| 92 // leave the default value, which is 0. | |
| 93 if (!is_charged) | |
| 94 status.chargingTime = std::numeric_limits<double>::infinity(); | |
| 95 | |
| 96 // Set dischargingTime if it's available and valid, i.e. when on battery | |
| 97 // power. Otherwise leave the default value, which is +infinity. | |
| 98 if (on_battery_power) { | |
| 99 CFIndex discharging_time = | |
| 100 GetValueAsCFIndex(description, CFSTR(kIOPSTimeToEmptyKey), -1); | |
| 101 if (discharging_time != -1) { | |
| 102 status.dischargingTime = | |
| 103 base::TimeDelta::FromMinutes(discharging_time).InSeconds(); | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 static void OnBatteryStatusChanged(BatteryCallback& callback) { | |
| 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 111 blink::WebBatteryStatus status; | |
| 112 base::ScopedCFTypeRef<CFTypeRef> blob(IOPSCopyPowerSourcesInfo()); | |
| 113 base::ScopedCFTypeRef<CFArrayRef> powerSourcesList( | |
| 
Mark Mentovai
2014/07/24 01:32:22
Naming: power_sources_list.
 
timvolodine
2014/07/24 16:03:19
Done.
 | |
| 114 IOPSCopyPowerSourcesList(blob)); | |
| 115 CFIndex count = CFArrayGetCount(powerSourcesList); | |
| 116 | |
| 117 for (CFIndex i = 0; i < count; ++i) { | |
| 118 CFDictionaryRef description = IOPSGetPowerSourceDescription(blob, | |
| 119 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.
 | |
| 120 | |
| 121 bool battery_present = GetValueAsBoolean(description, | |
| 122 CFSTR(kIOPSIsPresentKey), | |
| 123 false); | |
| 124 | |
| 125 if (!description || !battery_present) | |
| 126 continue; | |
| 127 | |
| 128 FetchBatteryStatus(description, status); | |
| 129 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.
 | |
| 130 } | |
| 131 | |
| 132 callback.Run(status); | |
| 133 } | |
| 134 | |
| 135 class BatteryStatusObserver | |
| 136 : public base::RefCountedThreadSafe<BatteryStatusObserver> { | |
| 137 public: | |
| 138 explicit BatteryStatusObserver(BatteryCallback& callback) | |
| 139 : callback_(callback) {} | |
| 140 | |
| 141 void Start() { | |
| 142 // 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.
 | |
| 143 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 144 StartOnUI(); | |
| 145 } else { | |
| 146 BrowserThread::PostTask( | |
| 147 BrowserThread::UI, | |
| 148 FROM_HERE, | |
| 149 base::Bind(&BatteryStatusObserver::StartOnUI, this)); | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 void Stop() { | |
| 154 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 155 StopOnUI(); | |
| 156 } else { | |
| 157 BrowserThread::PostTask( | |
| 158 BrowserThread::UI, | |
| 159 FROM_HERE, | |
| 160 base::Bind(&BatteryStatusObserver::StopOnUI, this)); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 private: | |
| 165 friend class base::RefCountedThreadSafe<BatteryStatusObserver>; | |
| 166 virtual ~BatteryStatusObserver() { DCHECK(!notifier_run_loop_); } | |
| 167 | |
| 168 void StartOnUI() { | |
| 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 170 | |
| 171 if (notifier_run_loop_) | |
| 172 return; | |
| 173 | |
| 174 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.
 | |
| 175 | |
| 176 notifier_run_loop_.reset( | |
| 177 IOPSNotificationCreateRunLoopSource(OnBatteryStatusChangedUI, | |
| 178 (void*)&callback_)); | |
| 179 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
 | |
| 180 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifier_run_loop_, | |
| 181 kCFRunLoopDefaultMode); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void StopOnUI() { | |
| 186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 187 | |
| 188 if (!notifier_run_loop_) | |
| 189 return; | |
| 190 | |
| 191 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifier_run_loop_, | |
| 192 kCFRunLoopDefaultMode); | |
| 193 notifier_run_loop_.reset(); | |
| 194 } | |
| 195 | |
| 196 static void OnBatteryStatusChangedUI(void* callback) { | |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 198 // Offload fetching of values and callback execution to the IO thread. | |
| 199 BrowserThread::PostTask( | |
| 200 BrowserThread::IO, | |
| 201 FROM_HERE, | |
| 202 base::Bind(&OnBatteryStatusChanged, | |
| 203 *static_cast<BatteryCallback*>(callback))); | |
| 204 } | |
| 205 | |
| 206 BatteryCallback callback_; | |
| 207 base::ScopedCFTypeRef<CFRunLoopSourceRef> notifier_run_loop_; | |
| 208 | |
| 209 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver); | |
| 210 }; | |
| 211 | |
| 212 class BatteryStatusManagerMac : public BatteryStatusManager { | |
| 213 public: | |
| 214 explicit BatteryStatusManagerMac(BatteryCallback& callback) | |
| 215 : notifier_(new BatteryStatusObserver(callback)) {} | |
| 216 | |
| 217 virtual ~BatteryStatusManagerMac() { | |
| 218 notifier_->Stop(); | |
| 219 } | |
| 220 | |
| 221 // BatteryStatusManager: | |
| 222 virtual bool StartListeningBatteryChange() OVERRIDE { | |
| 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 224 notifier_->Start(); | |
| 225 return true; | |
| 226 } | |
| 227 | |
| 228 virtual void StopListeningBatteryChange() OVERRIDE { | |
| 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 230 notifier_->Stop(); | |
| 231 } | |
| 232 | |
| 233 private: | |
| 234 scoped_refptr<BatteryStatusObserver> notifier_; | |
| 235 | |
| 236 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerMac); | |
| 237 }; | |
| 238 | |
| 239 } // end namespace | |
| 240 | |
| 241 // static | |
| 242 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create( | |
| 243 const BatteryStatusService::BatteryUpdateCallback& callback) { | |
| 244 return scoped_ptr<BatteryStatusManager>( | |
| 245 new BatteryStatusManagerMac(callback)); | |
| 246 } | |
| 247 | |
| 248 } // namespace content | |
| OLD | NEW |