Skip to content

Commit

Permalink
supportsSession->sessionSupported, resolves w/ bool
Browse files Browse the repository at this point in the history
Fixes #824. Acts on feedback from the TAG that supportsSession should
resolve with a boolean rather than reject when a session mode is not
supported. In order to aid developers the method name was changed so
that previous uses of the old method will be clearly identified as
failing, rather than silently report that a session was supported that
shouldn't be because the app failed to check the resolved boolean value.
  • Loading branch information
toji committed Sep 11, 2019
1 parent 5834078 commit cd8086f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 27 deletions.
32 changes: 17 additions & 15 deletions explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ The basic steps most WebXR applications will go through are:

The UA will identify an available physical unit of XR hardware that can present imagery to the user, referred to here as an "XR device". On desktop clients this will usually be a headset peripheral; on mobile clients it may represent the mobile device itself in conjunction with a viewer harness (e.g., Google Cardboard/Daydream or Samsung Gear VR). It may also represent devices without stereo-presentation capabilities but with more advanced tracking, such as ARCore/ARKit-compatible devices. Any queries for XR capabilities or functionality are implicitly made against this device.

> **Non-normative Note:** If there are multiple XR devices available, the UA will need to pick which one to expose. The UA is allowed to use any criteria it wishes to select which device is used, including settings UI that allow users to manage device priority. Calling `navigator.xr.supportsSession` or `navigator.xr.requestSession` with `'inline'` should **not** trigger device-selection UI, however, as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation.
> **Non-normative Note:** If there are multiple XR devices available, the UA will need to pick which one to expose. The UA is allowed to use any criteria it wishes to select which device is used, including settings UI that allow users to manage device priority. Calling `navigator.xr.sessionSupported` or `navigator.xr.requestSession` with `'inline'` should **not** trigger device-selection UI, however, as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation.
It's possible that even if no XR device is available initially, one may become available while the application is running, or that a previously available device becomes unavailable. This will be most common with PC peripherals that can be connected or disconnected at any time. Pages can listen to the `devicechange` event emitted on `navigator.xr` to respond to changes in device availability after the page loads. (XR devices already available when the page loads will not cause a `devicechange` event to be fired.) `devicechange` fires an event of type `Event`.

Expand All @@ -84,9 +84,9 @@ navigator.xr.addEventListener('devicechange', checkForXRSupport);

Interacting with an XR device is done through the `XRSession` interface, but before any XR-enabled page requests a session it should first query to determine if the type of XR content desired is supported by the current hardware and UA. If it is, the page can then advertise XR functionality to the user. (For example, by adding a button to the page that the user can click to start XR content.)

The `navigator.xr.supportsSession` function is used to check if the device supports the XR capabilities the application needs. It takes an "XR mode" describing the desired functionality and returns a promise which resolves if the device can successfully create an `XRSession` using that mode. The call rejects otherwise.
The `navigator.xr.sessionSupported` function is used to check if the device supports the XR capabilities the application needs. It takes an "XR mode" describing the desired functionality and returns a promise which resolves with _true_ if the device can successfully create an `XRSession` using that mode. The call resolves with _false_ otherwise.

Querying for support this way is necessary because it allows the application to detect what XR modes are available prior to requesting an `XRSession`, which may engage the XR device sensors and begin presentation. This can incur significant power or performance overhead on some systems and may have side effects such as taking over the user's screen, launching a status tray or storefront, or terminating another application's access to XR hardware. Calling `navigator.xr.supportsSession` must not interfere with any running XR applications on the system or have any user-visible side effects.
Querying for support this way is necessary because it allows the application to detect what XR modes are available prior to requesting an `XRSession`, which may engage the XR device sensors and begin presentation. This can incur significant power or performance overhead on some systems and may have side effects such as taking over the user's screen, launching a status tray or storefront, or terminating another application's access to XR hardware. Calling `navigator.xr.sessionSupported` must not interfere with any running XR applications on the system or have any user-visible side effects.

There are two XR modes that can be requested:

Expand All @@ -106,20 +106,22 @@ async function checkForXRSupport() {
// presentation (for example: displaying in a headset). If the device has that
// capability the page will want to add an "Enter VR" button to the page (similar to
// a "Fullscreen" button) that starts the display of immersive VR content.
navigator.xr.supportsSession('immersive-vr').then(() => {
var enterXrBtn = document.createElement("button");
enterXrBtn.innerHTML = "Enter VR";
enterXrBtn.addEventListener("click", beginXRSession);
document.body.appendChild(enterXrBtn);
}).catch((reason) => {
console.log("Session not supported: " + reason);
navigator.xr.sessionSupported('immersive-vr').then((supported) => {
if (supported) {
var enterXrBtn = document.createElement("button");
enterXrBtn.innerHTML = "Enter VR";
enterXrBtn.addEventListener("click", beginXRSession);
document.body.appendChild(enterXrBtn);
} else {
console.log("Session not supported: " + reason);
}
});
}
```

### Requesting a Session

After confirming that the desired mode is available with `navigator.xr.supportsSession()`, the application will need to request an `XRSession` instance with the `navigator.xr.requestSession()` method in order to interact with XR device's presentation or tracking capabilities.
After confirming that the desired mode is available with `navigator.xr.sessionSupported()`, the application will need to request an `XRSession` instance with the `navigator.xr.requestSession()` method in order to interact with XR device's presentation or tracking capabilities.

```js
function beginXRSession() {
Expand All @@ -137,7 +139,7 @@ function beginXRSession() {

In this sample, the `beginXRSession` function, which is assumed to be run by clicking the "Enter VR" button in the previous sample, requests an `XRSession` that operates in `immersive-vr` mode. The `requestSession` method returns a promise that resolves to an `XRSession` upon success. In addition to the `XRSessionMode`, developers may supply an `XRSessionInit` dictionary containing the capabilities that the returned session must have. For more information, see [Feature dependencies](#feature-dependencies).

If `supportsSession` resolved for a given mode, then requesting a session with the same mode should be reasonably expected to succeed, barring external factors (such as `requestSession` not being called in a user activation event for an immersive session.) The UA is ultimately responsible for determining if it can honor the request.
If `sessionSupported` resolved to _true_ for a given mode, then requesting a session with the same mode should be reasonably expected to succeed, barring external factors (such as `requestSession` not being called in a user activation event for an immersive session.) The UA is ultimately responsible for determining if it can honor the request.

Only one immersive session per XR hardware device is allowed at a time across the entire UA. If an immersive session is requested and the UA already has an active immersive session or a pending request for an immersive session, then the new request must be rejected. All inline sessions are [suspended](#handling-suspended-sessions) when an immersive session is active. Inline sessions are not required to be created within a user activation event unless paired with another option that explicitly does require it.

Expand Down Expand Up @@ -365,7 +367,7 @@ function beginInlineXRSession() {

Immersive and inline sessions may run their render loops at at different rates. During immersive sessions the UA runs the rendering loop at the XR device's native refresh rate. During inline sessions the UA runs the rendering loop at the refresh rate of page (aligned with `window.requestAnimationFrame`.) The method of computation of `XRView` projection and view matrices also differs between immersive and inline sessions, with inline sessions taking into account the output canvas dimensions and possibly the position of the users head in relation to the canvas if that can be determined.

`navigator.xr.supportsSession()` will always return `true` when checking the support of `"inline"` sessions. The UA should not reject requests for an inline session unless the page's feature policy prevents it or unless a required feature is unavailable as described in [Feature dependencies](#feature-dependencies)). For example, the following use cases all depend on additional reference space types which would need to be enabled via the `XRSessionInit`:
`navigator.xr.sessionSupported()` will always resolve to `true` when checking the support of `"inline"` sessions. The UA should not reject requests for an inline session unless the page's feature policy prevents it or unless a required feature is unavailable as described in [Feature dependencies](#feature-dependencies)). For example, the following use cases all depend on additional reference space types which would need to be enabled via the `XRSessionInit`:
- Using phone rotation to view panoramic content.
- Taking advantage of 6DoF tracking on devices with no associated headset, like [ARCore](https://developers.google.com/ar/) or [ARKit](https://developer.apple.com/arkit/) enabled phones. (Note that this does not provide automatic camera access or composition)
- Making use of head-tracking features for devices like [zSpace](http://zspace.com/) systems.
Expand All @@ -391,7 +393,7 @@ Developers communicate their feature requirements by categorizing them into one
* **`requiredFeatures`** This feature must be available in order for the experience to function at all. If [explicit consent](privacy-security-explainer.md#explicit-consent) is necessary, users will be prompted in response to `xr.requestSession()`. Session creation will be rejected if the feature is unavailable for the XR device, if the UA determines the user does not wish the feature enabled, or if the UA does not recognize the feature being requested.
* **`optionalFeatures`** The experience would like to use this feature for the entire session, but can function without it. Again, if [explicit consent](privacy-security-explainer.md#explicit-consent) is necessary, users will be prompted in response to `xr.requestSession()`. However, session creation will succeed regardless of the feature's hardware support or user intent. Developers must not assume optional features are available in the session and check the result from attempting to use them.

(NOTE: `xr.supportsSession()` does not accept an `XRSessionInit` parameter and supplying one will have no effect)
(NOTE: `xr.sessionSupported()` does not accept an `XRSessionInit` parameter and supplying one will have no effect)

The following sample code represents the likely behavior of a warehouse-size experience. It depends on having an [`unbounded` reference space](spatial-tracking-explainer.md#unbounded-reference-space) and will reject creating the session if not available.

Expand Down Expand Up @@ -570,7 +572,7 @@ dictionary XRSessionInit {

[SecureContext, Exposed=Window] interface XR : EventTarget {
attribute EventHandler ondevicechange;
Promise<void> supportsSession(XRSessionMode mode);
Promise<boolean> sessionSupported(XRSessionMode mode);
Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit);
};

Expand Down
28 changes: 16 additions & 12 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ Application flow {#applicationflow}

Most applications using the WebXR Device API will follow a similar usage pattern:

* Query {{XR/supportsSession()|navigator.xr.supportsSession()}} to determine if the desired type of XR content is supported by the hardware and UA.
* Query {{XR/sessionSupported()|navigator.xr.sessionSupported()}} to determine if the desired type of XR content is supported by the hardware and UA.
* If so, advertise the XR content to the user.
* Wait for the user to [=triggered by user activation|trigger a user activation event=] indicating they want to begin viewing XR content.
* Request an {{XRSession}} within the user activation event with {{XR/requestSession()|navigator.xr.requestSession()}}.
Expand Down Expand Up @@ -214,7 +214,7 @@ XR {#xr-interface}
<pre class="idl">
[SecureContext, Exposed=Window] interface XR : EventTarget {
// Methods
Promise&lt;void&gt; supportsSession(XRSessionMode mode);
Promise&lt;boolean&gt; sessionSupported(XRSessionMode mode);
Promise&lt;XRSession&gt; requestSession(XRSessionMode mode, optional XRSessionInit options = {});

// Events
Expand Down Expand Up @@ -267,31 +267,35 @@ The user agent <dfn>ensures an immersive XR device is selected</dfn> by running

The <dfn attribute for="XR">ondevicechange</dfn> attribute is an [=Event handler IDL attribute=] for the {{devicechange}} event type.

<div class="algorithm" data-algorithm="supports-session">
The <dfn method for="XR">supportsSession(|mode|)</dfn> method queries if a given |mode| is supported by the user agent and device capabilities.
<div class="algorithm" data-algorithm="session-supported">
The <dfn method for="XR">sessionSupported(|mode|)</dfn> method queries if a given |mode| is supported by the user agent and device capabilities.

When this method is invoked, it MUST run the following steps:

1. Let |promise| be [=a new Promise=].
1. If |mode| is {{XRSessionMode/"inline"}}, [=/resolve=] |promise| and return it.
1. If |mode| is {{XRSessionMode/"inline"}}, [=/resolve=] |promise| with <code>true</code> and return it.
1. Run the following steps [=in parallel=]:
1. [=ensures an immersive XR device is selected|Ensure an immersive XR device is selected=].
1. If the [=XR/immersive XR device=] is null, [=reject=] |promise| with a "{{NotSupportedError}}" {{DOMException}} and abort these steps.
1. If the [=XR/immersive XR device=]'s [=list of supported modes=] does not [=list/contain=] |mode|, [=reject=] |promise| with a "{{NotSupportedError}}" {{DOMException}} and abort these steps.
1. [=/Resolve=] |promise|.
1. If the [=XR/immersive XR device=] is null, [=/resolve=] |promise| with <code>false</code> and abort these steps.
1. If the [=XR/immersive XR device=]'s [=list of supported modes=] does not [=list/contain=] |mode|, [=/resolve=] |promise| with <code>false</code> and abort these steps.
1. [=/Resolve=] |promise| with <code>true</code>.
1. Return |promise|.

</div>

Calling {{XR/supportsSession()}} MUST NOT trigger device-selection UI as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation. Additionally, calling {{XR/supportsSession()}} MUST NOT interfere with any running XR applications on the system, and MUST NOT cause XR-related applications to launch such as system trays or storefronts.
Calling {{XR/sessionSupported()}} MUST NOT trigger device-selection UI as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation. Additionally, calling {{XR/sessionSupported()}} MUST NOT interfere with any running XR applications on the system, and MUST NOT cause XR-related applications to launch such as system trays or storefronts.

<div class="example">
The following code checks to see if {{immersive-vr}} sessions are supported.

<pre highlight="js">
navigator.xr.supportsSession('immersive-vr').then(() => {
// 'immersive-vr' sessions are supported.
// Page should advertise support to the user.
navigator.xr.sessionSupported('immersive-vr').then((supported) => {
if (supported) {
// 'immersive-vr' sessions are supported.
// Page should advertise support to the user.
} else {
// 'immersive-vr' sessions are not supported.
}
}
</pre>
</div>
Expand Down

0 comments on commit cd8086f

Please sign in to comment.