├── README.md ├── geofencing_proposal.txt ├── index.bs ├── index.html └── simplified_geofence.txt /README.md: -------------------------------------------------------------------------------- 1 | This is the repository for the [Geofencing API](http://w3c.github.io/geofencing-api/) generated by the W3C Geolocation WG. 2 | -------------------------------------------------------------------------------- /geofencing_proposal.txt: -------------------------------------------------------------------------------- 1 | The first main change is that I've changed where the Geofencing(Controller) object is exposed. In my previous proposal this was on the navigator object, but to be better in line with other Service Worker based APIs here I moved it to the ServiceWorkerRegistration. This makes the API available to both service workers and websites with an active service worker (more on that later): 2 | 3 | partial interface ServiceWorkerRegistration { 4 | readonly attribute GeofencingController geofencing; 5 | }; 6 | 7 | For reasons explained in my reply to Martin, events are still exposed on the ServiceWorkerGlobalScope object, like this (additionally this might need some king of ongeofenceenter event, although I'm not quite sure of the use cases of such an event): 8 | 9 | partial interface ServiceWorkerGlobalScope 10 | { 11 | attribute EventHandler ongeofenceenter; 12 | attribute EventHandler ongeofenceleave; 13 | }; 14 | 15 | [NoInterfaceObject] 16 | interface GeofencingEvent { 17 | readonly attribute GeofenceRegistration region; 18 | readonly attribute Position position; 19 | } 20 | 21 | The biggest changes in my proposal are here. Before registerRegion didn't return anything, now I've changed this to return a GeofenceRegistration object (which is also used in the event above). I moved the id out of the GeofenceRegion object, and instead made this part of the Registration. This is more in line with Martin's proposal, but also allows for a couple of other nice things. For example a user agent could choose to slightly adjust the region that it is asked to register (if the radius is too small, or similar situations), and return the adjusted region as part of the registration object. 22 | 23 | [NoInterfaceObject] 24 | interface GeofencingController { 25 | Promise registerRegion(DOMString id, GeofencingRegion region); 26 | Promise> getRegisteredRegions(); 27 | Promise getRegisteredRegion(DOMString id); 28 | }; 29 | 30 | interface GeofenceRegistration : EventTarget { 31 | readonly attribute DOMString id; 32 | readonly GeofencingRegion region; 33 | 34 | Promise unregister(); 35 | 36 | // I'm not sure if there is much value in adding these events. Registering 37 | // to them from a service worker would be mostly useless, but they could 38 | // provide a nice entrypoint for a website to indicate their interest in 39 | // specific fences. 40 | attribute EventHandler onenter; 41 | attribute EventHandler onleave; 42 | }; 43 | 44 | As you see I also added onenter and onleave events to this GeofenceRegistration object. While these events won't be useful at all in service workers, this is what makes it possible to also use this API from regular webpages. For a regular webpage to use geofences it would still need to install an empty service worker, but it can then install event handlers on those geofence registrations it is actually interested in. 45 | 46 | And for completeness the GeofenceRegion classes, with no more MIN/MAX_RADIUS, and no more id as part of the region (but maybe something closer to Martin's proposal where you just directly pass a simple dictionary to registerRegion would be a better API, I don't really have a strong opinion on this). 47 | 48 | [NoInterfaceObject] 49 | interface GeofencingRegion { 50 | }; 51 | 52 | dictionary GeolocationPoint { 53 | double latitude; 54 | double longitude; 55 | }; 56 | 57 | [Constructor(dictionary options), exposed=Window&Worker] 58 | interface CircularRegion : GeofencingRegion { 59 | readonly attribute GeolocationPoint center; 60 | readonly attribute double radius; 61 | }; 62 | 63 | // Other potential region types: 64 | // Polygon of nonintersecting line segments. 65 | [Constructor(dictionary options), exposed=Window&Worker] 66 | interface PolygonRegion : GeofencingRegion { 67 | readonly attribute sequence points; 68 | }; -------------------------------------------------------------------------------- /index.bs: -------------------------------------------------------------------------------- 1 | 16 | 17 |
 18 | {
 19 |   "promises-guide": {
 20 |     "href": "https://www.w3.org/2001/tag/doc/promises-guide",
 21 |     "title": "Writing Promise-Using Specifications",
 22 |     "date": "24 July 2015",
 23 |     "status": "Finding of the W3C TAG",
 24 |     "publisher": "W3C TAG"
 25 |   },
 26 |   "WGS84": {
 27 |     "href": "http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf",
 28 |     "title": "National Imagery and Mapping Agency Technical Report 8350.2, Third Edition",
 29 |     "publisher": "National Imagery and Mapping Agency",
 30 |     "date": "3 January 2000"
 31 |   }
 32 | }
 33 | 
34 | 35 |
 36 | spec: ecma-262; urlPrefix: http://www.ecma-international.org/ecma-262/6.0/
 37 |     type: interface
 38 |         text: RangeError; url: sec-native-error-types-used-in-this-standard-rangeerror
 39 |         text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror
 40 | 
 41 | spec: geolocation-api; urlPrefix: http://www.w3.org/TR/geolocation-API/
 42 |     type: interface
 43 |         text: Position; url: position_interface
 44 | 
 45 | spec: html; urlPrefix: https://html.spec.whatwg.org/
 46 |     type: dfn
 47 |         text: trusted; url: concept-events-trusted
 48 | 
 49 | spec: powerful-features; urlPrefix: https://w3c.github.io/webappsec/specs/powerfulfeatures/#
 50 |     type: dfn
 51 |         text: secure context; url: secure-context
 52 | 
 53 | spec: promises-guide; urlPrefix: https://www.w3.org/2001/tag/doc/promises-guide#
 54 |     type: dfn
 55 |         text: A new promise; url: a-new-promise
 56 |         text: Reject; url: reject-promise
 57 |         text: Resolve; url: resolve-promise
 58 | 
 59 | spec: service-workers; urlPrefix: https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
 60 |     type: dfn
 61 |         text: handle functional event; url: handle-functional-event-algorithm
 62 |         text: service worker; url: service-worker-concept
 63 |         text: service worker registration; url: service-worker-registration-concept
 64 |     type: interface
 65 |         text: ExtendableEvent; url: extendable-event-interface
 66 |         text: ExtendableEventInit; url: extendable-event-init-dictionary
 67 |         text: ServiceWorkerGlobalScope; url: service-worker-global-scope-interface
 68 |         text: ServiceWorkerRegistration; url: service-worker-registration-interface
 69 | 
 70 | spec: WebIDL; urlPrefix: https://heycam.github.io/webidl/#
 71 |     type: exception
 72 |         text: QuotaExceededError; url: quotaexceedederror
 73 |     type: interface
 74 |         text: DOMException; url: idl-DOMException-error-names
 75 |         text: Promise; url: idl-Promise
 76 |         text: sequence; url: idl-sequence
 77 | 
78 | 79 |
80 |

Introduction

81 | 82 | This section is non-normative. 83 | 84 | The Geofencing API lets webapps set up geographic boundaries around 85 | specific locations and then receive notifications when the hosting device enters or leaves 86 | those areas. While it would be possible to implement something similar using the 87 | Geolocation API [[!GEOLOCATION-API]], there are a few differences that could make this API 88 | a better choice: 89 | 90 | * Because of the limited API surface of the Geofencing API, user 91 | agents can implement the API in a more (power) efficient way than could be achieved by 92 | regularly checking the current geographic position with the Geolocation API. 93 | * The Geofencing API is built around Service Workers. This makes it possible for a 94 | webapp to receive notifications from the Geofencing API even after the user has 95 | closed the webapp. 96 | 97 |
98 |

Examples

99 | 100 | The following code extracts illustrate how to use this API to be notified of geographic 101 | regions being entered or left. 102 | 103 |
104 | Monitor a region: 105 | 106 |
107 |         // https://example.com/webapp.js
108 |         navigator.serviceWorker
109 |           .register('serviceworker.js')
110 |           .then((swRegistration) => {
111 |             let region = new CircularGeofenceRegion({
112 |               name: 'myfence',
113 |               latitude: 37.421999,
114 |               longitude: -122.084015,
115 |               radius: 1000
116 |             });
117 |             let options = {
118 |               includePosition: true
119 |             };
120 |             swRegistration.geofencing.add(region, options)
121 |               .then(
122 |                 // If more than just a name needs to be stored with a geofence, now
123 |                 // would be the time to store this in some storage.
124 |                 (geofence) => console.log(geofence.id),
125 |                 (error) => console.log(error)
126 |               );
127 |         });
128 |       
129 |
130 | 131 |
132 | Respond to a region being entered: 133 | 134 |
135 |         // https://example.com/serviceworker.js
136 |         self.ongeofenceenter = (event) => {
137 |           console.log(event.geofence.id);
138 |           console.log(event.geofence.region.name);
139 | 
140 |           // If this is not a geofence of interest anymore, remove it.
141 |           if (event.geofence.region.name !== "myfence") {
142 |             event.waitUntil(event.geofence.remove());
143 |           }
144 |         };
145 |       
146 |
147 | 148 |
149 | Respond to an error condition: 150 | 151 |
152 |         // https://example.com/serviceworker.js
153 |         self.ongeofenceerror = (event) => {
154 |           console.log(event.geofence.id);
155 |           console.log(event.geofence.region.name);
156 |           console.log(event.error);
157 | 
158 |           // Some error condition occurred. The region is no longer monitored, and won't
159 |           // trigger any more events.
160 | 
161 |           // Try to re-monitor, although depending on the error this might fail.
162 |           event
163 |             .waitUntil(self.registration.geofencing.add(event.geofence.region))
164 |             .then((geofence) => {
165 |               // re-monitoring succeeded, new geofence will have a different ID.
166 |             }, (error) => {
167 |               // re-monitoring failed.
168 |             });
169 |         };
170 |       
171 |
172 | 173 |
174 | Stop monitoring a region in response to some other event: 175 | 176 |
177 |         // https://example.com/serviceworker.js
178 | 
179 |         // Either look geofence up by name:
180 |         self.onsomeevent = (event) => {
181 |           event
182 |             .waitUntil(
183 |               self.registration.geofencing.getAll({
184 |                 name: 'myfence'
185 |               })
186 |             )
187 |             .then(
188 |               geofences => geofences.forEach(fence => fence.remove())
189 |             );
190 |         };
191 | 
192 |         // Or look geofence up by ID:
193 |         self.onsomeotherevent = (event) => {
194 |           let geofence_id = ''; /* somehow get the ID of a geofence */
195 |           event
196 |             .waitUntil(self.registration.geofencing.getById(geofence_id))
197 |             .then(geofence => geofence.remove());
198 |         };
199 |       
200 |
201 |
202 |
203 | 204 |
205 |

Model

206 | 207 | The term webapp refers to a Web application, i.e. an application implemented 208 | using Web technologies, and executing within the context of a Web user agent, e.g. a 209 | Web browser or other Web runtime environment. 210 | 211 | A service worker registration has an associated list of geofences whose element 212 | type is a geofence. 213 | 214 | A geofence is one specific registration of a geograhpic region as a geofence. 215 | 216 | A geofence has a name (a string). 217 | 218 | A geofence has an associated geographic region. 219 | 220 | A geofence has a geofence ID, a string uniquely identifying it. This ID is 221 | generated by the user agent and MUST be unique among all geofences 222 | associated with all service worker registrations at the 223 | same origin. A user agent SHOULD NOT reuse the ID from an old geofence for a new 224 | one. 225 | 226 | A geofence has an include position flag, a boolean indicating if events 227 | associated with this geofence should include the exact geographic position. 228 | 229 | A geofence has an associated state, which is one of active or 230 | inactive. 231 | 232 | The user agent SHOULD be monitoring all active geofences 233 | for breach events. 234 | 235 | A geographic region is a circular region defined by a geographic 236 | coordinate representing the center of the region and a radius representing 237 | the size of the region. 238 | 239 | The geographic coordinate reference system used by the attributes in this API is 240 | the World Geodetic System (2d) [[!WGS84]]. No other reference system is supported. 241 | 242 | A geofence is said to be breached if the current geographical location 243 | changed from being inside the geographic region to outside (a leave 244 | event), or vice versa (an enter event). 245 | 246 |
247 |

Implementation considerations

248 | 249 | A user agent MAY impose limits on the maximum size of a 250 | geofence name. If a limit is imposed, this limit SHOULD allow for at least 100 characters. 251 | 252 | A user agent MAY impose limits on the total number of 253 | geofences that can be registered by a single origin. If a 254 | limit is imposed, this limit SHOULD allow at least 20 geofences 255 | to be registered on a single origin. 256 |
257 |
258 | 259 |
260 |

Security and privacy considerations

261 | 262 | The same security and privacy 263 | considerations that apply to the Geolocation API [[!GEOLOCATION-API]] also apply to 264 | this API. Furthermore since this API effectively gives access to geographic location 265 | information after a user has stopped interacting with a webapp, a few other considerations 266 | should be taken into account. 267 | 268 |
269 |

270 | Privacy considerations for implementers of the Geofencing API 271 |

272 | 273 | 274 | User agents MUST NOT provide Geofencing API access to 275 | webapps without the express permission of the user. 276 | User agents MUST acquire consent for permission through a user 277 | interface for each call to the {{GeofenceManager/add(initialRegion, options)}} method, unless a 278 | previous permission grant has been persisted, or a prearranged trust relationship applies. 279 | Permissions that are preserved beyond the current browsing session MUST be revocable. 280 | 281 | The user agent MAY consider the {{GeofenceRegion}} and/or the {{GeofenceOptions}} when 282 | acquiring permission or determining the permission status. 283 | 284 | When a permission is revoked, all geofences added with that permission 285 | MUST be deactivated. 286 | 287 | When permission is granted for unlimited use of the Geofencing API by a service worker 288 | registration, the state of all associated geofences SHOULD 289 | be set to active, and the user agent SHOULD start monitoring these 290 | geofences for breach events. 291 | 292 | When a service worker registration is unregistered, any associated 293 | geofences MUST be deactivated. 294 | 295 | User agents MUST allow access to the Geofencing API from 296 | secure contexts only. 297 | 298 | ISSUE: This should somehow mention how the [permissions] API is related to this. 299 |
300 | 301 |
302 |

303 | Privacy considerations for recipients of location information 304 |

305 | 306 | TODO 307 |
308 | 309 |
310 |

311 | Additional implementation considerations 312 |

313 | 314 | This section is non-normative. 315 | 316 | TODO 317 |
318 |
319 | 320 |
321 |

API Description

322 | 323 |
324 |

325 | Extensions to the {{ServiceWorkerRegistration}} interface 326 |

327 | 328 | The Service Worker specification defines a {{ServiceWorkerRegistration}} interface, which 329 | this specification extends. 330 | 331 |
332 |       partial interface ServiceWorkerRegistration {
333 |         readonly attribute GeofenceManager geofencing;
334 |       };
335 |     
336 |
337 | 338 |
339 |

{{GeofenceManager}} interface

340 | 341 | The {{GeofenceManager}} interface defines operations that enable 342 | webapps to establish access to geofencing services. 343 | 344 |
345 |       [NoInterfaceObject]
346 |       interface GeofenceManager {
347 |         Promise<Geofence> add(GeofenceRegion initialRegion, optional GeofenceOptions options);
348 |         Promise<sequence<Geofence>> getAll(optional GeofenceQueryOptions options);
349 |         Promise<Geofence> getById(DOMString id);
350 |       };
351 | 
352 |       dictionary GeofenceOptions {
353 |         boolean includePosition = false;
354 |       };
355 | 
356 |       dictionary GeofenceQueryOptions {
357 |         DOMString? name;
358 |       };
359 |     
360 | 361 | A {{GeofenceManager}} has an associated service worker registration, represented by the 362 | {{ServiceWorkerRegistration}} instance on which the {{GeofenceManager}} was exposed. 363 | 364 | The 365 | add(initialRegion, options) method when invoked MUST return 366 | a new promise promise and run the following steps in parallel: 367 |
    368 |
  1. 369 | Let serviceWorkerRegistration be the {{GeofenceManager}}'s associated service worker registration. 370 |
  2. 371 |
  3. 372 | If initialRegion is not a {{CircularGeofenceRegion}} instance, reject promise with a {{TypeError}}. 373 |
  4. 374 |
  5. 375 | If the length of the {{GeofenceRegion/name}} property of initialRegion exceeds a 376 | user agent defined limit, reject promise 377 | with a {{RangeError}}. 378 |
  6. 379 |
  7. 380 | If the {{CircularGeofenceRegion/latitude}} property of initialRegion is less than 381 | -90 or greater than 90, reject promise with a 382 | {{RangeError}}. 383 |
  8. 384 |
  9. 385 | If the {{CircularGeofenceRegion/longitude}} property of initialRegion is less 386 | than -180 or greater than 180, reject promise 387 | with a {{RangeError}}. 388 |
  10. 389 |
  11. 390 | If the total number of geofences for all service worker registrations in the current origin 392 | is more than the user agent defined limit, reject 393 | promise with a {{QuotaExceededError}} and terminate these substeps. 394 |
  12. 395 |
  13. 396 | Let geofence be a new geofence. 397 |
  14. 398 |
  15. 399 | Set the geofence ID of geofence to a newly generated value. 400 |
  16. 401 |
  17. 402 | Set the geographic region of geofence to a 403 | the region represented by initialRegion. 404 |
  18. 405 |
  19. 406 | Set the include position flag of geofence to 407 | options.includePosition, or false if no options were 408 | specified. 409 |
  20. 410 |
  21. 411 | Set the state of geofence to inactive. 412 |
  22. 413 |
  23. 414 | Add geofence to the list of geofences associated with 415 | serviceWorkerRegistration. 416 |
  24. 417 |
  25. 418 | Resolve promise with a new {{Geofence}} instance representing 419 | geofence. 420 |
  26. 421 |
  27. 422 | Ask the user whether they allow the webapp to monitor geofences, unless a 423 | prearranged trust relationship applies or the user has already granted or denied 424 | permission explicitly for this webapp to use this API. 425 |
  28. 426 |
  29. 427 | If permission is not granted, invoke the Handle Functional Event 428 | algorithm with serviceWorkerRegistration and the algorithm represented by 429 | the following substeps as arguments. 430 |
      431 |
    1. 432 | Let globalObject be the global object these steps are invoked with. 433 |
    2. 434 |
    3. 435 | Create a trusted event event that uses the {{GeofenceErrorEvent}} 436 | interface, with event type geofenceerror. 437 |
    4. 438 |
    5. 439 | Let the {{GeofenceErrorEvent/geofence}} atrribute of event be initialized to 440 | a new {{Geofence}} instance representing geofence. 441 |
    6. 442 |
    7. 443 | Let the {{GeofenceErrorEvent/error}} attribute of event be initialized to 444 | {{PermissionDeniedError}}. 445 |
    8. 446 |
    9. 447 | Dispatch event at globalObject. 448 |
    10. 449 |
    450 |
  30. 451 |
  31. 452 | Else if permission is granted, run the following substeps: 453 |
      454 |
    1. 455 | Set the state of geofence to active and start monitoring the 456 | geofence for breach events. 457 |
    2. 458 |
    3. 459 | If the current geographic position is inside the newly added region, fire a geofenceenter event. 461 |
    4. 462 |
    463 |
464 | 465 | ISSUE: Somehow mention that the region that is saved as part of the registration can be slightly 466 | different from the region passed to register. An implementation may adjust parameters to 467 | be in range of what is possible, or otherwise modify the region. 468 | 469 | If the includePosition 470 | attribute is set to true, {{GeofenceEvent}}s for this registration will have a 471 | {{GeofenceEvent/position}} attribute. When set to false, the {{GeofenceEvent/position}} 472 | attribute will always be undefined. 473 | 474 | The getAll(options) 475 | method when invoked MUST return a new promise promise and run the following steps 476 | in parallel: 477 |
    478 |
  1. 479 | Let geofences be a new {{sequence}}. 480 |
  2. 481 |
  3. 482 | For each geofence geofence in the list of geofences associated 483 | with this service worker registration, run the following substeps: 484 |
      485 |
    1. 486 | If options is passed, has a non-null name attribute, 487 | and that name is not equal to the name of the 488 | geofence, skip the rest of these substeps and continue with the next registration. 489 |
    2. 490 |
    3. 491 | Append a new {{Geofence}} instance representing geofence to geofences. 492 |
    4. 493 |
    494 |
  4. 495 |
  5. 496 | Resolve promise with geofences. 497 |
  6. 498 |
499 | 500 | The getById(id) 501 | method when invoked MUST return a new promise promise and run the following 502 | steps in parallel: 503 |
    504 |
  1. 505 | For each geofence geofence in the list of geofences associated 506 | with this service worker registration, run the following substeps: 507 |
      508 |
    1. 509 | If the geofence ID of geofence is not equal to 510 | the passed in id, skip the rest of these substeps and continue with 511 | the next geofence. 512 |
    2. 513 |
    3. 514 | Resolve promise with a new {{Geofence}} instance representing 515 | geofence. 516 |
    4. 517 |
    518 |
  2. 519 |
  3. 520 | If promise was not resolved, resolve promise with 521 | null. 522 |
  4. 523 |
524 |
525 | 526 |
527 |

{{Geofence}} interface

528 | 529 | An instance of the {{Geofence}} interface represents a geofence. 530 | 531 |
532 |       [Exposed=(Window,Worker)]
533 |       interface Geofence {
534 |         readonly attribute DOMString id;
535 |         readonly attribute GeofenceRegion region;
536 |         Promise<boolean> remove();
537 |       };
538 |     
539 | 540 | When getting the id attribute, the user 541 | agent MUST return the geofence ID of the geofence. 542 | 543 | When getting the region attribute, the 544 | user agent MUST return the geographic region of this geofence. 545 | 546 | The remove() method when invoked 547 | MUST return a new promise promise and run the following steps 548 | in parallel: 549 |
    550 |
  1. 551 | Let geofence be the geofence represented by this {{Geofence}} instance. 552 |
  2. 553 |
  3. 554 | If geofence is not currently in the list of geofences 555 | associated with a service worker registration, resolve promise with 556 | false and abort the remainder of these steps. 557 |
  4. 558 |
  5. 559 | Remove geofence from the list of geofences associated 560 | with the current service worker registration. No more events related to this 561 | geofence will be fired after this. 562 |
  6. 563 |
  7. 564 | Set the state of geofence to inactive, but do not trigger the steps 565 | that are normally triggered when a geofence is deactivated. 566 |
  8. 567 |
  9. 568 | Resolve promise with true. 569 |
  10. 570 |
571 |
572 | 573 |
574 |

{{GeofenceRegion}} interface

575 | 576 |
577 |       [Exposed=(Window,Worker)]
578 |       interface GeofenceRegion {
579 |         readonly attribute DOMString name;
580 |       };
581 | 
582 |       dictionary GeofenceRegionInit {
583 |         DOMString? name;
584 |       };
585 |     
586 | 587 | The name attribute MUST return 588 | the value it was initialized to. When the object is created, this attribute MUST be set to the 589 | value of the {{GeofenceRegionInit/name}} property in the {{GeofenceRegionInit}} dictionary, or 590 | an empty string if that property wasn't set. 591 |
592 | 593 |
594 |

{{CircularGeofenceRegion}} interface

595 | 596 |
597 |       [Constructor(CircularGeofenceRegionInit init), Exposed=(Window,Worker)]
598 |       interface CircularGeofenceRegion : GeofenceRegion {
599 |         readonly attribute double latitude;
600 |         readonly attribute double longitude;
601 |         readonly attribute double radius;
602 |       };
603 | 
604 |       dictionary CircularGeofenceRegionInit : GeofenceRegionInit {
605 |         double latitude;
606 |         double longitude;
607 |         double radius;
608 |       };
609 |     
610 | 611 | The {{CircularGeofenceRegion}} constructor when invoked MUST initialize the properties of the 612 | newly created object to the corresponding attributes in the initializer. 613 | 614 | The latitude attribute 615 | MUST return the value it was intialized to. This value represents the latitude in 616 | circular degrees of the center of the circular region. 617 | 618 | The longitude 619 | attribute MUST return the value it was intialized to. This value represents the longitude 620 | in circular degrees of the center of the circular region. 621 | 622 | The radius attribute MUST 623 | return thev value it was initialized to. This value represents the radius in meters of the 624 | circular region. 625 |
626 | 627 |
628 |

Events

629 | 630 | The Service Worker specification defines a {{ServiceWorkerGlobalScope}} interface, which this 631 | specification extends. 632 | 633 |
634 |       partial interface ServiceWorkerGlobalScope {
635 |         attribute EventHandler ongeofenceenter;
636 |         attribute EventHandler ongeofenceleave;
637 |         attribute EventHandler ongeofenceerror;
638 |       };
639 |     
640 | 641 | The ongeofenceenter attribute is 642 | an event handler whose corresponding event handler event type is 643 | geofenceenter. 644 | 645 | The ongeofenceleave attribute is 646 | an event handler whose corresponding event handler event type is 647 | geofenceleave. 648 | 649 | The ongeofenceerror attribute is 650 | an event handler whose corresponding event handler event type is 651 | geofenceerror. 652 | 653 |
654 |

655 | The geofenceenter and geofenceleave events 656 |

657 | 658 | The {{GeofenceEvent}} interface represents a geofence being breached. 659 | 660 |
661 |         [Exposed=ServiceWorker]
662 |         interface GeofenceEvent : ExtendableEvent {
663 |           readonly attribute Geofence geofence;
664 |           readonly attribute Position? position;
665 |         };
666 |       
667 | 668 | Upon detecting a breach of a geofence geofence, 669 | the user agent MUST run the following steps to fire a geofence event: 670 |
    671 |
  1. 672 | Let serviceWorkerRegistration be the service worker registration 673 | geofence is associated with. 674 |
  2. 675 |
  3. 676 | Invoke the Handle Functional Event algorithm with serviceWorkerRegistration 677 | and the algorithm represented by the following substeps as arguments. 678 |
      679 |
    1. 680 | Let globalObject be the global object these steps are invoked with. 681 |
    2. 682 |
    3. 683 | Let eventType be geofenceenter or 684 | geofenceleave, corresponding to the type of breach 685 | event being processed. 686 |
    4. 687 |
    5. 688 | Create a trusted event event that uses the {{GeofenceEvent}} 689 | interface, with event type equal to eventType. 690 |
    6. 691 |
    7. 692 | Let the {{GeofenceEvent/geofence}} atrribute of event be initialized to 693 | a new {{Geofence}} instance representing geofence. 694 |
    8. 695 |
    9. 696 | If the include position flag of geofence is true, set the 697 | {{GeofenceEvent/position}} attribute of event to the current geographical 698 | position. 699 |
    10. 700 |
    11. 701 | Dispatch event at globalObject. 702 |
    12. 703 |
    704 |
  4. 705 |
706 | 707 | The user agent MAY delay firing a geofence 708 | event until some time and/or distance has passed after the breach was detected to make sure that the geofence really was breached. 710 |
711 | 712 |
713 |

{{GeofenceErrorEvent}}

714 | 715 |
716 |         [Exposed=ServiceWorker]
717 |         interface GeofenceErrorEvent : ExtendableEvent {
718 |           readonly attribute Geofence geofence;
719 |           readonly attribute DOMString error;
720 |           readonly attribute DOMString message;
721 |         };
722 |       
723 | 724 | When a geofence geofence is deactivated, the user agent 725 | SHOULD run the following steps: 726 |
    727 |
  1. 728 | Let serviceWorkerRegistration be the service worker registration 729 | geofence is associated with. 730 |
  2. 731 |
  3. 732 | Let oldState be the state of geofence. 733 |
  4. 734 |
  5. 735 | Set the state of geofence to inactive. 736 |
  6. 737 |
  7. 738 | If oldState is active, invoke the Handle Functional Event 739 | algorithm with serviceWorkerRegistration and the algorithm represented by 740 | the following substeps as arguments. 741 |
      742 |
    1. 743 | Let globalObject be the global object these steps are invoked with. 744 |
    2. 745 |
    3. 746 | Create a trusted event event that uses the {{GeofenceErrorEvent}} 747 | interface, with event type geofenceerror. 748 |
    4. 749 |
    5. 750 | Let the {{GeofenceErrorEvent/geofence}} atrribute of event be initialized to 751 | a new {{Geofence}} instance representing geofence. 752 |
    6. 753 |
    7. 754 | Let the {{GeofenceErrorEvent/error}} attribute of event be initialized to 755 | an error name. 756 |
    8. 757 |
    9. 758 | Let the {{GeofenceErrorEvent/message}} attribute of event be initialized to 759 | a descriptive message for the error that occurred. 760 |
    10. 761 |
    11. 762 | Dispatch event at globalObject. 763 |
    12. 764 |
    765 |
  8. 766 |
767 |
768 |
769 |
770 | 771 |
772 |

Exceptions

773 | 774 | The Geofencing API uses the new PermissionDeniedError {{DOMException}} name. 775 |
776 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Geofencing API 6 | 7 | 1309 | 1310 | 1345 | 1403 | 1404 |
1405 |

1406 |

Geofencing API

1407 |

Editor’s Draft,

1408 |
1409 |
1410 |
This version: 1411 |
https://w3c.github.io/geofencing-api/ 1412 |
Latest version: 1413 |
http://www.w3.org/TR/geofencing/ 1414 |
Feedback: 1415 |
public-geolocation@w3.org with subject line “[geofencing-api] … message topic …” (archives) 1416 |
Issue Tracking: 1417 |
GitHub 1418 |
Inline In Spec 1419 |
Editor: 1420 |
(Google) 1421 |
1422 |
1423 |
1424 |
1425 | Obsoletion Notice 1426 |

This specification is not being actively maintained, 1427 | and should not be used as a guide for implementations. 1428 | It may be revived in the future, 1429 | but for now should be considered obsolete.

1430 |

If you have questions or comments on this specification, 1431 | please send an email to the editors.

1432 |
1433 |
1434 | 1435 |
1436 |
1437 |

Abstract

1438 |
1439 |

This specification defines an API that lets webapps setup geographic boundaries around specific locations and then receive notifications when the hosting device enters or leaves those areas.

1440 |
1441 |

Status of this document

1442 |
1443 |

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

1444 |

This document was published by the Geolocation Working Group as an Editor’s Draft. 1445 | If you wish to make comments regarding this document, please send them to public-geolocation@w3.org (subscribe, archives) 1446 | with [geofencing-api] at the start of your email’s subject. 1447 | All comments are welcome.

1448 |

Publication as an Editor’s Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other 1449 | documents at any time. It is inappropriate to cite this document as other than work in 1450 | progress.

1451 |

This document was produced by a group operating under 1452 | the 5 February 2004 W3C Patent Policy. 1453 | W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; 1454 | that page also includes instructions for disclosing a patent. 1455 | An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

1456 |

This document is governed by the 1 September 2015 W3C Process Document.

1457 |

1458 |
1459 |
1460 | 1517 |
1518 |
1519 |

1. Introduction

1520 |

This section is non-normative.

1521 |

The Geofencing API lets webapps set up geographic boundaries around 1522 | specific locations and then receive notifications when the hosting device enters or leaves 1523 | those areas. While it would be possible to implement something similar using the 1524 | Geolocation API [GEOLOCATION-API], there are a few differences that could make this API 1525 | a better choice:

1526 |
    1527 |
  • 1528 |

    Because of the limited API surface of the Geofencing API, user 1529 | agents can implement the API in a more (power) efficient way than could be achieved by 1530 | regularly checking the current geographic position with the Geolocation API.

    1531 |
  • 1532 |

    The Geofencing API is built around Service Workers. This makes it possible for a webapp to receive notifications from the Geofencing API even after the user has 1533 | closed the webapp.

    1534 |
1535 |
1536 |

1.1. Examples

1537 |

The following code extracts illustrate how to use this API to be notified of geographic 1538 | regions being entered or left.

1539 |
1540 | Monitor a region: 1541 |
// https://example.com/webapp.js
1542 | navigator.serviceWorker
1543 |   .register('serviceworker.js')
1544 |   .then((swRegistration) => {
1545 |     let region = new CircularGeofenceRegion({
1546 |       name: 'myfence',
1547 |       latitude: 37.421999,
1548 |       longitude: -122.084015,
1549 |       radius: 1000
1550 |     });
1551 |     let options = {
1552 |       includePosition: true
1553 |     };
1554 |     swRegistration.geofencing.add(region, options)
1555 |       .then(
1556 |         // If more than just a name needs to be stored with a geofence, now
1557 |         // would be the time to store this in some storage.
1558 |         (geofence) => console.log(geofence.id),
1559 |         (error) => console.log(error)
1560 |       );
1561 | });
1562 |
1563 |
1564 | Respond to a region being entered: 1565 |
// https://example.com/serviceworker.js
1566 | self.ongeofenceenter = (event) => {
1567 |   console.log(event.geofence.id);
1568 |   console.log(event.geofence.region.name);
1569 | 
1570 |   // If this is not a geofence of interest anymore, remove it.
1571 |   if (event.geofence.region.name !== "myfence") {
1572 |     event.waitUntil(event.geofence.remove());
1573 |   }
1574 | };
1575 |
1576 |
1577 | Respond to an error condition: 1578 |
// https://example.com/serviceworker.js
1579 | self.ongeofenceerror = (event) => {
1580 |   console.log(event.geofence.id);
1581 |   console.log(event.geofence.region.name);
1582 |   console.log(event.error);
1583 | 
1584 |   // Some error condition occurred. The region is no longer monitored, and won’t
1585 |   // trigger any more events.
1586 | 
1587 |   // Try to re-monitor, although depending on the error this might fail.
1588 |   event
1589 |     .waitUntil(self.registration.geofencing.add(event.geofence.region))
1590 |     .then((geofence) => {
1591 |       // re-monitoring succeeded, new geofence will have a different ID.
1592 |     }, (error) => {
1593 |       // re-monitoring failed.
1594 |     });
1595 | };
1596 |
1597 |
1598 | Stop monitoring a region in response to some other event: 1599 |
// https://example.com/serviceworker.js
1600 | 
1601 | // Either look geofence up by name:
1602 | self.onsomeevent = (event) => {
1603 |   event
1604 |     .waitUntil(
1605 |       self.registration.geofencing.getAll({
1606 |         name: 'myfence'
1607 |       })
1608 |     )
1609 |     .then(
1610 |       geofences => geofences.forEach(fence => fence.remove())
1611 |     );
1612 | };
1613 | 
1614 | // Or look geofence up by ID:
1615 | self.onsomeotherevent = (event) => {
1616 |   let geofence_id = ''; /* somehow get the ID of a geofence */
1617 |   event
1618 |     .waitUntil(self.registration.geofencing.getById(geofence_id))
1619 |     .then(geofence => geofence.remove());
1620 | };
1621 |
1622 |
1623 |
1624 |
1625 |

2. Model

1626 |

The term webapp#webappReferenced in:1. Introduction (2) (3)3.1. 1627 | Privacy considerations for implementers of the Geofencing API 4.2. GeofenceManager interface (2) (3) refers to a Web application, i.e. an application implemented 1628 | using Web technologies, and executing within the context of a Web user agent, e.g. a 1629 | Web browser or other Web runtime environment.

1630 |

A service worker registration has an associated list of geofences#list-of-geofencesReferenced in:2. Model2.1. Implementation considerations (2)4.2. GeofenceManager interface (2) (3) (4)4.3. Geofence interface (2) whose element 1631 | type is a geofence.

1632 |

A geofence#geofence-termReferenced in:2. Model (2) (3) (4) (5) (6) (7) (8) (9) (10)3.1. 1633 | Privacy considerations for implementers of the Geofencing API (2) (3) (4)4.2. GeofenceManager interface (2) (3)4.3. Geofence interface (2) (3) (4) (5)4.6.1. 1634 | The geofenceenter and geofenceleave events 4.6.2. GeofenceErrorEvent is one specific registration of a geograhpic region as a geofence.

1635 |

A geofence has a name#geofence-nameReferenced in:2.1. Implementation considerations4.2. GeofenceManager interface (a string).

1636 |

A geofence has an associated geographic region.

1637 |

A geofence has a geofence ID#geofence-idReferenced in:4.2. GeofenceManager interface (2)4.3. Geofence interface, a string uniquely identifying it. This ID is 1638 | generated by the user agent and MUST be unique among all geofences associated with all service worker registrations at the 1639 | same origin. A user agent SHOULD NOT reuse the ID from an old geofence for a new 1640 | one.

1641 |

A geofence has an include position#include-positionReferenced in:4.2. GeofenceManager interface4.6.1. 1642 | The geofenceenter and geofenceleave events flag, a boolean indicating if events 1643 | associated with this geofence should include the exact geographic position.

1644 |

A geofence has an associated state#stateReferenced in:3.1. 1645 | Privacy considerations for implementers of the Geofencing API 4.2. GeofenceManager interface (2)4.3. Geofence interface4.6.2. GeofenceErrorEvent (2), which is one of active#activeReferenced in:2. Model3.1. 1646 | Privacy considerations for implementers of the Geofencing API 4.2. GeofenceManager interface4.6.2. GeofenceErrorEvent or inactive#inactiveReferenced in:4.2. GeofenceManager interface4.3. Geofence interface4.6.2. GeofenceErrorEvent.

1647 |

The user agent SHOULD be monitoring all active geofences for breach events.

1648 |

A geographic region#geographic-regionReferenced in:2. Model (2)4.2. GeofenceManager interface4.3. Geofence interface is a circular region defined by a geographic 1649 | coordinate representing the center of the region and a radius representing 1650 | the size of the region.

1651 |

The geographic coordinate#geographic-coordinateReferenced in:2. Model reference system used by the attributes in this API is 1652 | the World Geodetic System (2d) [WGS84]. No other reference system is supported.

1653 |

A geofence is said to be breached#breachedReferenced in:2. Model3.1. 1654 | Privacy considerations for implementers of the Geofencing API 4.2. GeofenceManager interface4.6.1. 1655 | The geofenceenter and geofenceleave events (2) (3) (4) (5) if the current geographical location 1656 | changed from being inside the geographic region to outside (a leave 1657 | event), or vice versa (an enter event).

1658 |
1659 |

2.1. Implementation considerations

1660 |

A user agent MAY impose limits#name-limitReferenced in:4.2. GeofenceManager interface on the maximum size of a geofence name. If a limit is imposed, this limit SHOULD allow for at least 100 characters.

1661 |

A user agent MAY impose limits#geofence-limitReferenced in:4.2. GeofenceManager interface on the total number of geofences that can be registered by a single origin. If a 1662 | limit is imposed, this limit SHOULD allow at least 20 geofences to be registered on a single origin.

1663 |
1664 |
1665 |
1666 |

3. Security and privacy considerations

1667 |

The same security and privacy 1668 | considerations that apply to the Geolocation API [GEOLOCATION-API] also apply to 1669 | this API. Furthermore since this API effectively gives access to geographic location 1670 | information after a user has stopped interacting with a webapp, a few other considerations 1671 | should be taken into account.

1672 |
1673 |

3.1. Privacy considerations for implementers of the Geofencing API

1674 |

User agents MUST NOT provide Geofencing API access to webapps without the express permission of the user. User agents MUST acquire consent for permission through a user 1675 | interface for each call to the add(initialRegion, options) method, unless a 1676 | previous permission grant has been persisted, or a prearranged trust relationship applies. 1677 | Permissions that are preserved beyond the current browsing session MUST be revocable.

1678 |

The user agent MAY consider the GeofenceRegion and/or the GeofenceOptions when 1679 | acquiring permission or determining the permission status.

1680 |

When a permission is revoked, all geofences added with that permission 1681 | MUST be deactivated.

1682 |

When permission is granted for unlimited use of the Geofencing API by a service worker 1683 | registration, the state of all associated geofences SHOULD 1684 | be set to active, and the user agent SHOULD start monitoring these geofences for breach events.

1685 |

When a service worker registration is unregistered, any associated geofences MUST be deactivated.

1686 |

User agents MUST allow access to the Geofencing API from secure contexts only.

1687 |

This should somehow mention how the [permissions] API is related to this.

1688 |
1689 |
1690 |

3.2. Privacy considerations for recipients of location information

1691 |

TODO

1692 |
1693 |
1694 |

3.3. Additional implementation considerations

1695 |

This section is non-normative.

1696 |

TODO

1697 |
1698 |
1699 |
1700 |

4. API Description

1701 |
1702 |

4.1. Extensions to the ServiceWorkerRegistration interface

1703 |

The Service Worker specification defines a ServiceWorkerRegistration interface, which 1704 | this specification extends.

1705 |
partial interface ServiceWorkerRegistration {
1706 |   readonly attribute GeofenceManager geofencing;
1707 | };
1708 | 
1709 |
1710 |
1711 |

4.2. GeofenceManager interface

1712 |

The GeofenceManager interface defines operations that enable webapps to establish access to geofencing services.

1713 |
[NoInterfaceObject]
1714 | interface GeofenceManager#geofencemanagerReferenced in:4.1. 
1715 |       Extensions to the ServiceWorkerRegistration interface
1716 |     4.2. GeofenceManager interface (2) (3) (4) (5) {
1717 |   Promise<Geofence> add(GeofenceRegion initialRegion, optional GeofenceOptions options);
1718 |   Promise<sequence<Geofence>> getAll(optional GeofenceQueryOptions options);
1719 |   Promise<Geofence> getById(DOMString id);
1720 | };
1721 | 
1722 | dictionary GeofenceOptions#dictdef-geofenceoptionsReferenced in:3.1. 
1723 |       Privacy considerations for implementers of the Geofencing API
1724 |     4.2. GeofenceManager interface {
1725 |   boolean includePosition = false;
1726 | };
1727 | 
1728 | dictionary GeofenceQueryOptions#dictdef-geofencequeryoptionsReferenced in:4.2. GeofenceManager interface {
1729 |   DOMString? name;
1730 | };
1731 | 
1732 |

A GeofenceManager has an associated service worker registration, represented by the ServiceWorkerRegistration instance on which the GeofenceManager was exposed.

1733 |

The add(initialRegion, options)#dom-geofencemanager-addReferenced in:3.1. 1734 | Privacy considerations for implementers of the Geofencing API 4.2. GeofenceManager interface method when invoked MUST return a new promise promise and run the following steps in parallel:

1735 |
    1736 |
  1. Let serviceWorkerRegistration be the GeofenceManager's associated service worker registration. 1737 |
  2. If initialRegion is not a CircularGeofenceRegion instance, reject promise with a TypeError. 1738 |
  3. If the length of the name property of initialRegion exceeds a user agent defined limit, reject promise with a RangeError. 1739 |
  4. If the latitude property of initialRegion is less than -90 or greater than 90, reject promise with a RangeError. 1740 |
  5. If the longitude property of initialRegion is less 1741 | than -180 or greater than 180, reject promise with a RangeError. 1742 |
  6. If the total number of geofences for all service worker registrations in the current origin 1743 | is more than the user agent defined limit, reject promise with a QuotaExceededError and terminate these substeps. 1744 |
  7. Let geofence be a new geofence. 1745 |
  8. Set the geofence ID of geofence to a newly generated value. 1746 |
  9. Set the geographic region of geofence to a 1747 | the region represented by initialRegion. 1748 |
  10. Set the include position flag of geofence to options.includePosition, or false if no options were 1749 | specified. 1750 |
  11. Set the state of geofence to inactive. 1751 |
  12. Add geofence to the list of geofences associated with serviceWorkerRegistration. 1752 |
  13. Resolve promise with a new Geofence instance representing geofence. 1753 |
  14. Ask the user whether they allow the webapp to monitor geofences, unless a 1754 | prearranged trust relationship applies or the user has already granted or denied 1755 | permission explicitly for this webapp to use this API. 1756 |
  15. 1757 | If permission is not granted, invoke the Handle Functional Event algorithm with serviceWorkerRegistration and the algorithm represented by 1758 | the following substeps as arguments. 1759 |
      1760 |
    1. Let globalObject be the global object these steps are invoked with. 1761 |
    2. Create a trusted event event that uses the GeofenceErrorEvent interface, with event type geofenceerror. 1762 |
    3. Let the geofence atrribute of event be initialized to 1763 | a new Geofence instance representing geofence. 1764 |
    4. Let the error attribute of event be initialized to PermissionDeniedError. 1765 |
    5. Dispatch event at globalObject. 1766 |
    1767 |
  16. 1768 | Else if permission is granted, run the following substeps: 1769 |
      1770 |
    1. Set the state of geofence to active and start monitoring the 1771 | geofence for breach events. 1772 |
    2. If the current geographic position is inside the newly added region, fire a geofenceenter event. 1773 |
    1774 |
1775 |

Somehow mention that the region that is saved as part of the registration can be slightly 1776 | different from the region passed to register. An implementation may adjust parameters to 1777 | be in range of what is possible, or otherwise modify the region.

1778 |

If the includePosition#dom-geofenceoptions-includepositionReferenced in:4.2. GeofenceManager interface attribute is set to true, GeofenceEvents for this registration will have a position attribute. When set to false, the position attribute will always be undefined.

1779 |

The getAll(options)#dom-geofencemanager-getallReferenced in:4.2. GeofenceManager interface method when invoked MUST return a new promise promise and run the following steps in parallel:

1780 |
    1781 |
  1. Let geofences be a new sequence. 1782 |
  2. 1783 | For each geofence geofence in the list of geofences associated 1784 | with this service worker registration, run the following substeps: 1785 |
      1786 |
    1. If options is passed, has a non-null name attribute, 1787 | and that name is not equal to the name of the geofence, skip the rest of these substeps and continue with the next registration. 1788 |
    2. Append a new Geofence instance representing geofence to geofences. 1789 |
    1790 |
  3. Resolve promise with geofences. 1791 |
1792 |

The getById(id)#dom-geofencemanager-getbyidReferenced in:4.2. GeofenceManager interface method when invoked MUST return a new promise promise and run the following 1793 | steps in parallel:

1794 |
    1795 |
  1. 1796 | For each geofence geofence in the list of geofences associated 1797 | with this service worker registration, run the following substeps: 1798 |
      1799 |
    1. If the geofence ID of geofence is not equal to 1800 | the passed in id, skip the rest of these substeps and continue with 1801 | the next geofence. 1802 |
    2. Resolve promise with a new Geofence instance representing geofence. 1803 |
    1804 |
  2. If promise was not resolved, resolve promise with null. 1805 |
1806 |
1807 |
1808 |

4.3. Geofence interface

1809 |

An instance of the Geofence interface represents a geofence.

1810 |
[Exposed=(Window,Worker)]
1811 | interface Geofence#geofenceReferenced in:4.2. GeofenceManager interface (2) (3) (4) (5) (6) (7)4.3. Geofence interface (2) (3)4.6.1. 
1812 |         The geofenceenter and geofenceleave events
1813 |        (2)4.6.2. GeofenceErrorEvent (2) {
1814 |   readonly attribute DOMString id;
1815 |   readonly attribute GeofenceRegion region;
1816 |   Promise<boolean> remove();
1817 | };
1818 | 
1819 |

When getting the id#dom-geofence-idReferenced in:4.3. Geofence interface attribute, the user 1820 | agent MUST return the geofence ID of the geofence.

1821 |

When getting the region#dom-geofence-regionReferenced in:4.3. Geofence interface attribute, the user agent MUST return the geographic region of this geofence.

1822 |

The remove()#dom-geofence-removeReferenced in:4.3. Geofence interface method when invoked 1823 | MUST return a new promise promise and run the following steps in parallel:

1824 |
    1825 |
  1. Let geofence be the geofence represented by this Geofence instance. 1826 |
  2. If geofence is not currently in the list of geofences associated with a service worker registration, resolve promise with false and abort the remainder of these steps. 1827 |
  3. Remove geofence from the list of geofences associated 1828 | with the current service worker registration. No more events related to this 1829 | geofence will be fired after this. 1830 |
  4. Set the state of geofence to inactive, but do not trigger the steps 1831 | that are normally triggered when a geofence is deactivated. 1832 |
  5. Resolve promise with true. 1833 |
1834 |
1835 |
1836 |

4.4. GeofenceRegion interface

1837 |
[Exposed=(Window,Worker)]
1838 | interface GeofenceRegion#geofenceregionReferenced in:3.1. 
1839 |       Privacy considerations for implementers of the Geofencing API
1840 |     4.2. GeofenceManager interface4.3. Geofence interface4.4. GeofenceRegion interface4.5. CircularGeofenceRegion interface {
1841 |   readonly attribute DOMString name;
1842 | };
1843 | 
1844 | dictionary GeofenceRegionInit#dictdef-geofenceregioninitReferenced in:4.4. GeofenceRegion interface4.5. CircularGeofenceRegion interface {
1845 |   DOMString? name#dom-geofenceregioninit-nameReferenced in:4.4. GeofenceRegion interface;
1846 | };
1847 | 
1848 |

The name#dom-geofenceregion-nameReferenced in:4.2. GeofenceManager interface4.4. GeofenceRegion interface attribute MUST return 1849 | the value it was initialized to. When the object is created, this attribute MUST be set to the 1850 | value of the name property in the GeofenceRegionInit dictionary, or 1851 | an empty string if that property wasn’t set.

1852 |
1853 |
1854 |

4.5. CircularGeofenceRegion interface

1855 |
[Constructor(CircularGeofenceRegionInit init), Exposed=(Window,Worker)]
1856 | interface CircularGeofenceRegion#circulargeofenceregionReferenced in:4.2. GeofenceManager interface4.5. CircularGeofenceRegion interface (2) : GeofenceRegion {
1857 |   readonly attribute double latitude;
1858 |   readonly attribute double longitude;
1859 |   readonly attribute double radius;
1860 | };
1861 | 
1862 | dictionary CircularGeofenceRegionInit#dictdef-circulargeofenceregioninitReferenced in:4.5. CircularGeofenceRegion interface : GeofenceRegionInit {
1863 |   double latitude;
1864 |   double longitude;
1865 |   double radius;
1866 | };
1867 | 
1868 |

The CircularGeofenceRegion constructor when invoked MUST initialize the properties of the 1869 | newly created object to the corresponding attributes in the initializer.

1870 |

The latitude#dom-circulargeofenceregion-latitudeReferenced in:4.2. GeofenceManager interface4.5. CircularGeofenceRegion interface attribute 1871 | MUST return the value it was intialized to. This value represents the latitude in 1872 | circular degrees of the center of the circular region.

1873 |

The longitude#dom-circulargeofenceregion-longitudeReferenced in:4.2. GeofenceManager interface4.5. CircularGeofenceRegion interface attribute MUST return the value it was intialized to. This value represents the longitude 1874 | in circular degrees of the center of the circular region.

1875 |

The radius#dom-circulargeofenceregion-radiusReferenced in:4.5. CircularGeofenceRegion interface attribute MUST 1876 | return thev value it was initialized to. This value represents the radius in meters of the 1877 | circular region.

1878 |
1879 |
1880 |

4.6. Events

1881 |

The Service Worker specification defines a ServiceWorkerGlobalScope interface, which this 1882 | specification extends.

1883 |
partial interface ServiceWorkerGlobalScope {
1884 |   attribute EventHandler ongeofenceenter;
1885 |   attribute EventHandler ongeofenceleave;
1886 |   attribute EventHandler ongeofenceerror;
1887 | };
1888 | 
1889 |

The ongeofenceenter#dom-serviceworkerglobalscope-ongeofenceenterReferenced in:4.6. Events attribute is 1890 | an event handler whose corresponding event handler event type is geofenceenter#geofenceenterReferenced in:4.6.1. 1891 | The geofenceenter and geofenceleave events .

1892 |

The ongeofenceleave#dom-serviceworkerglobalscope-ongeofenceleaveReferenced in:4.6. Events attribute is 1893 | an event handler whose corresponding event handler event type is geofenceleave#geofenceleaveReferenced in:4.6.1. 1894 | The geofenceenter and geofenceleave events .

1895 |

The ongeofenceerror#dom-serviceworkerglobalscope-ongeofenceerrorReferenced in:4.6. Events attribute is 1896 | an event handler whose corresponding event handler event type is geofenceerror#geofenceerrorReferenced in:4.2. GeofenceManager interface4.6.2. GeofenceErrorEvent.

1897 |
1898 |

4.6.1. The geofenceenter and geofenceleave events

1899 |

The GeofenceEvent interface represents a geofence being breached.

1900 |
[Exposed=ServiceWorker]
1901 | interface GeofenceEvent#geofenceeventReferenced in:4.2. GeofenceManager interface4.6.1. 
1902 |         The geofenceenter and geofenceleave events
1903 |        (2) : ExtendableEvent {
1904 |   readonly attribute Geofence geofence#dom-geofenceevent-geofenceReferenced in:4.6.1. 
1905 |         The geofenceenter and geofenceleave events
1906 |       ;
1907 |   readonly attribute Position? position#dom-geofenceevent-positionReferenced in:4.2. GeofenceManager interface (2)4.6.1. 
1908 |         The geofenceenter and geofenceleave events
1909 |       ;
1910 | };
1911 | 
1912 |

Upon detecting a breach of a geofence geofence, 1913 | the user agent MUST run the following steps to fire a geofence event#fire-a-geofence-eventReferenced in:4.2. GeofenceManager interface4.6.1. 1914 | The geofenceenter and geofenceleave events :

1915 |
    1916 |
  1. Let serviceWorkerRegistration be the service worker registration geofence is associated with. 1917 |
  2. 1918 | Invoke the Handle Functional Event algorithm with serviceWorkerRegistration and the algorithm represented by the following substeps as arguments. 1919 |
      1920 |
    1. Let globalObject be the global object these steps are invoked with. 1921 |
    2. Let eventType be geofenceenter or geofenceleave, corresponding to the type of breach event being processed. 1922 |
    3. Create a trusted event event that uses the GeofenceEvent interface, with event type equal to eventType. 1923 |
    4. Let the geofence atrribute of event be initialized to 1924 | a new Geofence instance representing geofence. 1925 |
    5. If the include position flag of geofence is true, set the position attribute of event to the current geographical 1926 | position. 1927 |
    6. Dispatch event at globalObject. 1928 |
    1929 |
1930 |

The user agent MAY delay firing a geofence 1931 | event until some time and/or distance has passed after the breach was detected to make sure that the geofence really was breached.

1932 |
1933 |
1934 |

4.6.2. GeofenceErrorEvent

1935 |
[Exposed=ServiceWorker]
1936 | interface GeofenceErrorEvent#geofenceerroreventReferenced in:4.2. GeofenceManager interface4.6.2. GeofenceErrorEvent (2) : ExtendableEvent {
1937 |   readonly attribute Geofence geofence#dom-geofenceerrorevent-geofenceReferenced in:4.2. GeofenceManager interface4.6.2. GeofenceErrorEvent;
1938 |   readonly attribute DOMString error#dom-geofenceerrorevent-errorReferenced in:4.2. GeofenceManager interface4.6.2. GeofenceErrorEvent;
1939 |   readonly attribute DOMString message#dom-geofenceerrorevent-messageReferenced in:4.6.2. GeofenceErrorEvent;
1940 | };
1941 | 
1942 |

When a geofence geofence is deactivated#deactivatedReferenced in:3.1. 1943 | Privacy considerations for implementers of the Geofencing API (2)4.3. Geofence interface, the user agent SHOULD run the following steps:

1944 |
    1945 |
  1. Let serviceWorkerRegistration be the service worker registration geofence is associated with. 1946 |
  2. Let oldState be the state of geofence. 1947 |
  3. Set the state of geofence to inactive. 1948 |
  4. 1949 | If oldState is active, invoke the Handle Functional Event algorithm with serviceWorkerRegistration and the algorithm represented by 1950 | the following substeps as arguments. 1951 |
      1952 |
    1. Let globalObject be the global object these steps are invoked with. 1953 |
    2. Create a trusted event event that uses the GeofenceErrorEvent interface, with event type geofenceerror. 1954 |
    3. Let the geofence atrribute of event be initialized to 1955 | a new Geofence instance representing geofence. 1956 |
    4. Let the error attribute of event be initialized to 1957 | an error name. 1958 |
    5. Let the message attribute of event be initialized to 1959 | a descriptive message for the error that occurred. 1960 |
    6. Dispatch event at globalObject. 1961 |
    1962 |
1963 |
1964 |
1965 |
1966 |
1967 |

5. Exceptions

1968 |

The Geofencing API uses the new PermissionDeniedError DOMException name.

1969 |
1970 |
1971 |

Conformance

1972 |

Document conventions

1973 |

This specification defines conformance criteria that apply to a single product: the user agent#user-agentReferenced in:1. Introduction2. Model (2)2.1. Implementation considerations (2)3.1. 1974 | Privacy considerations for implementers of the Geofencing API (2) (3) (4) (5)4.2. GeofenceManager interface (2)4.3. Geofence interface (2)4.6.1. 1975 | The geofenceenter and geofenceleave events (2)4.6.2. GeofenceErrorEvent that implements the interfaces that it contains.

1976 |

Conformance requirements are expressed with a combination of 1977 | descriptive assertions and RFC 2119 terminology. The key words “MUST”, 1978 | “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, 1979 | “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this 1980 | document are to be interpreted as described in RFC 2119. 1981 | However, for readability, these words do not appear in all uppercase 1982 | letters in this specification.

1983 |

All of the text of this specification is normative except sections 1984 | explicitly marked as non-normative, examples, and notes. [RFC2119]

1985 |

Examples in this specification are introduced with the words “for example” 1986 | or are set apart from the normative text with class="example", 1987 | like this:

1988 |
1989 | 1990 |

This is an example of an informative example.

1991 |
1992 |

Informative notes begin with the word “Note” and are set apart from the 1993 | normative text with class="note", like this:

1994 |

Note, this is an informative note.

1995 |

Conformant Algorithms

1996 |

Requirements phrased in the imperative as part of algorithms (such as 1997 | "strip any leading space characters" or "return false and abort these 1998 | steps") are to be interpreted with the meaning of the key word ("must", 1999 | "should", "may", etc) used in introducing the algorithm.

2000 |

Conformance requirements phrased as algorithms or specific steps can be 2001 | implemented in any manner, so long as the end result is equivalent. In 2002 | particular, the algorithms defined in this specification are intended to 2003 | be easy to understand and are not intended to be performant. Implementers 2004 | are encouraged to optimize.

2005 | 2006 |

Index

2007 |

Terms defined by this specification

2008 | 2093 |

Terms defined by reference

2094 | 2144 |

References

2145 |

Normative References

2146 |
2147 |
[ECMASCRIPT] 2148 |
ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/ 2149 |
[GEOLOCATION-API] 2150 |
Andrei Popescu. Geolocation API Specification. 28 May 2015. PER. URL: http://dev.w3.org/geo/api/spec-source.html 2151 |
[HTML] 2152 |
Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/ 2153 |
[POWERFUL-FEATURES] 2154 |
Mike West. Secure Contexts. 13 April 2016. WD. URL: https://w3c.github.io/webappsec/specs/powerfulfeatures/ 2155 |
[PROMISES-GUIDE] 2156 |
Writing Promise-Using Specifications. 24 July 2015. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/promises-guide 2157 |
[RFC2119] 2158 |
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119 2159 |
[SERVICE-WORKERS] 2160 |
Alex Russell; Jungkee Song; Jake Archibald. Service Workers. 25 June 2015. WD. URL: https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ 2161 |
[WebIDL-1] 2162 |
Cameron McCormack; Boris Zbarsky. WebIDL Level 1. 8 March 2016. CR. URL: https://heycam.github.io/webidl/ 2163 |
[WGS84] 2164 |
National Imagery and Mapping Agency Technical Report 8350.2, Third Edition. 3 January 2000. URL: http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf 2165 |
2166 |

IDL Index

2167 |
partial interface ServiceWorkerRegistration {
2168 |   readonly attribute GeofenceManager geofencing;
2169 | };
2170 | 
2171 | [NoInterfaceObject]
2172 | interface GeofenceManager {
2173 |   Promise<Geofence> add(GeofenceRegion initialRegion, optional GeofenceOptions options);
2174 |   Promise<sequence<Geofence>> getAll(optional GeofenceQueryOptions options);
2175 |   Promise<Geofence> getById(DOMString id);
2176 | };
2177 | 
2178 | dictionary GeofenceOptions {
2179 |   boolean includePosition = false;
2180 | };
2181 | 
2182 | dictionary GeofenceQueryOptions {
2183 |   DOMString? name;
2184 | };
2185 | 
2186 | [Exposed=(Window,Worker)]
2187 | interface Geofence {
2188 |   readonly attribute DOMString id;
2189 |   readonly attribute GeofenceRegion region;
2190 |   Promise<boolean> remove();
2191 | };
2192 | 
2193 | [Exposed=(Window,Worker)]
2194 | interface GeofenceRegion {
2195 |   readonly attribute DOMString name;
2196 | };
2197 | 
2198 | dictionary GeofenceRegionInit {
2199 |   DOMString? name;
2200 | };
2201 | 
2202 | [Constructor(CircularGeofenceRegionInit init), Exposed=(Window,Worker)]
2203 | interface CircularGeofenceRegion : GeofenceRegion {
2204 |   readonly attribute double latitude;
2205 |   readonly attribute double longitude;
2206 |   readonly attribute double radius;
2207 | };
2208 | 
2209 | dictionary CircularGeofenceRegionInit : GeofenceRegionInit {
2210 |   double latitude;
2211 |   double longitude;
2212 |   double radius;
2213 | };
2214 | 
2215 | partial interface ServiceWorkerGlobalScope {
2216 |   attribute EventHandler ongeofenceenter;
2217 |   attribute EventHandler ongeofenceleave;
2218 |   attribute EventHandler ongeofenceerror;
2219 | };
2220 | 
2221 | [Exposed=ServiceWorker]
2222 | interface GeofenceEvent : ExtendableEvent {
2223 |   readonly attribute Geofence geofence;
2224 |   readonly attribute Position? position;
2225 | };
2226 | 
2227 | [Exposed=ServiceWorker]
2228 | interface GeofenceErrorEvent : ExtendableEvent {
2229 |   readonly attribute Geofence geofence;
2230 |   readonly attribute DOMString error;
2231 |   readonly attribute DOMString message;
2232 | };
2233 | 
2234 | 
2235 |

Issues Index

2236 |
2237 |
This should somehow mention how the [permissions] API is related to this.
2238 |
Somehow mention that the region that is saved as part of the registration can be slightly 2239 | different from the region passed to register. An implementation may adjust parameters to 2240 | be in range of what is possible, or otherwise modify the region.
2241 |
2242 | -------------------------------------------------------------------------------- /simplified_geofence.txt: -------------------------------------------------------------------------------- 1 | // Assuming https://github.com/slightlyoff/ServiceWorker/issues/421 gets 2 | // resolved this gives access to the API both from main pages and from within 3 | // the service worker itself, and seems cleaner than exposing this on the 4 | // service worker global scope. 5 | partial interface ServiceWorkerRegistration { 6 | readonly attribute GeofencingController geofencing; 7 | }; 8 | 9 | partial interface ServiceWorkerGlobalScope { 10 | attribute EventHandler ongeofenceenter; 11 | attribute EventHandler ongeofenceleave; 12 | attribute EventHandler ongeofenceerror; 13 | }; 14 | 15 | interface GeofencingEvent : ExtendableEvent { 16 | readonly attribute GeofenceRegistration registration; 17 | readonly attribute Position? position; 18 | }; 19 | 20 | // Not sure about specific error conditions. But some way of telling service 21 | // workers about error conditions is needed. 22 | interface GeofencingErrorEvent : GeofencingEvent { 23 | readonly attribute GeofencingError error; 24 | }; 25 | 26 | interface GeofencingController { 27 | Promise registerRegion( GeofencingRegion initialRegion, optional GeofenceRegisterOptions options ); 28 | Promise> getRegisteredRegions(optional GeofencingRegistrationQueryOptions options); 29 | Promise getRegisteredRegion(DOMString id); 30 | }; 31 | 32 | dictionary GeofenceRegisterOptions { 33 | bool includePosition = false; 34 | }; 35 | 36 | // Similar API to ServiceWorkerClients.getAll(), nice to have, but I could 37 | // live without it as well. 38 | dictionary GeofencingRegistrationQueryOptions { 39 | DOMString? name; // optionally filter by name 40 | }; 41 | 42 | interface GeofenceRegistration { 43 | readonly attribute DOMString id; // SWRegistration-unique ID 44 | readonly attribute DOMString name; // optional user-supplied name 45 | readonly GeofencingRegion region; 46 | 47 | Promise unregister(); 48 | }; 49 | 50 | dictionary GeofencingRegionInit { 51 | DOMString name = ""; // optional user-supplied name 52 | }; 53 | 54 | [NoInterfaceObject] 55 | interface GeofencingRegion { 56 | readonly attribute DOMString name; 57 | }; 58 | 59 | dictionary GeolocationPoint { 60 | double latitude; 61 | double longitude; 62 | }; 63 | 64 | dictionary CircularGeofencingRegionInit : GeofencingRegionInit { 65 | double latitude; 66 | double longitude; 67 | double radius; 68 | }; 69 | 70 | [Constructor(CircularGeofencingRegionInit), exposed=Worker] 71 | interface CircularGeofencingRegion : GeofencingRegion { 72 | readonly attribute GeolocationPoint center; 73 | readonly attribute double radius; 74 | }; 75 | 76 | // Other potential region types: 77 | // Polygon of nonintersecting line segments. 78 | [Constructor(dictionary options), exposed=Worker] 79 | interface PolygonRegion : GeofencingRegion { 80 | readonly attribute sequence points; 81 | }; 82 | 83 | 84 | 85 | Use case test: 86 | 87 | Promise registerRegion( 88 | new CircularRegion( { 89 | name: "myfence", 90 | latitude: 123, 91 | longitude: -1000, 92 | radius: 1 93 | })); 94 | 95 | Promise > getRegisteredRegions( 96 | {name: "myfence"}); 97 | --------------------------------------------------------------------------------