-
Notifications
You must be signed in to change notification settings - Fork 15
/
index.html
671 lines (667 loc) · 23.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
<!DOCTYPE html>
<html>
<head>
<title>
Battery Status API
</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="https://www.w3.org/Tools/respec/respec-w3c" class="remove"
defer></script>
<script class="remove">
var respecConfig = {
specStatus: "ED",
shortName: "battery-status",
// publishDate: "2021-06-01",
previousPublishDate: "2021-06-01",
previousMaturity: "WD",
github: "w3c/battery",
editors: [
{
name: "Anssi Kostiainen",
company: "Intel Corporation",
companyURL: "https://intel.com/",
w3cid: 41974
}
],
formerEditors: [
{
name: "Raphael Kubo da Costa",
company: "Intel Corporation",
companyURL: "https://intel.com/",
w3cid: 95850
},
{
name: "Mounir Lamouri",
company: "Google Inc.",
companyURL: "https://google.com/",
note: "previously Mozilla",
w3cid: 45389
}
],
group: "das",
wgPublicList: "public-device-apis",
testSuiteURI: "https://wpt.live/battery-status/",
implementationReportURI: "https://wpt.fyi/results/battery-status",
xref: {
profile: "web-platform",
specs: [
"permissions-policy"
]
}
};
</script>
</head>
<body>
<section id="abstract">
This specification defines an API that provides information about the
battery status of the hosting device.
</section>
<section id="sotd">
<p>
The Devices and Sensors Working Group will apply editorial
modernizations to this specification, perform a round of self-review
and revisions on the security and privacy aspects of the API before
requesting horizontal review. Existing <a href=
"https://www.w3.org/PM/horizontal/review.html?shortname=battery-status">
security and privacy issues</a> are available.
</p>
</section>
<section class="informative">
<h2>
Introduction
</h2>
<p>
The Battery Status API specification defines a means for web developers
to programmatically determine the battery status of the hosting device.
Without knowing the battery status of a device, a web developer must
design the web application with an assumption of sufficient battery
level for the task at hand. This means the battery of a device may
exhaust faster than desired because web developers are unable to make
decisions based on the battery status. Given knowledge of the battery
status, web developers are able to craft web content and applications
which are power-efficient, thereby leading to improved user experience.
Authors should be aware, however, that a naïve implementation of this
API can negatively affect the battery life.
</p>
<p>
The Battery Status API can be used to defer or scale back work when the
device is not charging in or is low on battery. An archetype of an
advanced web application, a web-based email client, may check the
server for new email every few seconds if the device is charging, but
do so less frequently if the device is not charging or is low on
battery. Another example is a web-based word processor which could
monitor the battery level and save changes before the battery runs out
to prevent data loss.
</p>
</section>
<section id="conformance">
<p>
This specification defines conformance criteria that apply to a single
product: the <dfn>user agent</dfn> that implements the interfaces that
it contains.
</p>
</section>
<section>
<h2>
Security and privacy considerations
</h2>
<p>
The API defined in this specification is used to determine the battery
status of the hosting device.
</p>
<p>
The user agent SHOULD not expose high precision readouts of battery
status information as that can introduce a new fingerprinting vector.
</p>
<p>
The user agent MAY ask the user for battery status information access,
or alternatively, enforce the user permission requirement in its
private browsing modes.
</p>
<p>
The user agent SHOULD inform the user of the API use by scripts in an
unobtrusive manner to aid transparency and to allow the user to revoke
the API access.
</p>
<p>
The user agent MAY obfuscate the exposed value in a way that authors
cannot directly know if a hosting device has no battery, is charging or
is exposing fake values.
</p>
</section>
<section>
<h2>
Concepts
</h2>
<p>
The <a>task source</a> for the <a>tasks</a> mentioned in this
specification is the <dfn>battery status task source</dfn>.
</p>
</section>
<section data-dfn-for="Navigator">
<h2>
Extensions to the `Navigator` interface
</h2>
<pre class="idl">
[SecureContext]
partial interface Navigator {
Promise<BatteryManager> getBattery();
};
</pre>
<p class="note">
This method was exposed to a non-secure context until <a href=
"https://github.com/w3c/battery/pull/51">PR #51</a>.
</p>
<section>
<h3>
Internal slots
</h3>
<table class="simple">
<thead>
<tr>
<th>
Internal slot
</th>
<th>
Initial value
</th>
<th>
Description
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<dfn>[[\BatteryPromise]]</dfn>
</td>
<td>
`null`
</td>
<td>
A {{Promise}} returned by calls to {{Navigator/getBattery()}}.
</td>
</tr>
<tr>
<td>
<dfn>[[\BatteryManager]]</dfn>
</td>
<td>
`null`
</td>
<td>
The {{BatteryManager}} instance associated with a given
{{Navigator}} after it has been created via
{{Navigator/getBattery()}}.
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3>
The `getBattery()` method
</h3>
<p data-tests=
"battery-promise-window.https.html, battery-promise.https.html">
The <dfn>getBattery()</dfn> method steps are:
</p>
<ol class="algorithm">
<li>If [=this=].{{Navigator/[[BatteryPromise]]}} is `null`, then set
it to [=a new promise=] in [=this=]'s [=relevant realm=].
</li>
<li>If [=this=]'s [=relevant global object=]'s [=associated
`Document`=] is not [=allowed to use=] the "`battery`"
[=policy-controlled feature=], then [=reject=]
[=this=].{{Navigator/[[BatteryPromise]]}} with a
{{"NotAllowedError"}} {{DOMException}}.
</li>
<li>Otherwise:
<ol>
<li>If [=this=].{{Navigator/[[BatteryManager]]}} is `null`, then
set it to the result of creating a [=new=] {{BatteryManager}} in
[=this=]'s [=relevant realm=].
</li>
<li>[=Resolve=] [=this=].{{Navigator/[[BatteryPromise]]}} with
[=this=].{{Navigator/[[BatteryManager]]}}.
</li>
</ol>
</li>
<li>Return [=this=].{{Navigator/[[BatteryPromise]]}}.
</li>
</ol>
</section>
</section>
<section data-dfn-for="BatteryManager">
<h2>
The `BatteryManager` interface
</h2>
<pre class="idl">
[SecureContext, Exposed=Window]
interface BatteryManager : EventTarget {
readonly attribute boolean charging;
readonly attribute unrestricted double chargingTime;
readonly attribute unrestricted double dischargingTime;
readonly attribute double level;
attribute EventHandler onchargingchange;
attribute EventHandler onchargingtimechange;
attribute EventHandler ondischargingtimechange;
attribute EventHandler onlevelchange;
};
</pre>
<p>
The <dfn>BatteryManager</dfn> interface represents the <dfn>current
battery status information</dfn> of the hosting device.
</p>
<p>
The <a>user agent</a> is said to be <dfn>unable to report the battery
status information</dfn> if it is not able to report the values for any
of the attributes, for example, due to a user or system preference,
setting, or limitation.
</p>
<aside class="note">
If the user agent is <a>unable to report the battery status
information</a>, the {{BatteryManager}}'s internal slots will remain
with their default values, which emulate a fully charged and plugged in
battery. This is aimed at reducing the potential for fingerprinting and
preventing applications from degrading performance, if the battery
status information is not made available, for example.
</aside>
<section>
<h3>
Internal slots
</h3>
<p>
{{BatteryManager}} instances are created with the following
<a data-cite=
"ECMASCRIPT#sec-object-internal-methods-and-internal-slots">internal
slots</a>:
</p>
<table class="simple">
<thead>
<tr>
<th>
Internal slot
</th>
<th>
Initial value
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<dfn>[[\Charging]]</dfn>
</td>
<td>
`true`
</td>
</tr>
<tr>
<td>
<dfn>[[\ChargingTime]]</dfn>
</td>
<td>
0
</td>
</tr>
<tr>
<td>
<dfn>[[\DischargingTime]]</dfn>
</td>
<td>
Positive Infinity
</td>
</tr>
<tr>
<td>
<dfn>[[\Level]]</dfn>
</td>
<td>
1.0
</td>
</tr>
</tbody>
</table>
<section>
<h4>
The `[[Charging]]` internal slot
</h4>
<p>
The {{BatteryManager/[[Charging]]}} internal slot represents the
charging state of the system's battery. It MUST be set to `false`
if the battery is discharging, and set to `true` if the battery is
charging, the implementation is unable to report the state, or
there is no battery attached to the system, or otherwise.
</p>
<p>
When the system battery's charging state changes, the user agent
must run the <a>update the battery status and notify</a> algorithm
with {{BatteryManager/[[Charging]]}}, `true` or `false` depending
on whether the battery is charging or discharging, and
"[=chargingchange=]".
</p>
</section>
<section>
<h4>
The `[[ChargingTime]]` internal slot
</h4>
<p>
The {{BatteryManager/[[ChargingTime]]}} internal slot represents
the remaining time in seconds until the system's battery is fully
charged. It MUST be set to 0 if the battery is full or there is no
battery attached to the system, and to the value positive Infinity
if the battery is discharging, the implementation is unable to
report the remaining charging time, or otherwise.
</p>
<p>
When the battery charging time is updated, the user agent must run
the <a>update the battery status and notify</a> algorithm with
{{BatteryManager/[[ChargingTime]]}}, the new charging time in
seconds, and "[=chargingtimechange=]".
</p>
</section>
<section>
<h4>
The `[[DischargingTime]]` internal slot
</h4>
<p>
The {{BatteryManager/[[DischargingTime]]}} attribute represents the
remaining time in seconds until the system's battery is completely
discharged and the system is about to be suspended. It MUST be set
to the value positive Infinity if the battery is charging, the
implementation is unable to report the remaining discharging time,
there is no battery attached to the system, or otherwise.
</p>
<p>
When the battery discharging time is updated, the user agent must
run the <a>update the battery status and notify</a> algorithm with
{{BatteryManager/[[DischargingTime]]}}, the new discharging time in
seconds, and "[=dischargingtimechange=]".
</p>
</section>
<section>
<h4>
The `[[Level]]` internal slot
</h4>
<p>
The {{BatteryManager/[[Level]]}} internal slot represents the
system's battery's level. It MUST be set to 0 if the system's
battery is depleted and the system is about to be suspended, and to
1.0 if the battery is full, the implementation is unable to report
the battery's level, or there is no battery attached to the system.
</p>
<p>
When the battery level is updated, the user agent must run the
<a>update the battery status and notify</a> algorithm with
{{BatteryManager/[[Level]]}}, the new battery level, and
"[=levelchange=]".
</p>
</section>
<p class="note">
The definition of how often the "[=chargingtimechange=]",
"[=dischargingtimechange=]", and "[=levelchange=]" events are fired
is left to the implementation.
</p>
</section>
<section>
<h3>
The `charging` attribute
</h3>
<p>
The <dfn>charging</dfn> getter steps are to return
[=this=].{{BatteryManager/[[Charging]]}}.
</p>
</section>
<section>
<h3>
The `chargingTime` attribute
</h3>
<p>
The <dfn>chargingTime</dfn> getter steps are to return
[=this=].{{BatteryManager/[[ChargingTime]]}}.
</p>
</section>
<section>
<h3>
The `dischargingTime` attribute
</h3>
<p>
The <dfn>dischargingTime</dfn> getter steps are to return
[=this=].{{BatteryManager/[[DischargingTime]]}}.
</p>
</section>
<section>
<h3>
The `level` attribute
</h3>
<p>
The <dfn>level</dfn> getter steps are to return
[=this=].{{BatteryManager/[[Level]]}}.
</p>
</section>
<section>
<h2>
Event handlers
</h2>
<p>
The following are the <a>event handlers</a> (and their corresponding
<a>event handler event types</a>) that MUST be supported as
attributes by the {{BatteryManager}} object:
</p>
<table class="simple">
<thead>
<tr>
<th>
event handler
</th>
<th>
event handler event type
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<dfn>onchargingchange</dfn>
</td>
<td>
<dfn>`chargingchange`</dfn>
</td>
</tr>
<tr>
<td>
<dfn>onchargingtimechange</dfn>
</td>
<td>
<dfn>`chargingtimechange`</dfn>
</td>
</tr>
<tr>
<td>
<dfn>ondischargingtimechange</dfn>
</td>
<td>
<dfn>`dischargingtimechange`</dfn>
</td>
</tr>
<tr>
<td>
<dfn>onlevelchange</dfn>
</td>
<td>
<dfn>`levelchange`</dfn>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3>
Algorithms
</h3>
<p>
To <dfn>update the battery status and notify</dfn> given an internal
slot |slot|, a |value| and an |eventName|, run the following steps:
</p>
<ol class="algorithm">
<li>Let |global| be the [=current global object=].
</li>
<li>If |global| is not a {{Window}}, abort these steps.
</li>
<li>Let |navigator:Navigator| be |global|'s associated {{Navigator}}.
</li>
<li>Let |batteryManager:BatteryManager| be the value of |navigator|.
{{Navigator/[[BatteryManager]]}}.
</li>
<li>If |batteryManager| is `null`, abort these steps.
</li>
<li>[=Queue a global task=] on the [=battery status task source=]
given |global| to run the following steps:
<ol>
<li>Set |batteryManager|.|slot| to |value|.
</li>
<li>[=Fire an event=] named |eventName| at |batteryManager|.
</li>
</ol>
</li>
</ol>
</section>
<section id="multiple-batteries">
<h2>
Multiple batteries
</h2>
<p>
If a hosting device contains more than one battery,
{{BatteryManager}} SHOULD expose a unified view of the batteries.
</p>
<p>
The {{BatteryManager/[[Charging]]}} internal slot MUST be set to true
if at least one battery's charging state as described above is true.
Otherwise, it MUST be set to false.
</p>
<p>
The {{BatteryManager/[[ChargingTime]]}} internal slot can be set to
the maximum charging time of the individual batteries if charging in
parallel, and to the sum of the individual charging times if charging
serially.
</p>
<p>
The {{BatteryManager/[[DischargingTime]]}} internal slot can be set
to the maximum discharging time of the individual batteries if
discharging in parallel, and to the sum of individual discharging
times if discharging serially.
</p>
<p>
The {{BatteryManager/[[Level]]}} internal slot can be set to the
average of the levels of batteries of same capacity, or the weighted
average of the battery levels for batteries of different capacities.
</p>
</section>
</section>
<section>
<h2>
Permissions Policy integration
</h2>
<p>
The Battery Status API is a <a>policy-controlled feature</a> identified
by the string "<code>battery</code>". Its [=policy-controlled
feature/default allowlist=] is <code>[=default
allowlist/'self'=]</code>.
</p>
</section>
<section class="informative">
<h2>
Examples
</h2>
<p>
This trivial example writes the battery level to the console each time
the level changes:
</p>
<pre class="example highlight">
// We get the initial value when the promise resolves ...
navigator.getBattery().then(function(battery) {
console.log(battery.level);
// ... and any subsequent updates.
battery.onlevelchange = function() {
console.log(this.level);
};
});
</pre>
<p>
Alternatively, the same using the <code>addEventListener()</code>
method:
</p>
<pre class="example highlight">
navigator.getBattery().then(function(battery) {
console.log(battery.level);
battery.addEventListener('levelchange', function() {
console.log(this.level);
});
});
</pre>
<p>
The following example updates the indicators to show the charging
state, level and time remaining in minutes:
</p>
<pre class="example highlight">
<!DOCTYPE html>
<html>
<head>
<title>Battery Status API Example</title>
<script>
window.onload = function () {
function updateBatteryStatus(battery) {
document.querySelector('#charging').textContent = battery.charging ? 'charging' : 'not charging';
document.querySelector('#level').textContent = battery.level;
document.querySelector('#dischargingTime').textContent = battery.dischargingTime / 60;
}
navigator.getBattery().then(function(battery) {
// Update the battery status initially when the promise resolves ...
updateBatteryStatus(battery);
// .. and for any subsequent updates.
battery.onchargingchange = function () {
updateBatteryStatus(battery);
};
battery.onlevelchange = function () {
updateBatteryStatus(battery);
};
battery.ondischargingtimechange = function () {
updateBatteryStatus(battery);
};
});
};
</script>
</head>
<body>
<div id="charging">(charging state unknown)</div>
<div id="level">(battery level unknown)</div>
<div id="dischargingTime">(discharging time unknown)</div>
</body>
</html>
</pre>
</section>
<section id="index" class="appendix"></section>
<section id="idl-index" class="appendix"></section>
<section class="appendix">
<h2>
Acknowledgements
</h2>
<p>
The group is deeply indebted to Mounir Lamouri, Jonas Sicking, and the
Mozilla WebAPI team in general for their invaluable feedback based on
prototype implementations. Many thanks to the people behind the System
Information API and Device Orientation Event specification for the
initial inspiration. Also thanks to the nice folks bringing us the Page
Visibility specification, which motivated the editor of this
specification to write the introduction chapter discussing some
real-world high value use cases that apply equally to this
specification. Special thanks to all the participants of the Device
APIs Working Group and others who have sent in substantial feedback and
comments, and made the Web a better place for everyone by doing so.
Finally, thanks to Lukasz Olejnik, Gunes Acar, Claude Castelluccia, and
Claudia Diaz for the privacy analysis of the API.
</p>
</section>
</body>
</html>