From f6aabb510265f79d6dfe485ff39b56d597a108e4 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 14 Nov 2023 21:05:36 +0100 Subject: [PATCH 1/3] Add Permissions API integration, start requiring requestPermission() usage This substantive and breaking change integrates the existing requestPermission() calls with the Permissions API, so that we do not need to essentially redefine the "request permission to use" algorithm here. Additionally, calling requestPermission() is now a requirement, as devicemotion, deviceorientation and deviceorientationabsolute events are fired only when the permission state is "granted". This matches WebKit's current behavior. Blink's plan is to follow suit in the near future. The powerful feature names are identical to those proposed in #121: "accelerometer", "gyroscope", and "magnetometer", which match the low-level sensors that provide the data in the events fired by this specification. These names also match those in the Accelerometer, Gyroscope and Magnetometer specifications, which allows developers who want to transition between these APIs to avoid having to request access to different powerful feature names with the same goal. Also similarly to #121, the idea is to: - Require "accelerometer" and "gyroscope" for the devicemotion event. - Require "accelerometer" and "gyroscope" to provide relative orientation data for the deviceorientation event, and additionally "magnetometer" to fall back to absolute orientation data. - Requires "accelerometer", "gyroscope", and "magnetometer" for the deviceorientationabsolute event. DeviceOrientationEvent.requestPermission() now takes an optional `absolute` argument (defaulting to false) to specify whether it will also request the "magnetometer" permission. IMPORTANT: As far as I can see, the WebKit implementation does not integrate with the Permissions API. It therefore does not use the powerful feature names described above, nor does support the new `absolute` argument or the requesting of different permissions depending on whether developers want to access to absolute orientation data. Fixes #70. --- index.bs | 224 +++++++++++++++++++++++++------------------------------ 1 file changed, 101 insertions(+), 123 deletions(-) diff --git a/index.bs b/index.bs index 84d0a37..f6024cb 100644 --- a/index.bs +++ b/index.bs @@ -213,6 +213,29 @@ The rotation rate measures the rate at which the device rotates about Note: [[MOTION-SENSORS]] and [[GYROSCOPE]] both contain a more detailed discussion of gyroscopes, rotation rates and measurements. +Permissions API integration {#permissions-api-integration} +=========================== + +This specification defines the following default powerful features: + + * "accelerometer" + * "gyroscope" + * "magnetometer" + +
+Note: Usage of the powerful features above by this specification is as follows: + + - The deviceorientation event requires "accelerometer" and "gyroscope" when providing relative orientation data. For the implementation to fall back to absolute orientation data, "magnetometer" is also required. + - The deviceorientationabsolute event requires "accelerometer", "gyroscope" and "magnetometer". + - The devicemotion event requires "accelerometer" and "gyroscope". + +
+ +Task Source {#taks-source} +=========== + +The task source for the tasks mentioned in this specification is the device motion and orientation task source. + API {#api} ========================== @@ -231,7 +254,7 @@ interface DeviceOrientationEvent : Event { readonly attribute double? gamma; readonly attribute boolean absolute; - static Promise<PermissionState> requestPermission(); + static Promise<PermissionState> requestPermission(optional boolean absolute = false); }; dictionary DeviceOrientationEventInit : EventInit { @@ -253,39 +276,24 @@ The gamma attribute must retur The absolute attribute must return the value it was initialized to. It indicates whether relative orientation or absolute orientation data is being provided.
-The requestPermission() method steps are: - -
    -
  1. Let promise be a new promise. - -

  2. -

    Run these steps in parallel: - -

      -
    1. Let permission be permission for - relevant settings object's origin. - -

    2. If permission is "default" and the relevant global object does not have transient activation, then reject promise with a - {{NotAllowedError!!exception}} {{DOMException}} and abort these steps. - -

    3. If permission is "default", ask the user whether sharing device orientation - for the relevant settings object's - origin is acceptable. If it is, set - permission to "granted", and "denied" otherwise. - -

    4. -

      Queue a task to run these steps: - -

        -
      1. Set permission for the relevant settings object's - origin to permission. +The requestPermission(absolute) method steps are: + + 1. Let global be the current global object. + 1. If this's relevant global object does not have transient activation, return a promise rejected with a "{{NotAllowedError}}" {{DOMException}}. + 1. Let result be a new promise in this's relevant Realm. + 1. Run these steps in parallel: + 1. If absolute is true: + 1. Let permissions be « "accelerometer", "gyroscope", "magnetometer" ». + 1. Otherwise: + 1. Let permissions be « "accelerometer", "gyroscope" ». + 1. Let permissionState be "granted". + 1. For each name of permissions: + 1. If the result of requesting permission to use name is "denied": + 1. Set permissionState to "denied". + 1. Break + 1. Queue a global task on the device motion and orientation task source given global to resolve result with permissionState.

      2. + 1. Return result. -
      3. Fulfill promise with permission. -

      -
    - -
  3. Return promise. -

@@ -293,15 +301,23 @@ To fire an orientation event given a event name (a string) 1. If absolute is false: 1. Let orientation be the device's relative orientation in the tridimensional plane. + 1. Let permissions be « "accelerometer", "gyroscope" ». 1. Otherwise: 1. Let orientation be the device's absolute orientation in the tridimensional plane. - 1. Let z rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the Z axis, or null if the implementation cannot provide an angle value. - 1. If z rotation is not null, limit z rotation's precision to 0.1 degrees. - 1. Let x rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the X' axis, or null if the implementation cannot provide an angle value. - 1. If x rotation is not null, limit x rotation's precision to 0.1 degrees. - 1. Let y rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the Y'' axis, or null if the implementation cannot provide an angle value. - 1. If y rotation is not null, limit y rotation's precision to 0.1 degrees. - 1. Fire an event named event name at window, using {{DeviceOrientationEvent}}, with the {{DeviceOrientationEvent/alpha}} attribute initialized to z rotation, the {{DeviceOrientationEvent/beta}} attribute initialized to x rotation, the {{DeviceOrientationEvent/gamma}} attribute initialized to y rotation, and the {{DeviceOrientationEvent/absolute}} attribute initialized to absolute. + 1. Let permissions be « "accelerometer", "gyroscope", "magnetometer" ». + 1. Let environment be window's relevant settings object. + 1. Run these steps in parallel: + 1. For each permission name in permissions: + 1. Let state be the result of getting the current permission state with permission name and environment. + 1. If state is not "granted", return. + 1. Queue a global task on the device motion and orientation task source given window to run the following steps: + 1. Let z rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the Z axis, or null if the implementation cannot provide an angle value. + 1. If z rotation is not null, limit z rotation's precision to 0.1 degrees. + 1. Let x rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the X' axis, or null if the implementation cannot provide an angle value. + 1. If x rotation is not null, limit x rotation's precision to 0.1 degrees. + 1. Let y rotation be orientation's representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the Y'' axis, or null if the implementation cannot provide an angle value. + 1. If y rotation is not null, limit y rotation's precision to 0.1 degrees. + 1. Fire an event named event name at window, using {{DeviceOrientationEvent}}, with the {{DeviceOrientationEvent/alpha}} attribute initialized to z rotation, the {{DeviceOrientationEvent/beta}} attribute initialized to x rotation, the {{DeviceOrientationEvent/gamma}} attribute initialized to y rotation, and the {{DeviceOrientationEvent/absolute}} attribute initialized to absolute.
@@ -464,37 +480,18 @@ The interval attribute must return
The requestPermission() method steps are: -
    -
  1. Let promise be a new promise. - -

  2. -

    Run these steps in parallel: - -

      -
    1. Let permission be permission for - relevant settings object's origin. - -

    2. If permission is "default" and the relevant global object does not have transient activation, then reject promise with a - {{NotAllowedError!!exception}} {{DOMException}} and abort these steps. - -

    3. If permission is "default", ask the user whether sharing device motion - for the relevant settings object's - origin is acceptable. If it is, set - permission to "granted", and "denied" otherwise. - -

    4. -

      Queue a task to run these steps: - -

        -
      1. Set permission for the relevant settings object's - origin to permission. - -

      2. Fulfill promise with permission. -

      -
    + 1. Let global be the current global object. + 1. If this's relevant global object does not have transient activation, return a promise rejected with a "{{NotAllowedError}}" {{DOMException}}. + 1. Let result be a new promise in this's relevant Realm. + 1. Run these steps in parallel: + 1. Let permissionState be "granted". + 1. For each name of « "accelerometer", "gyroscope" »: + 1. If the result of requesting permission to use name is "denied": + 1. Set permissionState to "denied". + 1. Break + 1. Queue a global task on the device motion and orientation task source given global to resolve result with permissionState.
  3. + 1. Return result. -
  4. Return promise. -

@@ -503,31 +500,37 @@ At an implementation-defined interval interval, the user agent 1. Let acceleration be null. 1. Let accelerationIncludingGravity be null. 1. Let rotationRate be null. - 1. If the implementation is able to provide linear acceleration: - 1. Set acceleration to a new {{DeviceMotionEventAcceleration}} created in window's realm. - 1. Set acceleration's x axis acceleration to the device's linear acceleration along the X axis, or null if it cannot be provided. - 1. If acceleration's x axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. Set acceleration's y axis acceleration to the device's linear acceleration along the Y axis, or null if it cannot be provided. - 1. If acceleration's y axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. Set acceleration's z axis acceleration to the device's linear acceleration along the Z axis, or null if it cannot be provided. - 1. If acceleration's z axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. If the implementation is able to provide acceleration with gravity: - 1. Set accelerationIncludingGravity to a new {{DeviceMotionEventAcceleration}} created in window's realm. - 1. Set accelerationIncludingGravity's x axis acceleration to the device's acceleration with gravity along the X axis, or null if it cannot be provided. - 1. If accelerationIncludingGravity's x axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. Set accelerationIncludingGravity's y axis acceleration to the device's acceleration with gravity along the Y axis, or null if it cannot be provided. - 1. If accelerationIncludingGravity's y axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. Set accelerationIncludingGravity's z axis acceleration to the device's acceleration with gravity along the Z axis, or null if it cannot be provided. - 1. If accelerationIncludingGravity's z axis acceleration is not null, limit its precision to no more than 0.1 m/s2. - 1. If the implementation is able to provide rotation rate: - 1. Set rotationRate to a new {{DeviceMotionEventRotationRate}} created in window's realm. - 1. Set rotationRate's x axis rotation rate to the device's rotation rate about the X axis, or null if it cannot be provided. - 1. If rotationRate's x axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. - 1. Set rotationRate's y axis rotation rate to the device's rotation rate about the Y axis, or null if it cannot be provided. - 1. If rotationRate's y axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. - 1. Set rotationRate's z axis rotation rate to the device's rotation rate about the Z axis, or null if it cannot be provided. - 1. If rotationRate's z axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. - 1. Fire an event named devicemotion at window, using {{DeviceMotionEvent}}, with the {{DeviceMotionEvent/acceleration}} attribute initialized to acceleration, the {{DeviceMotionEvent/accelerationIncludingGravity}} attribute initialized to accelerationIncludingGravity, the {{DeviceMotionEvent/rotationRate}} attribute initialized to rotationRate, and the {{DeviceMotionEvent/interval}} attribute initialized to interval. + 1. Let environment be window's relevant settings object. + 1. Run these steps in parallel: + 1. For each permission name in « "accelerometer", "gyroscope" »: + 1. Let state be the result of getting the current permission state with permission name and environment. + 1. If state is not "granted", return. + 1. Queue a global task on the device motion and orientation task source given window to run the following steps: + 1. If the implementation is able to provide linear acceleration: + 1. Set acceleration to a new {{DeviceMotionEventAcceleration}} created in window's realm. + 1. Set acceleration's x axis acceleration to the device's linear acceleration along the X axis, or null if it cannot be provided. + 1. If acceleration's x axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. Set acceleration's y axis acceleration to the device's linear acceleration along the Y axis, or null if it cannot be provided. + 1. If acceleration's y axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. Set acceleration's z axis acceleration to the device's linear acceleration along the Z axis, or null if it cannot be provided. + 1. If acceleration's z axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. If the implementation is able to provide acceleration with gravity: + 1. Set accelerationIncludingGravity to a new {{DeviceMotionEventAcceleration}} created in window's realm. + 1. Set accelerationIncludingGravity's x axis acceleration to the device's acceleration with gravity along the X axis, or null if it cannot be provided. + 1. If accelerationIncludingGravity's x axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. Set accelerationIncludingGravity's y axis acceleration to the device's acceleration with gravity along the Y axis, or null if it cannot be provided. + 1. If accelerationIncludingGravity's y axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. Set accelerationIncludingGravity's z axis acceleration to the device's acceleration with gravity along the Z axis, or null if it cannot be provided. + 1. If accelerationIncludingGravity's z axis acceleration is not null, limit its precision to no more than 0.1 m/s2. + 1. If the implementation is able to provide rotation rate: + 1. Set rotationRate to a new {{DeviceMotionEventRotationRate}} created in window's realm. + 1. Set rotationRate's x axis rotation rate to the device's rotation rate about the X axis, or null if it cannot be provided. + 1. If rotationRate's x axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. + 1. Set rotationRate's y axis rotation rate to the device's rotation rate about the Y axis, or null if it cannot be provided. + 1. If rotationRate's y axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. + 1. Set rotationRate's z axis rotation rate to the device's rotation rate about the Z axis, or null if it cannot be provided. + 1. If rotationRate's z axis rotation rate is not null, limit its precision to no more than 0.1 deg/s. + 1. Fire an event named devicemotion at window, using {{DeviceMotionEvent}}, with the {{DeviceMotionEvent/acceleration}} attribute initialized to acceleration, the {{DeviceMotionEvent/accelerationIncludingGravity}} attribute initialized to accelerationIncludingGravity, the {{DeviceMotionEvent/rotationRate}} attribute initialized to rotationRate, and the {{DeviceMotionEvent/interval}} attribute initialized to interval.
@@ -537,33 +540,6 @@ At an implementation-defined interval interval, the user agent --> If an implementation can never provide motion information, the event should be fired with the {{DeviceMotionEvent/acceleration}}, {{DeviceMotionEvent/accelerationIncludingGravity}} and {{DeviceMotionEvent/rotationRate}} attributes set to null. -

Permission model

- -
Further implementation experience is being gathered for the permission model and specification clarifications informed by this experience are being discussed in GitHub issue #74.
- -

Implementations may choose to share device orientation & motion only if the -user (or user agent on behalf of the user) has granted permission. -The permission to share device orientation & motion -for a given origin is one of three strings: - -

-
"default" -

This is equivalent to "denied", but the user has made no - explicit choice thus far. - -

"denied" -

This means the user does not want - to share device orientation or motion. - -

"granted" -

This means device orientation or motion may be shared. -

- -

There is no equivalent to "default" -meaning "granted". In that case -"granted" is simply returned as there would be no reason -for the application to ask for permission. - Security and privacy considerations {#security-and-privacy} =========================================================== @@ -573,7 +549,9 @@ The API defined in this specification can be used to obtain information from har * Location tracking [[INDOORPOS]] * User identification [[FINGERPRINT]] -In light of that, implementations may consider permissions or visual indicators to signify the use of sensors by the web page. Furthermore, to minimize privacy risks, the chance of fingerprinting and other attacks the implementations must: +In light of that, implementations may consider visual indicators to signify the use of sensors by the web page. Additionally, this specification requires users to give express permission for the user agent to provide device motion and/or orientation data via the requestPermission() API calls. + +Furthermore, to minimize privacy risks, the chance of fingerprinting and other attacks the implementations must: * fire events only when a [=/navigable=]'s [=navigable/active document=]'s [=visibility state=] is "visible", * fire events only on the [=/top-level traversable=]'s [=navigable/active window=] and [=child navigables=]' [=navigable/active windows=] whose [=relevant settings object=]'s [=environment settings object/origin=] is [=same origin=] with the [=/top-level traversable=]'s [=navigable/active window=]'s [=relevant settings object=]'s [=environment settings object/origin=]. From b095ccdb0f3478f26c2001de4490aba5ed5aa89e Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Wed, 22 Nov 2023 18:45:22 +0100 Subject: [PATCH 2/3] Export powerful features here Instead of doing that in the Accelerometer, Gyroscope and Magnetometer specifications, export them here and reference the definitions from said specs. Doing so allows us not to depend on specifications that are less advanced in the Rec track and have fewer implementations. --- index.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index f6024cb..c428257 100644 --- a/index.bs +++ b/index.bs @@ -218,9 +218,9 @@ Permissions API integration {#permissions-api-integration} This specification defines the following default powerful features: - * "accelerometer" - * "gyroscope" - * "magnetometer" + * "accelerometer" + * "gyroscope" + * "magnetometer"

Note: Usage of the powerful features above by this specification is as follows: From 3c965c8b4deefdede10dbbf1767ab09b1b9e7a99 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 28 Nov 2023 12:14:59 +0100 Subject: [PATCH 3/3] Add note to implementers about bundling permission requests. --- index.bs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/index.bs b/index.bs index c428257..d7ef951 100644 --- a/index.bs +++ b/index.bs @@ -288,6 +288,9 @@ The requestPermission(absolutepermissions be « "accelerometer", "gyroscope" ». 1. Let permissionState be "granted". 1. For each name of permissions: + + Note: There is no algorithm for requesting multiple permissions at once. However, user agents are encouraged to bundle concurrent requests for different kinds of media into a single user-facing permission prompt. + 1. If the result of requesting permission to use name is "denied": 1. Set permissionState to "denied". 1. Break @@ -486,6 +489,9 @@ The requestPermission() method steps a 1. Run these steps in parallel: 1. Let permissionState be "granted". 1. For each name of « "accelerometer", "gyroscope" »: + + Note: There is no algorithm for requesting multiple permissions at once. However, user agents are encouraged to bundle concurrent requests for different kinds of media into a single user-facing permission prompt. + 1. If the result of requesting permission to use name is "denied": 1. Set permissionState to "denied". 1. Break