-
Notifications
You must be signed in to change notification settings - Fork 394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use permissions API for XR feature requests #900
Use permissions API for XR feature requests #900
Conversation
index.bs
Outdated
@@ -496,33 +503,113 @@ Note: {{XRReferenceSpaceType/"local"}} is always included in the [=requested fea | |||
|
|||
Note: For example, several VR devices support either configuring a safe boundary for the user to move around within or skipping boundary configuration and operating in a mode where the user is expected to stand in place. Such a device can be considered to be [=capable of supporting=] {{"bounded-floor"}} {{XRReferenceSpace}}s even if they are currently not configured with safety boundaries, because it's expected that the user could configure the device appropriately if the experience required it. This is to allow user agents to avoid fully initializing the [=XRSession/XR device=] or waiting for the user's environment to be recognized prior to [=resolve the requested features|resolving the requested features=] if desired. If, however, the user agent knows that the boundary state at the time the session is requested without additional initialization it may choose to reject the {{"bounded-floor"}} feature if the safety boundary not already configured. | |||
|
|||
Permissions API Integration {#permissions} | |||
--------- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why this was put here, but it feels currently like it's kind of "breaking the flow" of the document. (As much as a spec can have any sort of proper flow to it, anyway.) It's not really part of the "Initialization" topic, nor is it a critical piece to using the API. As a result, despite the strong relationship to the requiredFeatures
and optionalFeatures
, I feel this would be better placed near the end of the spec (in the "Integrations" section).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me.
470686b
to
ee370bd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hoo boy, this is some dense stuff. Thanks for working out how this can all fit together, I'm sure it was a pain. Overall it's looking really good, and I like the direction you're taking it. I've got some questions that primarily relate to my lack of knowledge about the permissions API, and a couple of issues that should be addressed.
index.bs
Outdated
1. [=Resolve the requested features=] given by |options|' {{XRSessionInit/requiredFeatures}} and |options|' {{XRSessionInit/optionalFeatures}} values for |session|, and let |resolved| be the returned value. | ||
1. If |resolved| is <code>false</code>, run the following steps: | ||
1. Let |descriptor| be an {{XRPermissionDescriptor}} initialized with |session|, |options|' {{XRSessionInit/requiredFeatures}}, and |options|' {{XRSessionInit/optionalFeatures}}. | ||
1. Let |descriptor| be an {{XRPermissionDescriptor}} initialized with |session|, |options|' {{XRSessionInit/requiredFeatures}}, and |options|' {{XRSessionInit/optionalFeatures}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate line here.
index.bs
Outdated
1. Abort these steps. | ||
1. Let <code>(|consentRequired|, |consentOptional|, |granted|)</code> be the fields of |result|. | ||
1. For each |feature| in |consentRequired| perform the following steps: | ||
1. If a clear signal of [=user intent=] to enable |feature| has not been given, set |status|'s {{PermissionStatus/state}} to {{PermissionState/"denied"}} and abort these steps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may just be me not groking the permissions flow, but it's not clear to me where in this algorithm the user intent should be prompted? [=resolve the requested features=] identifies what features need consent, and then this fails if they don't have consent, and it seems like there's not an opportunity in between to actually prompt for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Clear signal of user intent" is when they can be prompted, but that signal can also be UA preferences or something else. We could perhaps firm up the language around that, maybe adding a definition for "clear signal of user intent" that includes something about prompting. The permissions spec itself is rather wishy washy about prompting as well.
FWIW "clear signal of user intent" was copied over from the old feature request code. I wasn't quite sure what to do for prompting so I left it as is.
[=Resolve the requested features=] is about filtering which features need to actually be requested.
<div class=algorithm data-algorithm="xr-permission-query-algorithm"> | ||
To query the "xr" permission with an {{XRPermissionDescriptor}} |descriptor| and a {{XRPermissionStatus}} |status|, the UA MUST run the following steps: | ||
|
||
1. Set |status|'s {{PermissionStatus/state}} to |descriptor|'s [=permission state=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll admit that I don't really get what this line is doing, but I also see that other permissions do something similar so I'm going to assume it's a good thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this confuses me too. Is there someone we can ask to validate this isn't an obsolete thing to be doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically the base algorithm to read the permission state. This is entirely fine to do. However, the way it's described in the spec makes it unclear to me whether this is taking into account the optional and required features. Unfortunately, I'm running out of time to review this :(
1. For each |feature| in |consentOptional| perform the following steps: | ||
1. If a clear signal of [=user intent=] to enable |feature| has not been given, continue to the next entry. | ||
1. If |feature| is not in |granted|, append |feature| to |granted|. | ||
1. Set |status|'s {{XRPermissionStatus/granted}} to |granted|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the session's [=list of enabled features=] be updated to |granted| here? I know that happens above, but that's only for the requestSession() method, while this could also be invoked by the Permissions.request() method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point
/agenda to ask people to look at it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, this must have been a beast to write up. Thank you so much for taking it on! I've left a few nits and one or two questions, but other than that LGTM!
<div class=algorithm data-algorithm="xr-permission-query-algorithm"> | ||
To query the "xr" permission with an {{XRPermissionDescriptor}} |descriptor| and a {{XRPermissionStatus}} |status|, the UA MUST run the following steps: | ||
|
||
1. Set |status|'s {{PermissionStatus/state}} to |descriptor|'s [=permission state=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this confuses me too. Is there someone we can ask to validate this isn't an obsolete thing to be doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!!!
self mentioning to have it in my queue @mounirlamouri |
It will avoid to have PR author sending rendered output as in immersive-web#900
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late comments, thanksgiving week was on the way :-/
index.bs
Outdated
|
||
<pre class="idl"> | ||
dictionary XRPermissionDescriptor: PermissionDescriptor { | ||
XRSession session; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems odd to me that XRPermissionDescriptor
would contain an XRSession
as this is what developers would need to call permissions.query()
and ideally, they may want to do that before calling requestSession()
. However, requestSession()
is what provides the session and querying about the permission status at that point becomes moot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because there's no user-exposed handle for the "device" except for the session itself. The permissions integration needs to check against a device, and also needs to be able to deal with the device being different -- e.g. if you plug in a device that supports bounded-floor spaces, you want the permissions check to work.
We could replace this with a mode enum, and use the "current XR device" instead, setting the list of granted features on the device instead of the session.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the permission need to be checked against a device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some devices don't support a feature, period.This is the existing behavior of XR features, I'm wary about changing how this works without broader agreement.
1. If |resolved| is <code>false</code>, run the following steps: | ||
1. Let |descriptor| be an {{XRPermissionDescriptor}} initialized with |session|, |options|' {{XRSessionInit/requiredFeatures}}, and |options|' {{XRSessionInit/optionalFeatures}}. | ||
1. Let |status| be an {{XRPermissionStatus}}, initially <code>null</code> | ||
1. [=Request the xr permission=] with |descriptor| and |status|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that "Request the xr permission" could return "status" instead of having it as in in/out parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't, that's how the permission request algorithm works. I agree that it is awkward, but that's a problem for upstream.
https://wicg.github.io/permissions-request/#permission-request-algorithm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a different spec FWIW. You could re-use https://wicg.github.io/permissions-request/#boolean-permission-request-algorithm the same way https://w3c.github.io/permissions/#media-devices does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The media spec is using it incorrectly: it operates on the return value of the boolean permissions request algorithm, which does not exist, and it returns a value from its own permissions request algorithm, which according to the permissions spec should not exist. I'd be more than happy to clean this up but as written the permissions spec forces you to use an inout parameter. Perhaps it should be changed to use return values in many places so that it can be used in the way the media spec expects it to be.
@@ -2334,6 +2309,121 @@ The [=default allowlist=] for this feature is <code>["self"]</code>. | |||
|
|||
Note: If the document's origin is not allowed to use the <code>"xr-spatial-tracking"</code> feature policy any [=immersive sessions=] will be blocked, because all [=immersive sessions=] require some use of spatial tracking. [=Inline sessions=] will still be allowed, but restricted to only using the {{XRReferenceSpaceType/"viewer"}} {{XRReferenceSpace}}. | |||
|
|||
|
|||
Permissions API Integration {#permissions} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this section have a disclaimer that it's temporary and ought to move to the Permissions API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that's the case? E.g. web bluetooth doesn't have this disclaimer, and it would be really weird to upstream all of this machinery to that API I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://w3c.github.io/permissions/#permission-registry is here exactly for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, okay.
<dd> | ||
<pre class=idl> | ||
dictionary XRPermissionStatus: PermissionStatus { | ||
sequence<any> granted; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would call this features
, not granted
because it's hard to understand what that is without a lot of context. It kind of relates to #860 too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I find granted
clearer than features
. But open to changing if others feel differently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PermissionStatus
has a field called state
that can be set to granted
. It's super confusing that PermissionStatus
which reflects the status of the permission has a field called granted
that just return a list of any
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @toji opinions on naming?
<div class=algorithm data-algorithm="xr-permission-request-algorithm"> | ||
To <dfn lt="request the xr permission">request the "xr" permission</dfn> with an {{XRPermissionDescriptor}} |descriptor| and a {{XRPermissionStatus}} |status|, the UA MUST run the following steps: | ||
|
||
1. Set |status|'s {{XRPermissionStatus/granted}} to an empty {{FrozenArray}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: I don't know why this spec is using "1." for bullet points but it makes it a bit hard to compare to the generated spec.
<pre class=idl> | ||
dictionary XRPermissionStatus: PermissionStatus { | ||
sequence<any> granted; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This said, I wonder if we could delay this addition. Are there strong use cases for this? It would require implementations to be able to provide the list of enabled features without creating the session which may or may not an easy thing to do. If we don't have a strong use case, keeping the change small for now may be good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would require implementations to be able to provide the list of enabled features without creating the session which may or may not an easy thing to do
I don't understand why? The spec already requires you to compute which features have been granted when you requestSession(), this just exposes that list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In requestSession()
, you create an XRSession
and have the list of available features. Here, you should be able to check for permissions without a session.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping about this. I think dropping the attribute entirely would be better. The only benefit of returning the list of features is to tell which optional features are granted. It doesn't seem critical and if someone really cares, they shouldn't have them as optional in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this was part of the point of this change, see #794 . It's important for apps to know what optional features were granted.
So yeah, there was a strong use case, this was one of the main reasons we wanted to make this pull request.
1. The user agent MAY at this point perform any necessary steps, like showing permissions prompts, to determine if there is a clear signal of [=user intent=] for any features in |requiredFeatures| and |optionalFeatures|. | ||
1. For each |feature| in |consentRequired| perform the following steps: | ||
1. The user agent MAY at this point perform any necessary steps, like showing permissions prompts, to determine if there is a clear signal of [=user intent=] for |feature|. | ||
1. If a clear signal of [=user intent=] to enable |feature| has not been determined, set |status|'s {{PermissionStatus/state}} to {{PermissionState/"denied"}} and abort these steps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, the Permissions API has language for that. Maybe we can try to re-use it? #request-permission-to-use for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, this is not useful here, #request-permission-to-use
takes a whole permission descriptor, we're requesting stuff for individual subfeatures. It would be nice if the permissions spec exposed a more scoped way to do prompts, but it doesn't, everything has to use a descriptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-using the wording would be a first step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
<div class=algorithm data-algorithm="xr-permission-query-algorithm"> | ||
To query the "xr" permission with an {{XRPermissionDescriptor}} |descriptor| and a {{XRPermissionStatus}} |status|, the UA MUST run the following steps: | ||
|
||
1. Set |status|'s {{PermissionStatus/state}} to |descriptor|'s [=permission state=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically the base algorithm to read the permission state. This is entirely fine to do. However, the way it's described in the spec makes it unclear to me whether this is taking into account the optional and required features. Unfortunately, I'm running out of time to review this :(
Sorry that I'm late to the review party due to holidays but from an API consumer / framework writer perspective this looks really solid and addresses all of my concerns. Great work, Manish! |
54f830c
to
8a4a443
Compare
Addressed. The last commit is the one moving stuff over to using devices, not sessions. |
@mounirlamouri review ping, let's get this merged 😄 |
/agenda to check for any final issues before landing |
This is implemented on the Oculus side. |
Please let me know if there were any issues implementing the API and if you think it could be better! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this has merged. FWIW, I did review this last week but didn't submit my changes. My concern was that basically most of my comments were ignored so I'm not sure what you wanted me to look at.
@@ -256,6 +262,7 @@ Each time the [=list of immersive XR devices=] changes the user agent should <df | |||
1. [=Shut down the session|Shut down=] any active {{XRSession}}s. | |||
1. Set the [=XR compatible=] boolean of all {{WebGLRenderingContextBase}} instances to <code>false</code>. | |||
1. [=Queue a task=] to [=fire an event=] named {{devicechange!!event}} on the [=context object=]. | |||
1. [=Queue a task=] to fire appropriate <code>change</code> events on any {{XRPermissionStatus}} objects who are affected by the change in the [=XR/immersive XR device=] or [=inline XR device=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would an update in the list of available device have an impact on the permissions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because permissions being granted is the intersection of the device supporting it and the user allowing it. This could be changed, but I was trying to keep the behavior of permissions as close to the existing features behavior as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically the fallout of making it no longer require an XRSession (which was definitely a good decision): features are still tied to devices, so changing the device can invalidate permissions.
It could be expanded to not require this, we can file a followup issue about that. There's some concern about how much permissions should persist between devices anyway.
1. If |resolved| is <code>false</code>, run the following steps: | ||
1. Let |descriptor| be an {{XRPermissionDescriptor}} initialized with |session|, |options|' {{XRSessionInit/requiredFeatures}}, and |options|' {{XRSessionInit/optionalFeatures}}. | ||
1. Let |status| be an {{XRPermissionStatus}}, initially <code>null</code> | ||
1. [=Request the xr permission=] with |descriptor| and |status|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping about this
<dd> | ||
<pre class=idl> | ||
dictionary XRPermissionStatus: PermissionStatus { | ||
sequence<any> granted; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PermissionStatus
has a field called state
that can be set to granted
. It's super confusing that PermissionStatus
which reflects the status of the permission has a field called granted
that just return a list of any
.
<pre class=idl> | ||
dictionary XRPermissionStatus: PermissionStatus { | ||
sequence<any> granted; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping about this. I think dropping the attribute entirely would be better. The only benefit of returning the list of features is to tell which optional features are granted. It doesn't seem critical and if someone really cares, they shouldn't have them as optional in the first place.
It will avoid to have PR author sending rendered output as in immersive-web#900
Rendered
This makes our feature request algorithm reuse machinery from the Permissions API, making it possible to do things like query consent status.
We define a single "xr" feature, however the query is done through a new
XRPermissionDescriptor
type which contains additional information about the requested features and the session.In the current implementation, requested features are not persisted across sessions (which enables sessions with different modes, and sessions using different devices to have different granted features). However, there is nothing stopping the user agent from persisting granted features where it feels it prudent, since the spec relies on there being a "clear signal of user intent".
I'm not 100% sure of this approach, and I suspect this may go through a bunch of changes, hence the draft PR.
r? @NellWaliczek @toji
/fixes #794, /fixes #722, /fixes #702, /fixes #725
(maybe also #725?)