Skip to content
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

Merged
merged 8 commits into from
Feb 24, 2020

Conversation

Manishearth
Copy link
Contributor

@Manishearth Manishearth commented Nov 6, 2019

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?)

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}
---------
Copy link
Member

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).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me.

Copy link
Member

@toji toji left a 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}}.
Copy link
Member

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.
Copy link
Member

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?

Copy link
Contributor Author

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=].
Copy link
Member

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.

Copy link
Member

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?

Copy link
Contributor

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|.
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point

@Manishearth Manishearth marked this pull request as ready for review November 8, 2019 18:36
avadacatavra pushed a commit to avadacatavra/webxr that referenced this pull request Nov 14, 2019
toji pushed a commit that referenced this pull request Nov 14, 2019
@Manishearth
Copy link
Contributor Author

/agenda to ask people to look at it

Copy link
Member

@NellWaliczek NellWaliczek left a 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=].
Copy link
Member

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?

Copy link
Member

@NellWaliczek NellWaliczek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!!

@mounirlamouri
Copy link
Contributor

self mentioning to have it in my queue @mounirlamouri

@toji toji added the agenda Request discussion in the next telecon/FTF label Dec 2, 2019
mounirlamouri added a commit to mounirlamouri/webxr that referenced this pull request Dec 2, 2019
It will avoid to have PR author sending rendered output as in immersive-web#900
Copy link
Contributor

@mounirlamouri mounirlamouri left a 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;
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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|.
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping about this

Copy link
Contributor Author

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.

image

@@ -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}
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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&lt;any&gt; granted;
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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}}.
Copy link
Contributor

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&lt;any&gt; granted;
};
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@mounirlamouri mounirlamouri Dec 3, 2019

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.

Copy link
Contributor

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.

Copy link
Contributor Author

@Manishearth Manishearth Feb 25, 2020

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.
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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=].
Copy link
Contributor

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 :(

@TrevorFSmith
Copy link

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!

@AdaRoseCannon AdaRoseCannon added agenda Request discussion in the next telecon/FTF and removed agenda Request discussion in the next telecon/FTF labels Dec 13, 2019
@Manishearth
Copy link
Contributor Author

Addressed. The last commit is the one moving stuff over to using devices, not sessions.

@Manishearth
Copy link
Contributor Author

@mounirlamouri review ping, let's get this merged 😄

@Manishearth
Copy link
Contributor Author

/agenda to check for any final issues before landing

@cabanier
Copy link
Member

This is implemented on the Oculus side.
@ravi, doesn't Magic Leap have this implemented as well?

@Manishearth
Copy link
Contributor Author

Please let me know if there were any issues implementing the API and if you think it could be better!

@Manishearth Manishearth merged commit 41612a7 into immersive-web:master Feb 24, 2020
@Manishearth Manishearth deleted the consent-tracking branch February 24, 2020 18:37
Copy link
Contributor

@mounirlamouri mounirlamouri left a 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=].
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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|.
Copy link
Contributor

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&lt;any&gt; granted;
Copy link
Contributor

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&lt;any&gt; granted;
};
Copy link
Contributor

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.

kearwood pushed a commit to kearwood/webxr that referenced this pull request Mar 11, 2020
kearwood pushed a commit to kearwood/webxr that referenced this pull request Mar 11, 2020
It will avoid to have PR author sending rendered output as in immersive-web#900
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants