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

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: SInt32 -> SInt64 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 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 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 SInt64.
27 SInt64 GetValueAsSInt64(CFDictionaryRef description,
28 CFStringRef key,
29 SInt64 default_value) {
30 CFNumberRef number =
31 base::mac::GetValueFromDictionary<CFNumberRef>(description, key);
32 SInt64 value;
33
34 if (number && CFNumberGetValue(number, kCFNumberSInt64Type, &value))
35 return value;
36
37 return default_value;
38 }
39
40 bool GetValueAsBoolean(CFDictionaryRef description,
41 CFStringRef key,
42 bool default_value) {
43 CFBooleanRef boolean =
44 base::mac::GetValueFromDictionary<CFBooleanRef>(description, key);
45
46 return boolean ? CFBooleanGetValue(boolean) : default_value;
47 }
48
49 bool CFStringsAreEqual(CFStringRef string1, CFStringRef string2) {
50 if (!string1 || !string2)
51 return false;
52 return CFStringCompare(string1, string2, 0) == kCFCompareEqualTo;
53 }
54
55 void FetchBatteryStatus(CFDictionaryRef description,
56 blink::WebBatteryStatus& status) {
57 CFStringRef current_state =
58 base::mac::GetValueFromDictionary<CFStringRef>(description,
59 CFSTR(kIOPSPowerSourceStateKey));
60
61 bool on_battery_power =
62 CFStringsAreEqual(current_state, CFSTR(kIOPSBatteryPowerValue));
63 bool is_charging =
64 GetValueAsBoolean(description, CFSTR(kIOPSIsChargingKey), true);
Robert Sesek 2014/07/25 14:48:44 Why assume charging?
timvolodine 2014/07/25 18:17:51 kIOPSIsChargingKey is a required key so this shoul
65 bool is_charged =
66 GetValueAsBoolean(description, CFSTR(kIOPSIsChargedKey), false);
67
68 status.charging = !on_battery_power || is_charging;
69
70 SInt64 current_capacity =
71 GetValueAsSInt64(description, CFSTR(kIOPSCurrentCapacityKey), -1);
72 SInt64 max_capacity =
73 GetValueAsSInt64(description, CFSTR(kIOPSMaxCapacityKey), -1);
74
75 // Set level if it is available and valid. Otherwise leave the default value,
76 // which is 1.
77 if (current_capacity != -1 && max_capacity != -1 &&
78 current_capacity <= max_capacity && max_capacity != 0)
79 status.level = current_capacity / static_cast<double>(max_capacity);
Robert Sesek 2014/07/25 14:48:44 nit: this body requires braces since the condition
timvolodine 2014/07/25 18:17:51 Done.
80
81 if (is_charging) {
82 SInt64 charging_time =
83 GetValueAsSInt64(description, CFSTR(kIOPSTimeToFullChargeKey), -1);
84
85 // Battery is charging: set the charging time if it's available, otherwise
86 // set to +infinity.
87 status.chargingTime = (charging_time != -1)
88 ? base::TimeDelta::FromMinutes(charging_time).InSeconds()
89 : std::numeric_limits<double>::infinity();
90 } else {
91 // Battery is not charging.
92 // Set chargingTime to +infinity if the battery is not charged. Otherwise
93 // leave the default value, which is 0.
94 if (!is_charged)
95 status.chargingTime = std::numeric_limits<double>::infinity();
96
97 // Set dischargingTime if it's available and valid, i.e. when on battery
98 // power. Otherwise leave the default value, which is +infinity.
99 if (on_battery_power) {
100 SInt64 discharging_time =
101 GetValueAsSInt64(description, CFSTR(kIOPSTimeToEmptyKey), -1);
102 if (discharging_time != -1) {
103 status.dischargingTime =
104 base::TimeDelta::FromMinutes(discharging_time).InSeconds();
105 }
106 }
107 }
108 }
109
110 void OnBatteryStatusChanged(const BatteryCallback& callback) {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
112 blink::WebBatteryStatus status;
113 base::ScopedCFTypeRef<CFTypeRef> info(IOPSCopyPowerSourcesInfo());
114 base::ScopedCFTypeRef<CFArrayRef> power_sources_list(
115 IOPSCopyPowerSourcesList(info));
116 CFIndex count = CFArrayGetCount(power_sources_list);
117
118 bool internal_source_found = false;
119
120 for (CFIndex i = 0; i < count; ++i) {
121 CFDictionaryRef description = IOPSGetPowerSourceDescription(info,
122 CFArrayGetValueAtIndex(power_sources_list, i));
123
124 if (!description)
125 continue;
126
127 CFStringRef transport_type =
128 base::mac::GetValueFromDictionary<CFStringRef>(description,
129 CFSTR(kIOPSTransportTypeKey));
130
131 bool internal_source =
132 CFStringsAreEqual(transport_type, CFSTR(kIOPSInternalType));
133 bool source_present =
134 GetValueAsBoolean(description, CFSTR(kIOPSIsPresentKey), false);
135
136 if (internal_source && source_present) {
137 // FIXME: the case when there are multiple internal sources, e.g. when
Robert Sesek 2014/07/25 14:48:44 FIXME -> TODO(who)
timvolodine 2014/07/25 18:17:51 Done.
138 // multiple batteries are present. Currently this will fail a DCHECK.
139 DCHECK(!internal_source_found);
140 FetchBatteryStatus(description, status);
141 internal_source_found = true;
142 }
143 }
144
145 callback.Run(status);
146 }
147
148 class BatteryStatusObserver
149 : public base::RefCountedThreadSafe<BatteryStatusObserver> {
150 public:
151 explicit BatteryStatusObserver(const BatteryCallback& callback)
152 : callback_(callback) {}
153
154 void Start() {
155 // Need to start on a thread with UI-type message loop for
156 // |notifier_run_loop_| to receive callbacks.
157 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
158 StartOnUI();
159 } else {
160 BrowserThread::PostTask(
161 BrowserThread::UI,
162 FROM_HERE,
163 base::Bind(&BatteryStatusObserver::StartOnUI, this));
164 }
165 }
166
167 void Stop() {
168 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
169 StopOnUI();
170 } else {
171 BrowserThread::PostTask(
172 BrowserThread::UI,
173 FROM_HERE,
174 base::Bind(&BatteryStatusObserver::StopOnUI, this));
175 }
176 }
177
178 private:
179 friend class base::RefCountedThreadSafe<BatteryStatusObserver>;
180 virtual ~BatteryStatusObserver() { DCHECK(!notifier_run_loop_); }
181
182 void StartOnUI() {
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184
185 if (notifier_run_loop_)
186 return;
187
188 notifier_run_loop_.reset(
189 IOPSNotificationCreateRunLoopSource(OnBatteryStatusChangedUI,
190 static_cast<void*>(&callback_)));
191 if (!notifier_run_loop_) {
192 LOG(ERROR) << "Failed to create battery status notification run loop";
193 // Make sure to execute to callback with the default values.
194 callback_.Run(blink::WebBatteryStatus());
195 return;
196 }
197
198 OnBatteryStatusChangedUI(static_cast<void*>(&callback_));
199 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifier_run_loop_,
200 kCFRunLoopDefaultMode);
201 }
202
203 void StopOnUI() {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205
206 if (!notifier_run_loop_)
207 return;
208
209 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifier_run_loop_,
210 kCFRunLoopDefaultMode);
211 notifier_run_loop_.reset();
212 }
213
214 static void OnBatteryStatusChangedUI(void* callback) {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 // Offload fetching of values and callback execution to the IO thread.
217 BrowserThread::PostTask(
218 BrowserThread::IO,
219 FROM_HERE,
220 base::Bind(&OnBatteryStatusChanged,
221 *static_cast<BatteryCallback*>(callback)));
222 }
223
224 BatteryCallback callback_;
225 base::ScopedCFTypeRef<CFRunLoopSourceRef> notifier_run_loop_;
Robert Sesek 2014/07/25 14:48:44 naming: a run_loop_ indicates an object of type CF
timvolodine 2014/07/25 18:17:50 Done.
226
227 DISALLOW_COPY_AND_ASSIGN(BatteryStatusObserver);
228 };
229
230 class BatteryStatusManagerMac : public BatteryStatusManager {
231 public:
232 explicit BatteryStatusManagerMac(const BatteryCallback& callback)
233 : notifier_(new BatteryStatusObserver(callback)) {}
234
235 virtual ~BatteryStatusManagerMac() {
236 notifier_->Stop();
237 }
238
239 // BatteryStatusManager:
240 virtual bool StartListeningBatteryChange() OVERRIDE {
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242 notifier_->Start();
243 return true;
244 }
245
246 virtual void StopListeningBatteryChange() OVERRIDE {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248 notifier_->Stop();
249 }
250
251 private:
252 scoped_refptr<BatteryStatusObserver> notifier_;
253
254 DISALLOW_COPY_AND_ASSIGN(BatteryStatusManagerMac);
255 };
256
257 } // end namespace
258
259 // static
260 scoped_ptr<BatteryStatusManager> BatteryStatusManager::Create(
261 const BatteryStatusService::BatteryUpdateCallback& callback) {
262 return scoped_ptr<BatteryStatusManager>(
263 new BatteryStatusManagerMac(callback));
264 }
265
266 } // 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