Source: lib/polyfill/orientation.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.polyfill.Orientation');
  7. goog.require('shaka.log');
  8. goog.require('shaka.util.FakeEvent');
  9. goog.require('shaka.util.FakeEventTarget');
  10. goog.require('shaka.polyfill');
  11. /**
  12. * @summary A polyfill for systems that do not implement screen.orientation.
  13. * For now, this only handles systems that implement the deprecated
  14. * window.orientation feature... e.g. iPad.
  15. * @export
  16. */
  17. shaka.polyfill.Orientation = class {
  18. /**
  19. * Install the polyfill if needed.
  20. * @export
  21. */
  22. static install() {
  23. if (screen.orientation && screen.orientation.unlock) {
  24. // Not needed.
  25. shaka.log.info('Using native screen.orientation');
  26. return;
  27. }
  28. if (screen.orientation != undefined) {
  29. // There are some platforms where screen.orientation is defined but
  30. // incomplete (e.g. Safari).
  31. // Install a very simple polyfill in that case.
  32. shaka.polyfill.Orientation.installBasedOnScreenMethods_();
  33. } else if (window.orientation != undefined) {
  34. // There is no way to check to see if the 'orientationchange' event exists
  35. // on window, which could theoretically lead to this making a
  36. // screen.orientation object that doesn't actually work.
  37. // However, it looks like all platforms that support the deprecated
  38. // window.orientation feature also support that event.
  39. shaka.polyfill.Orientation.installBasedOnWindowMethods_();
  40. }
  41. }
  42. /**
  43. * Modifies screen.orientation to add no-ops for missing methods.
  44. * Meant for cases where screen.orientation is defined, but has missing
  45. * methods that cannot be properly polyfilled.
  46. * @private
  47. */
  48. static installBasedOnScreenMethods_() {
  49. if (screen.orientation.lock === undefined) {
  50. screen.orientation.lock = (orientation) => {
  51. shaka.log.info('screen.orientation.lock is a no-op');
  52. return Promise.resolve();
  53. };
  54. }
  55. if (screen.orientation.unlock === undefined) {
  56. screen.orientation.unlock = () => {
  57. shaka.log.info('screen.orientation.unlock is a no-op');
  58. };
  59. }
  60. }
  61. /**
  62. * Makes a polyfill for orientation, based on window methods.
  63. * Note that some of the features this is based on are deprecated, so this
  64. * will not necessarily work on all platforms.
  65. * @private
  66. */
  67. static installBasedOnWindowMethods_() {
  68. const orientation = new shaka.polyfill.Orientation.FakeOrientation();
  69. screen.orientation = /** @type {!ScreenOrientation} */ (orientation);
  70. const setValues = () => {
  71. switch (window.orientation) {
  72. case -90:
  73. orientation.type = 'landscape-secondary';
  74. orientation.angle = 270;
  75. break;
  76. case 0:
  77. orientation.type = 'portrait-primary';
  78. orientation.angle = 0;
  79. break;
  80. case 90:
  81. orientation.type = 'landscape-primary';
  82. orientation.angle = 90;
  83. break;
  84. case 180:
  85. orientation.type = 'portrait-secondary';
  86. orientation.angle = 180;
  87. break;
  88. }
  89. };
  90. setValues();
  91. window.addEventListener('orientationchange', () => {
  92. setValues();
  93. orientation.dispatchChangeEvent();
  94. });
  95. }
  96. };
  97. shaka.polyfill.Orientation.FakeOrientation =
  98. class extends shaka.util.FakeEventTarget {
  99. /** */
  100. constructor() {
  101. super();
  102. /** @type {string} */
  103. this.type = '';
  104. /** @type {number} */
  105. this.angle = 0;
  106. }
  107. /** Dispatch a 'change' event. */
  108. dispatchChangeEvent() {
  109. const event = new shaka.util.FakeEvent('change');
  110. this.dispatchEvent(event);
  111. }
  112. /**
  113. * @param {string} orientation
  114. * @return {!Promise}
  115. */
  116. lock(orientation) {
  117. /**
  118. * @param {string} orientation
  119. * @return {boolean}
  120. */
  121. const lockOrientation = (orientation) => {
  122. if (screen.lockOrientation) {
  123. return screen.lockOrientation(orientation);
  124. }
  125. if (screen.mozLockOrientation) {
  126. return screen.mozLockOrientation(orientation);
  127. }
  128. if (screen.msLockOrientation) {
  129. return screen.msLockOrientation(orientation);
  130. }
  131. return false;
  132. };
  133. let success = false;
  134. // The set of input strings for screen.orientation.lock and for
  135. // screen.lockOrientation are almost, but not entirely, the same.
  136. switch (orientation) {
  137. case 'natural':
  138. success = lockOrientation('default');
  139. break;
  140. case 'any':
  141. // It's not quite clear what locking the screen orientation to 'any'
  142. // is supposed to mean... presumably, that's equivalent to not being
  143. // locked?
  144. success = true;
  145. this.unlock();
  146. break;
  147. default:
  148. success = lockOrientation(orientation);
  149. break;
  150. }
  151. // According to the docs, there "may be a delay" between the
  152. // lockOrientation method being called and the screen actually being
  153. // locked. Unfortunately, without any idea as to how long that delay is,
  154. // and with no events to listen for, we cannot account for it here.
  155. if (success) {
  156. return Promise.resolve();
  157. }
  158. // Either locking was not available, or the process failed... either way,
  159. // reject this with a mock error.
  160. // This should be a DOMException, but there is not a public constructor for
  161. // that. So we make this look-alike instead.
  162. const unsupportedKeySystemError =
  163. new Error('screen.orientation.lock() is not available on this device');
  164. unsupportedKeySystemError.name = 'NotSupportedError';
  165. unsupportedKeySystemError['code'] = DOMException.NOT_SUPPORTED_ERR;
  166. return Promise.reject(unsupportedKeySystemError);
  167. }
  168. /** Unlock the screen orientation. */
  169. unlock() {
  170. // screen.unlockOrientation has a return value, but
  171. // screen.orientation.unlock does not. So ignore the return value.
  172. if (screen.unlockOrientation) {
  173. screen.unlockOrientation();
  174. } else if (screen.mozUnlockOrientation) {
  175. screen.mozUnlockOrientation();
  176. } else if (screen.msUnlockOrientation) {
  177. screen.msUnlockOrientation();
  178. }
  179. }
  180. };
  181. shaka.polyfill.register(shaka.polyfill.Orientation.install);