diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js index 0e46ace485799f2f602907e17b2f439d57bac2f8..da4eeecd12d6394ad080e9370c69e4e036416dbf 100644 --- a/src/react-components/ui-root.js +++ b/src/react-components/ui-root.js @@ -1,14 +1,14 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { getPreEntryMobileVRDeviceCaps } from "../utils/vr-caps-detect.js" class UIRoot extends Component { static propTypes = { - enterScene: PropTypes.func + enterScene: PropTypes.func, + mobileVRDeviceCaps: PropTypes.object }; componentDidMount = () => { - getPreEntryMobileVRDeviceCaps().then(x => console.log(x)) + console.log(this.props.mobileVRDeviceCaps); } render() { diff --git a/src/room.js b/src/room.js index a20f8653f15c912f180631c405a6bae032b86bb1..3c6009afb4206087cec36c2f1f634cdcc5eaccce 100644 --- a/src/room.js +++ b/src/room.js @@ -52,6 +52,8 @@ import registerNetworkSchemas from "./network-schemas"; import { inGameActions, config } from "./input-mappings"; import registerTelemetry from "./telemetry"; +import { getPreEntryMobileVRDeviceCaps } from "./utils/vr-caps-detect.js" + AFRAME.registerInputBehaviour("vive_trackpad_dpad4", vive_trackpad_dpad4); AFRAME.registerInputBehaviour("oculus_touch_joystick_dpad4", oculus_touch_joystick_dpad4); AFRAME.registerInputActivator("pressedmove", PressedMove); @@ -150,7 +152,11 @@ function onConnect() { document.getElementById("loader").style.display = "none"; } -document.addEventListener("DOMContentLoaded", () => { - ReactDOM.render(<UIRoot enterScene={enterScene} />, document.getElementById("ui-root")); - document.getElementById("loader").style.display = "none"; -}); +function mountUI() { + getPreEntryMobileVRDeviceCaps().then(mobileVRDeviceCaps => { + ReactDOM.render(<UIRoot {...{ mobileVRDeviceCaps, enterScene }} />, document.getElementById("ui-root")); + document.getElementById("loader").style.display = "none"; + }); +} + +document.addEventListener("DOMContentLoaded", () => mountUI()); diff --git a/src/utils/vr-caps-detect.js b/src/utils/vr-caps-detect.js index 4013e1bbc12a82439c6a55a45c12d158f98c4cca..54e79f9bb0b14ce44e6b7432b3a45cfd3e987088 100644 --- a/src/utils/vr-caps-detect.js +++ b/src/utils/vr-caps-detect.js @@ -3,10 +3,10 @@ const browser = detect(); // Precision on device detection is fuzzy -- we can sometimes know if a device is definitely // available, or definitely *not* available, and assume it may be available otherwise. -const VR_DEVICE_AVAILABILITY = { +export const VR_DEVICE_AVAILABILITY = { yes: "yes", // Implies VR can be launched into on this device immediately, in this browser no: "no", // Implies this VR device is definitely not supported regardless of browser - maybe: "maybe" // Implies this device may support this VR device, but may not be installed or in the right browser + maybe: "maybe" // Implies this device may support this VR platform, but may not be installed or in a compatible browser }; function hasPhysicalScreenDimensions(w, h) { @@ -18,27 +18,21 @@ function hasPhysicalScreenDimensions(w, h) { return Math.abs(w - width) < 3 && Math.abs(h - height) < 3; } -function matchesScreenSizesAndUserAgentRegex(sizes, regex) { - return !!(sizes.find(s => hasPhysicalScreenDimensions(...s)) && navigator.userAgent.match(regex)); +function matchesScreenSizesAndUserAgentRegexes(sizes, regexes) { + return !!(sizes.find(s => hasPhysicalScreenDimensions(...s)) && regexes.find(r => navigator.userAgent.match())); } -function isGearVRCompatibleDevice() { - // Modern Samsung Galaxy devices have model numbers in the user agent of the form SX-XXXX - return matchesScreenSizesAndUserAgentRegex([[1440, 2560], [1440, 2960]], /\WS.-.....?\W/); +function isMaybeGearVRCompatibleDevice() { + // Modern Samsung Galaxy devices have model numbers in the user agent of the form SX-XXXX or GT-XXXX for note 8 + return matchesScreenSizesAndUserAgentRegexes([[1440, 2560], [1440, 2960]], [/\WS.-.....?\W/, /\WGT-.....?\W/]); } -function isGooglePixelPhone() { - return matchesScreenSizesAndUserAgentRegex([[1080, 1920], [1440, 2560]], /\WPixel\W/); -} - -function isKnownDaydreamCompatibleDevice() { - // Samsung S6, S7, and Note 5 do not support Daydream, but other GearVR compatiable devices - // do. Instead of doing fine-grained model detection we will just assume they are all compatible. - if (isGearVRCompatibleDevice()) return true; - if (isGooglePixelPhone()) return true; +function isMaybeDaydreamCompatibleDevice() { + if (isMaybeGearVRCompatibleDevice()) return true; - // Note this is non-exhaustive -- this function may return false for compatible devices. - return false; + // List of resolutions of Pixel line of phones as well as other announced Daydream compatible + // phones. This list may need to be updated as new phones roll out. + return matchesScreenSizesAndUserAgentRegexes([[1080, 1920], [1440, 2560], [1440, 2880]], [/\WAndroid\W/]); } // Captures the potential ways a user can launch into mobile VR *before* a headset is attached to the phone. @@ -48,21 +42,19 @@ function isKnownDaydreamCompatibleDevice() { // on this device, returns "no" if that platform cannot be supported on any browser, and "maybe" if the // device potentially could support that platform if a different browser was running. export async function getPreEntryMobileVRDeviceCaps() { - const isWebVREnabled = !!navigator.getVRDisplays; - const isWebVREnabledChrome = !!(isWebVREnabled && browser.name === "chrome"); - const isAndroidCompatible = - navigator.userAgent.match(/\Wandroid\W/i) && !navigator.userAgent.match(/\Wwindows phone\W/i); + const isWebVRCapableBrowser = !!navigator.getVRDisplays; + const isDaydreamCapableBrowser = !!(isWebVRCapableBrowser && browser.name === "chrome"); // We only consider GearVR hardware support as "maybe" and never return "yes" for GearVR. The only browser // that will detect GearVR outside of VR is Samsung Internet, and we'd prefer to launch into Oculus // Browser for now since Samsung Internet requires an additional WebVR installation + flag. - const gearvr = isGearVRCompatibleDevice() ? VR_DEVICE_AVAILABILITY.maybe : VR_DEVICE_AVAILABILITY.no; + const gearvr = isMaybeGearVRCompatibleDevice() ? VR_DEVICE_AVAILABILITY.maybe : VR_DEVICE_AVAILABILITY.no; // For daydream detection, we first check if they are on an Android compatible device, and assume they // may support daydream *unless* this browser has WebVR capabilities, in which case we can do better. - let daydream = isAndroidCompatible ? VR_DEVICE_AVAILABILITY.maybe : VR_DEVICE_AVAILABILITY.no; + let daydream = isMaybeDaydreamCompatibleDevice() ? VR_DEVICE_AVAILABILITY.maybe : VR_DEVICE_AVAILABILITY.no; - if (isWebVREnabled) { + if (isWebVRCapableBrowser) { // For daydream detection, if this is a WebVR browser we can increase confidence in daydream compatibility. const displays = await navigator.getVRDisplays(); const hasDaydreamWebVRDevice = displays.find(d => d.displayName.match(/\Wdaydream\W/i)); @@ -70,8 +62,8 @@ export async function getPreEntryMobileVRDeviceCaps() { if (hasDaydreamWebVRDevice) { // If we detected daydream via WebVR daydream = VR_DEVICE_AVAILABILITY.yes; - } else if (isWebVREnabledChrome || !isKnownDaydreamCompatibleDevice()) { - // If we didn't detect daydream in chrome (which is known to detect it) and we are on a known compatible device + } else if (isDaydreamCapableBrowser) { + // If we didn't detect daydream in a daydream capable browser, we definitely can't run daydream at all. daydream = VR_DEVICE_AVAILABILITY.no; } }