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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.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
OLDNEW
« 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