| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var vrShellUi = (function() { | 5 var vrShellUi = (function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 let scene = new ui.Scene(); | 8 let scene = new ui.Scene(); |
| 9 let sceneManager; | 9 let sceneManager; |
| 10 | 10 |
| 11 let uiRootElement = document.querySelector('#ui'); | 11 let uiRootElement = document.querySelector('#ui'); |
| 12 let uiStyle = window.getComputedStyle(uiRootElement); | 12 let uiStyle = window.getComputedStyle(uiRootElement); |
| 13 /** @const */ var ANIM_DURATION = 150; | 13 /** @const */ var ANIM_DURATION = 150; |
| 14 | 14 |
| 15 // This value should match the one in VrShellImpl.java | 15 // This value should match the one in VrShellImpl.java |
| 16 /** @const */ var UI_DPR = 1.2; | 16 /** @const */ var UI_DPR = 1.2; |
| 17 | 17 |
| 18 function getStyleFloat(style, property) { | 18 function getStyleFloat(style, property) { |
| 19 let value = parseFloat(style.getPropertyValue(property)); | 19 let value = parseFloat(style.getPropertyValue(property)); |
| 20 return isNaN(value) ? 0 : value; | 20 return isNaN(value) ? 0 : value; |
| 21 } | 21 } |
| 22 | 22 |
| 23 class ContentQuad { | 23 class ContentQuad { |
| 24 constructor() { | 24 constructor() { |
| 25 /** @const */ this.SCREEN_HEIGHT = 1.6; | 25 /** @const */ this.SCREEN_HEIGHT = 1.6; |
| 26 /** @const */ this.SCREEN_RATIO = 16 / 9; | 26 /** @const */ this.SCREEN_RATIO = 16 / 9; |
| 27 /** @const */ this.BROWSING_SCREEN_DISTANCE = 2.0; | 27 /** @const */ this.BROWSING_SCREEN_DISTANCE = 2.0; |
| 28 /** @const */ this.CINEMA_SCREEN_DISTANCE = 3.0; | 28 /** @const */ this.FULLSCREEN_DISTANCE = 3.0; |
| 29 | 29 |
| 30 let element = new api.UiElement(0, 0, 0, 0); | 30 let element = new api.UiElement(0, 0, 0, 0); |
| 31 element.setIsContentQuad(); | 31 element.setIsContentQuad(); |
| 32 element.setVisible(false); | 32 element.setVisible(false); |
| 33 element.setSize( | 33 element.setSize( |
| 34 this.SCREEN_HEIGHT * this.SCREEN_RATIO, this.SCREEN_HEIGHT); | 34 this.SCREEN_HEIGHT * this.SCREEN_RATIO, this.SCREEN_HEIGHT); |
| 35 element.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); | 35 element.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); |
| 36 this.elementId = scene.addElement(element); | 36 this.elementId = scene.addElement(element); |
| 37 } | 37 } |
| 38 | 38 |
| 39 setEnabled(enabled) { | 39 setEnabled(enabled) { |
| 40 let update = new api.UiElementUpdate(); | 40 let update = new api.UiElementUpdate(); |
| 41 update.setVisible(enabled); | 41 update.setVisible(enabled); |
| 42 scene.updateElement(this.elementId, update); | 42 scene.updateElement(this.elementId, update); |
| 43 } | 43 } |
| 44 | 44 |
| 45 setCinemaMode(enabled) { | 45 setFullscreen(enabled) { |
| 46 let anim = new api.Animation(this.elementId, ANIM_DURATION); | 46 let anim = new api.Animation(this.elementId, ANIM_DURATION); |
| 47 if (enabled) { | 47 if (enabled) { |
| 48 anim.setTranslation(0, 0, -this.CINEMA_SCREEN_DISTANCE); | 48 anim.setTranslation(0, 0, -this.FULLSCREEN_DISTANCE); |
| 49 } else { | 49 } else { |
| 50 anim.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); | 50 anim.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); |
| 51 } | 51 } |
| 52 scene.addAnimation(anim); | 52 scene.addAnimation(anim); |
| 53 } | 53 } |
| 54 | 54 |
| 55 // TODO(crbug/643815): Add a method setting aspect ratio (and possible | 55 // TODO(crbug/643815): Add a method setting aspect ratio (and possible |
| 56 // animation of changing it). | 56 // animation of changing it). |
| 57 | 57 |
| 58 getElementId() { | 58 getElementId() { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 onMouseLeave() { | 118 onMouseLeave() { |
| 119 this.configure(0.8, 0, 0); | 119 this.configure(0.8, 0, 0); |
| 120 } | 120 } |
| 121 }; | 121 }; |
| 122 | 122 |
| 123 class Controls { | 123 class Controls { |
| 124 constructor(contentQuadId) { | 124 constructor(contentQuadId) { |
| 125 this.buttons = []; | 125 this.buttons = []; |
| 126 let descriptors = [ | 126 let descriptors = [ |
| 127 ['#back', function() { | 127 ['#back', function() { |
| 128 // If we are in cinema mode, revert to standard mode on back press. | 128 api.doAction(api.Action.HISTORY_BACK); |
| 129 if (sceneManager.cinemaMode) { | |
| 130 // TODO(crbug/644511): Send a message back to native to handle | |
| 131 // switching back to standard mode and out of full screen instead | |
| 132 // of only changing the mode here. | |
| 133 sceneManager.setMode(sceneManager.mode, sceneManager.menuMode, | |
| 134 false /* Cinema Mode */); | |
| 135 } else { | |
| 136 api.doAction(api.Action.HISTORY_BACK); | |
| 137 } | |
| 138 }], | 129 }], |
| 139 ['#reload', function() { | 130 ['#reload', function() { |
| 140 api.doAction(api.Action.RELOAD); | 131 api.doAction(api.Action.RELOAD); |
| 141 }], | 132 }], |
| 142 ['#forward', function() { | 133 ['#forward', function() { |
| 143 api.doAction(api.Action.HISTORY_FORWARD); | 134 api.doAction(api.Action.HISTORY_FORWARD); |
| 144 }], | 135 }], |
| 145 ]; | 136 ]; |
| 146 | 137 |
| 147 /** @const */ var BUTTON_SPACING = 0.136; | 138 /** @const */ var BUTTON_SPACING = 0.136; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 update.setVisible(false); | 222 update.setVisible(false); |
| 232 update.setLockToFieldOfView(true); | 223 update.setLockToFieldOfView(true); |
| 233 scene.updateElement(this.transientWarning.uiElementId, update); | 224 scene.updateElement(this.transientWarning.uiElementId, update); |
| 234 } | 225 } |
| 235 | 226 |
| 236 setEnabled(enabled) { | 227 setEnabled(enabled) { |
| 237 this.enabled = enabled; | 228 this.enabled = enabled; |
| 238 this.updateState(); | 229 this.updateState(); |
| 239 } | 230 } |
| 240 | 231 |
| 241 setSecureOrigin(secure) { | 232 setSecure(secure) { |
| 242 this.isSecureOrigin = secure; | 233 this.secure = secure; |
| 243 this.updateState(); | 234 this.updateState(); |
| 244 } | 235 } |
| 245 | 236 |
| 246 updateState() { | 237 updateState() { |
| 247 /** @const */ var TRANSIENT_TIMEOUT_MS = 30000; | 238 /** @const */ var TRANSIENT_TIMEOUT_MS = 30000; |
| 248 | 239 |
| 249 let visible = (this.enabled && !this.isSecureOrigin); | 240 let visible = (this.enabled && !this.secure); |
| 250 if (this.secureOriginTimer) { | 241 if (this.secureOriginTimer) { |
| 251 clearInterval(this.secureOriginTimer); | 242 clearInterval(this.secureOriginTimer); |
| 252 this.secureOriginTimer = null; | 243 this.secureOriginTimer = null; |
| 253 } | 244 } |
| 254 if (visible) { | 245 if (visible) { |
| 255 this.secureOriginTimer = setTimeout( | 246 this.secureOriginTimer = setTimeout( |
| 256 this.onTransientTimer.bind(this), TRANSIENT_TIMEOUT_MS); | 247 this.onTransientTimer.bind(this), TRANSIENT_TIMEOUT_MS); |
| 257 } | 248 } |
| 258 this.showOrHideWarnings(visible); | 249 this.showOrHideWarnings(visible); |
| 259 } | 250 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 271 let update = new api.UiElementUpdate(); | 262 let update = new api.UiElementUpdate(); |
| 272 update.setVisible(false); | 263 update.setVisible(false); |
| 273 scene.updateElement(this.transientWarning.uiElementId, update); | 264 scene.updateElement(this.transientWarning.uiElementId, update); |
| 274 this.secureOriginTimer = null; | 265 this.secureOriginTimer = null; |
| 275 scene.flush(); | 266 scene.flush(); |
| 276 } | 267 } |
| 277 }; | 268 }; |
| 278 | 269 |
| 279 class Omnibox { | 270 class Omnibox { |
| 280 constructor(contentQuadId) { | 271 constructor(contentQuadId) { |
| 281 /** @const */ var VISIBILITY_TIMEOUT_MS = 3000; | |
| 282 | |
| 283 this.domUiElement = new DomUiElement('#omni-container'); | 272 this.domUiElement = new DomUiElement('#omni-container'); |
| 284 this.enabled = false; | 273 this.enabled = false; |
| 285 this.secure = false; | 274 this.level = 0; |
| 286 this.visibilityTimeout = VISIBILITY_TIMEOUT_MS; | 275 this.visibilityTimeout = 0; |
| 287 this.visibilityTimer = null; | 276 this.visibilityTimer = null; |
| 288 this.nativeState = {}; | 277 this.nativeState = {}; |
| 289 | 278 |
| 290 // Initially invisible. | 279 // Initially invisible. |
| 291 let update = new api.UiElementUpdate(); | 280 let update = new api.UiElementUpdate(); |
| 292 update.setVisible(false); | 281 update.setVisible(false); |
| 293 scene.updateElement(this.domUiElement.uiElementId, update); | 282 scene.updateElement(this.domUiElement.uiElementId, update); |
| 294 this.nativeState.visible = false; | 283 this.nativeState.visible = false; |
| 295 | 284 |
| 296 // Listen to the end of transitions, so that the box can be natively | 285 // Listen to the end of transitions, so that the box can be natively |
| (...skipping 15 matching lines...) Expand all Loading... |
| 312 } | 301 } |
| 313 | 302 |
| 314 setURL(host, path) { | 303 setURL(host, path) { |
| 315 let omnibox = this.domUiElement.domElement; | 304 let omnibox = this.domUiElement.domElement; |
| 316 omnibox.querySelector('#domain').innerHTML = host; | 305 omnibox.querySelector('#domain').innerHTML = host; |
| 317 omnibox.querySelector('#path').innerHTML = path; | 306 omnibox.querySelector('#path').innerHTML = path; |
| 318 this.resetVisibilityTimer(); | 307 this.resetVisibilityTimer(); |
| 319 this.updateState(); | 308 this.updateState(); |
| 320 } | 309 } |
| 321 | 310 |
| 322 setSecureOrigin(secure) { | 311 setSecurityLevel(level) { |
| 323 this.secure = secure; | 312 this.level = level; |
| 324 this.resetVisibilityTimer(); | 313 this.resetVisibilityTimer(); |
| 325 this.updateState(); | 314 this.updateState(); |
| 326 } | 315 } |
| 327 | 316 |
| 328 setVisibilityTimeout(milliseconds) { | 317 setVisibilityTimeout(milliseconds) { |
| 329 this.visibilityTimeout = milliseconds; | 318 this.visibilityTimeout = milliseconds; |
| 330 this.resetVisibilityTimer(); | 319 this.resetVisibilityTimer(); |
| 331 this.updateState(); | 320 this.updateState(); |
| 332 } | 321 } |
| 333 | 322 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 351 if (e.propertyName == 'opacity' && !this.visibleAfterTransition) { | 340 if (e.propertyName == 'opacity' && !this.visibleAfterTransition) { |
| 352 this.setNativeVisibility(false); | 341 this.setNativeVisibility(false); |
| 353 } | 342 } |
| 354 } | 343 } |
| 355 | 344 |
| 356 updateState() { | 345 updateState() { |
| 357 if (!this.enabled) { | 346 if (!this.enabled) { |
| 358 this.setNativeVisibility(false); | 347 this.setNativeVisibility(false); |
| 359 return; | 348 return; |
| 360 } | 349 } |
| 361 | 350 let secure = this.level == 2 || this.level == 3; |
| 362 document.querySelector('#omni-secure-icon').style.display = | 351 document.querySelector('#omni-secure-icon').style.display = |
| 363 (this.secure ? 'block' : 'none'); | 352 (secure ? 'block' : 'none'); |
| 364 document.querySelector('#omni-insecure-icon').style.display = | 353 document.querySelector('#omni-insecure-icon').style.display = |
| 365 (this.secure ? 'none' : 'block'); | 354 (secure ? 'none' : 'block'); |
| 366 | 355 |
| 367 let state = 'idle'; | 356 let state = 'idle'; |
| 368 this.visibleAfterTransition = true; | 357 this.visibleAfterTransition = true; |
| 369 if (this.loading) { | 358 if (this.loading) { |
| 370 state = 'loading'; | 359 state = 'loading'; |
| 371 } else if (this.visibilityTimeout > 0 && !this.visibilityTimer) { | 360 } else if (this.visibilityTimeout > 0 && !this.visibilityTimer) { |
| 372 state = 'hide'; | 361 state = 'hide'; |
| 373 this.visibleAfterTransition = false; | 362 this.visibleAfterTransition = false; |
| 374 } | 363 } |
| 375 document.querySelector('#omni').className = state; | 364 document.querySelector('#omni').className = state; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 386 update.setVisible(visible); | 375 update.setVisible(visible); |
| 387 scene.updateElement(this.domUiElement.uiElementId, update); | 376 scene.updateElement(this.domUiElement.uiElementId, update); |
| 388 scene.flush(); | 377 scene.flush(); |
| 389 } | 378 } |
| 390 }; | 379 }; |
| 391 | 380 |
| 392 class SceneManager { | 381 class SceneManager { |
| 393 constructor() { | 382 constructor() { |
| 394 this.mode = api.Mode.UNKNOWN; | 383 this.mode = api.Mode.UNKNOWN; |
| 395 this.menuMode = false; | 384 this.menuMode = false; |
| 396 this.cinemaMode = false; | 385 this.fullscreen = false; |
| 397 | 386 |
| 398 this.contentQuad = new ContentQuad(); | 387 this.contentQuad = new ContentQuad(); |
| 399 let contentId = this.contentQuad.getElementId(); | 388 let contentId = this.contentQuad.getElementId(); |
| 400 | 389 |
| 401 this.controls = new Controls(contentId); | 390 this.controls = new Controls(contentId); |
| 402 this.secureOriginWarnings = new SecureOriginWarnings(); | 391 this.secureOriginWarnings = new SecureOriginWarnings(); |
| 403 this.omnibox = new Omnibox(contentId); | 392 this.omnibox = new Omnibox(contentId); |
| 404 } | 393 } |
| 405 | 394 |
| 406 setMode(mode, menuMode, cinemaMode) { | 395 setMode(mode, menuMode, fullscreen) { |
| 396 /** @const */ var OMNIBOX_VISIBILITY_TIMEOUT_MS = 5000; |
| 397 |
| 407 this.mode = mode; | 398 this.mode = mode; |
| 408 this.menuMode = menuMode; | 399 this.menuMode = menuMode; |
| 409 this.cinemaMode = cinemaMode; | 400 this.fullscreen = fullscreen; |
| 410 | 401 |
| 411 this.contentQuad.setEnabled(mode == api.Mode.STANDARD && !menuMode); | 402 this.contentQuad.setEnabled(mode == api.Mode.STANDARD && !menuMode); |
| 412 this.contentQuad.setCinemaMode(cinemaMode); | 403 this.contentQuad.setFullscreen(fullscreen); |
| 413 // TODO(crbug/643815): Set aspect ratio on content quad when available. | 404 // TODO(crbug/643815): Set aspect ratio on content quad when available. |
| 414 // TODO(amp): Don't show controls in CINEMA mode once MENU mode lands. | 405 // TODO(amp): Don't show controls in fullscreen once MENU mode lands. |
| 415 this.controls.setEnabled(mode == api.Mode.STANDARD && !menuMode); | 406 this.controls.setEnabled(mode == api.Mode.STANDARD && !menuMode); |
| 416 this.omnibox.setEnabled(mode == api.Mode.STANDARD && !menuMode); | 407 this.omnibox.setEnabled(mode == api.Mode.STANDARD && !menuMode); |
| 408 // TODO(amp): Don't show controls in CINEMA mode once MENU mode lands. |
| 409 this.omnibox.setVisibilityTimeout( |
| 410 mode == api.Mode.STANDARD && !menuMode ? |
| 411 0 : OMNIBOX_VISIBILITY_TIMEOUT_MS); |
| 417 this.secureOriginWarnings.setEnabled(mode == api.Mode.WEB_VR); | 412 this.secureOriginWarnings.setEnabled(mode == api.Mode.WEB_VR); |
| 418 | 413 |
| 419 api.setUiCssSize(uiRootElement.clientWidth, uiRootElement.clientHeight, | 414 api.setUiCssSize(uiRootElement.clientWidth, uiRootElement.clientHeight, |
| 420 UI_DPR); | 415 UI_DPR); |
| 421 } | 416 } |
| 422 | 417 |
| 423 setSecureOrigin(secure) { | 418 setSecurityLevel(level) { |
| 424 this.secureOriginWarnings.setSecureOrigin(secure); | 419 this.omnibox.setSecurityLevel(level); |
| 425 this.omnibox.setSecureOrigin(secure); | 420 } |
| 421 |
| 422 setWebVRSecureOrigin(secure) { |
| 423 this.secureOriginWarnings.setSecure(secure); |
| 426 } | 424 } |
| 427 | 425 |
| 428 setReloadUiEnabled(enabled) { | 426 setReloadUiEnabled(enabled) { |
| 429 this.controls.setReloadUiEnabled(enabled); | 427 this.controls.setReloadUiEnabled(enabled); |
| 430 } | 428 } |
| 431 }; | 429 }; |
| 432 | 430 |
| 433 function initialize() { | 431 function initialize() { |
| 434 sceneManager = new SceneManager(); | 432 sceneManager = new SceneManager(); |
| 435 scene.flush(); | 433 scene.flush(); |
| 436 | 434 |
| 437 api.domLoaded(); | 435 api.domLoaded(); |
| 438 } | 436 } |
| 439 | 437 |
| 440 function command(dict) { | 438 function command(dict) { |
| 441 if ('mode' in dict) { | 439 if ('mode' in dict) { |
| 442 sceneManager.setMode(dict['mode'], dict['menuMode'], dict['cinemaMode']); | 440 sceneManager.setMode(dict['mode'], dict['menuMode'], dict['fullscreen']); |
| 443 } | 441 } |
| 444 if ('secureOrigin' in dict) { | 442 if ('securityLevel' in dict) { |
| 445 sceneManager.setSecureOrigin(dict['secureOrigin']); | 443 sceneManager.setSecurityLevel(dict['securityLevel']); |
| 444 } |
| 445 if ('webVRSecureOrigin' in dict) { |
| 446 sceneManager.setWebVRSecureOrigin(dict['webVRSecureOrigin']); |
| 446 } | 447 } |
| 447 if ('enableReloadUi' in dict) { | 448 if ('enableReloadUi' in dict) { |
| 448 sceneManager.setReloadUiEnabled(dict['enableReloadUi']); | 449 sceneManager.setReloadUiEnabled(dict['enableReloadUi']); |
| 449 } | 450 } |
| 450 if ('url' in dict) { | 451 if ('url' in dict) { |
| 451 let url = dict['url']; | 452 let url = dict['url']; |
| 452 sceneManager.omnibox.setURL(url['host'], url['path']); | 453 sceneManager.omnibox.setURL(url['host'], url['path']); |
| 453 } | 454 } |
| 454 if ('loading' in dict) { | 455 if ('loading' in dict) { |
| 455 sceneManager.omnibox.setLoading(dict['loading']); | 456 sceneManager.omnibox.setLoading(dict['loading']); |
| 456 } | 457 } |
| 457 scene.flush(); | 458 scene.flush(); |
| 458 } | 459 } |
| 459 | 460 |
| 460 return { | 461 return { |
| 461 initialize: initialize, | 462 initialize: initialize, |
| 462 command: command, | 463 command: command, |
| 463 }; | 464 }; |
| 464 })(); | 465 })(); |
| 465 | 466 |
| 466 document.addEventListener('DOMContentLoaded', vrShellUi.initialize); | 467 document.addEventListener('DOMContentLoaded', vrShellUi.initialize); |
| OLD | NEW |