All files / Sources/Common/System/MobileVR index.js

48.27% Statements 28/58
45.45% Branches 20/44
33.33% Functions 2/6
45.28% Lines 24/53

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145        1x       1x               1x     1x       1x     1x     1x     1x   1x             192x       96x                                                 1x 102x 102x         102x           102x 6x       96x 96x 192x 192x         96x 96x                       1x                                                                      
// Inspired from https://github.com/immersive-web/cardboard-vr-display/blob/master/src/dpdb.js
import dpdb from './dpdb.json';
import headsets from './headsets';
 
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
 
/* eslint-disable */
const isMobile =
  /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
    userAgent
  ) ||
  /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
    userAgent.substr(0, 4)
  );
/* eslint-enable */
 
const isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
 
const isWebViewAndroid =
  userAgent.indexOf('Version') !== -1 &&
  userAgent.indexOf('Android') !== -1 &&
  userAgent.indexOf('Chrome') !== -1;
 
const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);
 
const isFirefoxAndroid =
  userAgent.indexOf('Firefox') !== -1 && userAgent.indexOf('Android') !== -1;
 
const width =
  Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
 
const height =
  Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
 
const hardware = { width, height };
 
// ----------------------------------------------------------------------------
 
function matchRules(rule, ua, screenWidth, screenHeight) {
  // We can only match 'ua' and 'res' rules, not other types like 'mdmh'
  // (which are meant for native platforms).
  if (!rule.ua && !rule.res) return false;
 
  // If our user agent string doesn't contain the indicated user agent string,
  // the match fails.
  if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
 
  // If the rule specifies screen dimensions that don't correspond to ours,
  // the match fails.
  if (rule.res) {
    if (!rule.res[0] || !rule.res[1]) return false;
    const [resX, resY] = rule.res;
 
    // Compare min and max so as to make the order not matter, i.e., it should
    // be true that 640x480 == 480x640.
    if (
      Math.min(screenWidth, screenHeight) !== Math.min(resX, resY) ||
      Math.max(screenWidth, screenHeight) !== Math.max(resX, resY)
    ) {
      return false;
    }
  }
 
  return true;
}
 
// ----------------------------------------------------------------------------
 
/* eslint-disable no-continue */
function extractDeviceParameters() {
  for (let i = 0; i < dpdb.devices.length; i++) {
    const device = dpdb.devices[i];
    Iif (!device.rules) {
      console.warn(`Device[${i}] has no rules section.`);
      continue;
    }
 
    Iif (device.type !== 'ios' && device.type !== 'android') {
      console.warn(`Device[${i}] has invalid type.`);
      continue;
    }
 
    // See if this device is of the appropriate type.
    if (isIOS !== (device.type === 'ios')) {
      continue;
    }
 
    // See if this device matches any of the rules:
    let matched = false;
    for (let j = 0; j < device.rules.length; j++) {
      const rule = device.rules[j];
      Iif (matchRules(rule, userAgent, width, height)) {
        matched = true;
        break;
      }
    }
    if (!matched) {
      continue;
    }
 
    // device.dpi might be an array of [ xdpi, ydpi] or just a scalar.
    hardware.xdpi = device.dpi[0] || device.dpi;
    hardware.ydpi = device.dpi[1] || device.dpi;
    hardware.bevelMm = device.bw;
  }
}
/* eslint-enable no-continue */
 
// Apply rules
extractDeviceParameters();
 
// ----------------------------------------------------------------------------
 
function getVRHeadset() {
  return new Promise((resolve, reject) => {
    const body = document.querySelector('body');
    const selector = document.createElement('select');
    selector.innerHTML = headsets
      .map((headset, idx) => `<option value="${idx}">${headset.label}</option>`)
      .join('');
    selector.style.zIndex = 1000;
    selector.style.position = 'absolute';
    selector.style.left = '50%';
    selector.style.top = '50%';
    selector.style.transform = 'translate(-50%, -50%)';
    selector.addEventListener('change', (e) => {
      body.removeChild(selector);
      resolve(headsets[Number(e.target.value)]);
    });
    body.appendChild(selector);
  });
}
 
// ----------------------------------------------------------------------------
 
export default {
  isMobile,
  isIOS,
  isWebViewAndroid,
  isSafari,
  isFirefoxAndroid,
  hardware,
  getVRHeadset,
};