19d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved.
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com'use strict';
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
79d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/**
89d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @param {Element} playerContainer Main container.
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * @param {Element} videoContainer Container for the video element.
109d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @param {Element} controlsContainer Container for video controls.
119d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @constructor
1269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com */
139d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgfunction FullWindowVideoControls(
14181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com    playerContainer, videoContainer, controlsContainer) {
15383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  VideoControls.call(this,
16383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com      controlsContainer,
17181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      this.onPlaybackError_.wrap(this),
18181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      loadTimeData.getString.wrap(loadTimeData),
19181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      this.toggleFullScreen_.wrap(this),
20181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      videoContainer);
21181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com
22181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com  this.playerContainer_ = playerContainer;
23383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  this.decodeErrorOccured = false;
24383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com
25383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  this.casting = false;
26383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com
27383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  this.updateStyle();
28383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  window.addEventListener('resize', this.updateStyle.wrap(this));
29383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com  document.addEventListener('keydown', function(e) {
30383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    switch (e.keyIdentifier) {
31383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com      case 'U+0020': // Space
32181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      case 'MediaPlayPause':
33181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com        this.togglePlayStateWithFeedback();
34181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com        break;
35181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com      case 'U+001B': // Escape
36181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com        util.toggleFullScreen(
37b5b3168a645802f66233234a06dd5a3764f18018bsalomon@google.com            chrome.app.window.current(),
38181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com            false);  // Leave the full screen mode.
399d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        break;
409d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      case 'Right':
41c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      case 'MediaNextTrack':
42c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        player.advance_(1);
43afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        break;
44c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      case 'Left':
45c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      case 'MediaPreviousTrack':
46c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        player.advance_(0);
479d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        break;
48c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      case 'MediaStop':
499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // TODO: Define "Stop" behavior.
509d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        break;
519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  }.wrap(this));
539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
549d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  // TODO(mtomasz): Simplify. crbug.com/254318.
552047f00e4698f83499ab91911999a65c21a951c9epoger@google.com  var clickInProgress = false;
5661f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com  videoContainer.addEventListener('click', function(e) {
5761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    if (clickInProgress)
5861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      return;
5961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com
6061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    clickInProgress = true;
6161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    var togglePlayState = function() {
6261f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      clickInProgress = false;
6361f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com
649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      if (e.ctrlKey) {
659d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        this.toggleLoopedModeWithFeedback(true);
669d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        if (!this.isPlaying())
679d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org          this.togglePlayStateWithFeedback();
68c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      } else {
69c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        this.togglePlayStateWithFeedback();
70c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      }
71c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }.wrap(this);
72c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (!this.media_)
749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      player.reloadCurrentVideo(togglePlayState);
759d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    else
769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      setTimeout(togglePlayState);
779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  }.wrap(this));
789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.inactivityWatcher_ = new MouseInactivityWatcher(playerContainer);
809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.__defineGetter__('inactivityWatcher', function() {
817744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com    return this.inactivityWatcher_;
827744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com  }.wrap(this));
839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
847744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com  this.inactivityWatcher_.check();
859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgFullWindowVideoControls.prototype = { __proto__: VideoControls.prototype };
889d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/**
909d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * Displays error message.
919d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org *
929d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @param {string} message Message id.
939d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org */
94c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.comFullWindowVideoControls.prototype.showErrorMessage = function(message) {
95afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com  var errorBanner = document.querySelector('#error');
96c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  errorBanner.textContent = loadTimeData.getString(message);
97c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  errorBanner.setAttribute('visible', 'true');
98c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
99c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  // The window is hidden if the video has not loaded yet.
100c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  chrome.app.window.current().show();
101c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com};
1022047f00e4698f83499ab91911999a65c21a951c9epoger@google.com
103c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com/**
1049d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * Handles playback (decoder) errors.
1059d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @param {MediaError} error Error object.
1062047f00e4698f83499ab91911999a65c21a951c9epoger@google.com * @private
10761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com */
10861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.comFullWindowVideoControls.prototype.onPlaybackError_ = function(error) {
10961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com  if (error.target && error.target.error &&
11061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      error.target.error.code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED) {
11161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    if (this.casting)
11261f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      this.showErrorMessage('VIDEO_PLAYER_VIDEO_FILE_UNSUPPORTED_FOR_CAST');
11361f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    else
11461f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      this.showErrorMessage('GALLERY_VIDEO_ERROR');
1159d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    this.decodeErrorOccured = false;
1169d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  } else {
1179d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    this.showErrorMessage('GALLERY_VIDEO_DECODING_ERROR');
1189d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    this.decodeErrorOccured = true;
119c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  }
120c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
121c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  // Disable inactivity watcher, and disable the ui, by hiding tools manually.
122c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  this.inactivityWatcher.disabled = true;
123c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  document.querySelector('#video-player').setAttribute('disabled', 'true');
124c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
1259d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  // Detach the video element, since it may be unreliable and reset stored
1269d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  // current playback time.
1279d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.cleanup();
1289d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.clearState();
1299d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1309d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  // Avoid reusing a video element.
1319d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  player.unloadVideo();
1329d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org};
1337744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com
1347744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com/**
1357744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com * Toggles the full screen mode.
1369d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @private
1379d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org */
1387744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.comFullWindowVideoControls.prototype.toggleFullScreen_ = function() {
1397744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com  var appWindow = chrome.app.window.current();
1409d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow));
1417744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com};
1429d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1439d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/**
1449d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * Media completion handler.
1459d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org */
1469d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgFullWindowVideoControls.prototype.onMediaComplete = function() {
1479d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  VideoControls.prototype.onMediaComplete.apply(this, arguments);
14807f3ee10d34f09342abb93d758b5e151ff78f7a5reed@google.com  if (!this.getMedia().loop)
14907f3ee10d34f09342abb93d758b5e151ff78f7a5reed@google.com    player.advance_(1);
150c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com};
151afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com
152c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com/**
153c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com * @constructor
154c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com */
1559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgfunction VideoPlayer() {
1569d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.controls_ = null;
1579d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.videoElement_ = null;
1589d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.videos_ = null;
1599d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.currentPos_ = 0;
160129b8e3237b80b9d258a8f48e8f54c0073cafbdcsenorblanco@chromium.org
1619d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.currentSession_ = null;
1629d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.currentCast_ = null;
1639d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
16407f3ee10d34f09342abb93d758b5e151ff78f7a5reed@google.com  this.loadQueue_ = new AsyncUtil.Queue();
1659d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1669d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.onCastSessionUpdateBound_ = this.onCastSessionUpdate_.wrap(this);
1679d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  Object.seal(this);
1699d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgVideoPlayer.prototype = {
1729d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  get controls() {
1739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return this.controls_;
1749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  }
1759d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org};
1769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/**
1789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * Initializes the video player window. This method must be called after DOM
1799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * initialization.
1809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org * @param {Array.<Object.<string, Object>>} videos List of videos.
1819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org */
1829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgVideoPlayer.prototype.prepare = function(videos) {
1839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  this.videos_ = videos;
1849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  var preventDefault = function(event) { event.preventDefault(); }.wrap(null);
1869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  document.ondragstart = preventDefault;
1889d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
18969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com  var maximizeButton = document.querySelector('.maximize-button');
1901971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  maximizeButton.addEventListener(
19169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      'click',
19269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      function(event) {
1935e9bf82814aa5d1503c39dd14c420d6db30055dcbsalomon@google.com        var appWindow = chrome.app.window.current();
1945e9bf82814aa5d1503c39dd14c420d6db30055dcbsalomon@google.com        if (appWindow.isMaximized())
1955e9bf82814aa5d1503c39dd14c420d6db30055dcbsalomon@google.com          appWindow.restore();
1961971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        else
197dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com          appWindow.maximize();
198dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        event.stopPropagation();
199dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      }.wrap(null));
200dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  maximizeButton.addEventListener('mousedown', preventDefault);
201dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
20269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com  var minimizeButton = document.querySelector('.minimize-button');
20369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com  minimizeButton.addEventListener(
20469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      'click',
2051971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com      function(event) {
2061971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        chrome.app.window.current().minimize();
2071971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        event.stopPropagation();
2081971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com      }.wrap(null));
209dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  minimizeButton.addEventListener('mousedown', preventDefault);
210dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
211dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  var closeButton = document.querySelector('.close-button');
212dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  closeButton.addEventListener(
213dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      'click',
214dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      function(event) {
215dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        close();
216dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        event.stopPropagation();
217dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      }.wrap(null));
218dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  closeButton.addEventListener('mousedown', preventDefault);
219dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
220dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  var menu = document.querySelector('#cast-menu');
221dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  cr.ui.decorate(menu, cr.ui.Menu);
222dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
223dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  this.controls_ = new FullWindowVideoControls(
224dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      document.querySelector('#video-player'),
225dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com      document.querySelector('#video-container'),
22620e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com      document.querySelector('#controls'));
22720e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com
22820e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com  var reloadVideo = function(e) {
22920e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com    if (this.controls_.decodeErrorOccured &&
23020e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com        // Ignore shortcut keys
231dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
2321971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com      this.reloadCurrentVideo(function() {
2331971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        this.videoElement_.play();
2341971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com      }.wrap(this));
2351971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com      e.preventDefault();
2361971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    }
2371971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  }.wrap(this);
2381971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2391971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  var arrowRight = document.querySelector('.arrow-box .arrow.right');
240dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  arrowRight.addEventListener('click', this.advance_.wrap(this, 1));
241dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  var arrowLeft = document.querySelector('.arrow-box .arrow.left');
242dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  arrowLeft.addEventListener('click', this.advance_.wrap(this, 0));
2431971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2441971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  var videoPlayerElement = document.querySelector('#video-player');
245dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  if (videos.length > 1)
246dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    videoPlayerElement.setAttribute('multiple', true);
2471971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  else
2481971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    videoPlayerElement.removeAttribute('multiple');
2491971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2501971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  document.addEventListener('keydown', reloadVideo);
2511971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  document.addEventListener('click', reloadVideo);
2521971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com};
2531971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2541971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com/**
2551971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com * Unloads the player.
2561971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com */
2571971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.comfunction unload() {
2581971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  // Releases keep awake just in case (should be released on unloading video).
2591971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  chrome.power.releaseKeepAwake();
2601971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2611971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  if (!player.controls || !player.controls.getMedia())
2621971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    return;
2631971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2641971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  player.controls.savePosition(true /* exiting */);
2651971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  player.controls.cleanup();
2661971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com}
2671971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2681971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com/**
2691971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com * Loads the video file.
2701971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com * @param {Object} video Data of the video file.
2711971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com * @param {function()=} opt_callback Completion callback.
272dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com * @private
27369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com */
27469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comVideoPlayer.prototype.loadVideo_ = function(video, opt_callback) {
27569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com  this.unloadVideo(true);
27669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
27769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com  this.loadQueue_.run(function(callback) {
27869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    document.title = video.title;
27969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
28069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    document.querySelector('#title').innerText = video.title;
28169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
28269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    var videoPlayerElement = document.querySelector('#video-player');
28369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    if (this.currentPos_ === (this.videos_.length - 1))
28469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.setAttribute('last-video', true);
28569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    else
28669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.removeAttribute('last-video');
28769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
28869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    if (this.currentPos_ === 0)
28969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.setAttribute('first-video', true);
29069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    else
29169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.removeAttribute('first-video');
29269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
29369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    // Re-enables ui and hides error message if already displayed.
29469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    document.querySelector('#video-player').removeAttribute('disabled');
29569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    document.querySelector('#error').removeAttribute('visible');
29669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    this.controls.detachMedia();
29769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    this.controls.inactivityWatcher.disabled = true;
29869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    this.controls.decodeErrorOccured = false;
29969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    this.controls.casting = !!this.currentCast_;
30069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
30169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    videoPlayerElement.setAttribute('loading', true);
30269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
30369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    var media = new MediaManager(video.entry);
30469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
30569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    Promise.all([media.getThumbnail(), media.getToken()])
30669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        .then(function(results) {
30769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          var url = results[0];
30869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          var token = results[1];
30969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          if (url && token) {
31069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            document.querySelector('#thumbnail').style.backgroundImage =
31169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                'url(' + url + '&access_token=' + token + ')';
31269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          } else {
31369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            document.querySelector('#thumbnail').style.backgroundImage = '';
31469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          }
31569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        })
31669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        .catch(function() {
31769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          // Shows no image on error.
31869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          document.querySelector('#thumbnail').style.backgroundImage = '';
31969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        });
32069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
32169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    var videoElementInitializePromise;
32269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    if (this.currentCast_) {
32369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.setAttribute('casting', true);
32469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
32569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      document.querySelector('#cast-name').textContent =
32669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          this.currentCast_.friendlyName;
32769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
32869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoPlayerElement.setAttribute('castable', true);
32969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
33069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com      videoElementInitializePromise = media.isAvailableForCast()
33169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com          .then(function(result) {
33269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            if (!result)
333              return Promise.reject('No casts are available.');
334
335            return new Promise(function(fulfill, reject) {
336              chrome.cast.requestSession(
337                  fulfill, reject, undefined, this.currentCast_.label);
338            }.bind(this)).then(function(session) {
339              session.addUpdateListener(this.onCastSessionUpdateBound_);
340
341              this.currentSession_ = session;
342              this.videoElement_ = new CastVideoElement(media, session);
343              this.controls.attachMedia(this.videoElement_);
344            }.bind(this));
345          }.bind(this));
346    } else {
347      videoPlayerElement.removeAttribute('casting');
348
349      this.videoElement_ = document.createElement('video');
350      document.querySelector('#video-container').appendChild(
351          this.videoElement_);
352
353      this.controls.attachMedia(this.videoElement_);
354      this.videoElement_.src = video.url;
355
356      media.isAvailableForCast().then(function(result) {
357        if (result)
358          videoPlayerElement.setAttribute('castable', true);
359        else
360          videoPlayerElement.removeAttribute('castable');
361      }).catch(function() {
362        videoPlayerElement.setAttribute('castable', true);
363      });
364
365      videoElementInitializePromise = Promise.resolve();
366    }
367
368    videoElementInitializePromise
369        .then(function() {
370          var handler = function(currentPos) {
371            if (currentPos === this.currentPos_) {
372              if (opt_callback)
373                opt_callback();
374              videoPlayerElement.removeAttribute('loading');
375              this.controls.inactivityWatcher.disabled = false;
376            }
377
378            this.videoElement_.removeEventListener('loadedmetadata', handler);
379          }.wrap(this, this.currentPos_);
380
381          this.videoElement_.addEventListener('loadedmetadata', handler);
382
383          this.videoElement_.addEventListener('play', function() {
384            chrome.power.requestKeepAwake('display');
385          }.wrap());
386          this.videoElement_.addEventListener('pause', function() {
387            chrome.power.releaseKeepAwake();
388          }.wrap());
389
390          this.videoElement_.load();
391          callback();
392        }.bind(this))
393        // In case of error.
394        .catch(function(error) {
395          videoPlayerElement.removeAttribute('loading');
396          console.error('Failed to initialize the video element.',
397                        error.stack || error);
398          this.controls_.showErrorMessage('GALLERY_VIDEO_ERROR');
399          callback();
400        }.bind(this));
401  }.wrap(this));
402};
403
404/**
405 * Plays the first video.
406 */
407VideoPlayer.prototype.playFirstVideo = function() {
408  this.currentPos_ = 0;
409  this.reloadCurrentVideo(this.onFirstVideoReady_.wrap(this));
410};
411
412/**
413 * Unloads the current video.
414 * @param {boolean=} opt_keepSession If true, keep using the current session.
415 *     Otherwise, discards the session.
416 */
417VideoPlayer.prototype.unloadVideo = function(opt_keepSession) {
418  this.loadQueue_.run(function(callback) {
419    chrome.power.releaseKeepAwake();
420
421    // Detaches the media from the control.
422    this.controls.detachMedia();
423
424    if (this.videoElement_) {
425      // If the element has dispose method, call it (CastVideoElement has it).
426      if (this.videoElement_.dispose)
427        this.videoElement_.dispose();
428      // Detach the previous video element, if exists.
429      if (this.videoElement_.parentNode)
430        this.videoElement_.parentNode.removeChild(this.videoElement_);
431    }
432    this.videoElement_ = null;
433
434    if (!opt_keepSession && this.currentSession_) {
435      this.currentSession_.stop(callback, callback);
436      this.currentSession_.removeUpdateListener(this.onCastSessionUpdateBound_);
437      this.currentSession_ = null;
438    } else {
439      callback();
440    }
441  }.wrap(this));
442};
443
444/**
445 * Called when the first video is ready after starting to load.
446 * @private
447 */
448VideoPlayer.prototype.onFirstVideoReady_ = function() {
449  var videoWidth = this.videoElement_.videoWidth;
450  var videoHeight = this.videoElement_.videoHeight;
451
452  var aspect = videoWidth / videoHeight;
453  var newWidth = videoWidth;
454  var newHeight = videoHeight;
455
456  var shrinkX = newWidth / window.screen.availWidth;
457  var shrinkY = newHeight / window.screen.availHeight;
458  if (shrinkX > 1 || shrinkY > 1) {
459    if (shrinkY > shrinkX) {
460      newHeight = newHeight / shrinkY;
461      newWidth = newHeight * aspect;
462    } else {
463      newWidth = newWidth / shrinkX;
464      newHeight = newWidth / aspect;
465    }
466  }
467
468  var oldLeft = window.screenX;
469  var oldTop = window.screenY;
470  var oldWidth = window.outerWidth;
471  var oldHeight = window.outerHeight;
472
473  if (!oldWidth && !oldHeight) {
474    oldLeft = window.screen.availWidth / 2;
475    oldTop = window.screen.availHeight / 2;
476  }
477
478  var appWindow = chrome.app.window.current();
479  appWindow.resizeTo(newWidth, newHeight);
480  appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2,
481                   oldTop - (newHeight - oldHeight) / 2);
482  appWindow.show();
483
484  this.videoElement_.play();
485};
486
487/**
488 * Advances to the next (or previous) track.
489 *
490 * @param {boolean} direction True to the next, false to the previous.
491 * @private
492 */
493VideoPlayer.prototype.advance_ = function(direction) {
494  var newPos = this.currentPos_ + (direction ? 1 : -1);
495  if (0 <= newPos && newPos < this.videos_.length) {
496    this.currentPos_ = newPos;
497    this.reloadCurrentVideo(function() {
498      this.videoElement_.play();
499    }.wrap(this));
500  }
501};
502
503/**
504 * Reloads the current video.
505 *
506 * @param {function()=} opt_callback Completion callback.
507 */
508VideoPlayer.prototype.reloadCurrentVideo = function(opt_callback) {
509  var currentVideo = this.videos_[this.currentPos_];
510  this.loadVideo_(currentVideo, opt_callback);
511};
512
513/**
514 * Invokes when a menuitem in the cast menu is selected.
515 * @param {Object} cast Selected element in the list of casts.
516 * @private
517 */
518VideoPlayer.prototype.onCastSelected_ = function(cast) {
519  // If the selected item is same as the current item, do nothing.
520  if ((this.currentCast_ && this.currentCast_.label) === (cast && cast.label))
521    return;
522
523  this.unloadVideo(false);
524
525  // Waits for unloading video.
526  this.loadQueue_.run(function(callback) {
527    this.currentCast_ = cast || null;
528    this.updateCheckOnCastMenu_();
529    this.reloadCurrentVideo();
530    callback();
531  }.wrap(this));
532};
533
534/**
535 * Set the list of casts.
536 * @param {Array.<Object>} casts List of casts.
537 */
538VideoPlayer.prototype.setCastList = function(casts) {
539  var videoPlayerElement = document.querySelector('#video-player');
540  var menu = document.querySelector('#cast-menu');
541  menu.innerHTML = '';
542
543  // TODO(yoshiki): Handle the case that the current cast disappears.
544
545  if (casts.length === 0) {
546    videoPlayerElement.removeAttribute('cast-available');
547    if (this.currentCast_)
548      this.onCurrentCastDisappear_();
549    return;
550  }
551
552  if (this.currentCast_) {
553    var currentCastAvailable = casts.some(function(cast) {
554      return this.currentCast_.label === cast.label;
555    }.wrap(this));
556
557    if (!currentCastAvailable)
558      this.onCurrentCastDisappear_();
559  }
560
561  var item = new cr.ui.MenuItem();
562  item.label = loadTimeData.getString('VIDEO_PLAYER_PLAY_THIS_COMPUTER');
563  item.setAttribute('aria-label', item.label);
564  item.castLabel = '';
565  item.addEventListener('activate', this.onCastSelected_.wrap(this, null));
566  menu.appendChild(item);
567
568  for (var i = 0; i < casts.length; i++) {
569    var item = new cr.ui.MenuItem();
570    item.label = casts[i].friendlyName;
571    item.setAttribute('aria-label', item.label);
572    item.castLabel = casts[i].label;
573    item.addEventListener('activate',
574                          this.onCastSelected_.wrap(this, casts[i]));
575    menu.appendChild(item);
576  }
577  this.updateCheckOnCastMenu_();
578  videoPlayerElement.setAttribute('cast-available', true);
579};
580
581/**
582 * Updates the check status of the cast menu items.
583 * @private
584 */
585VideoPlayer.prototype.updateCheckOnCastMenu_ = function() {
586  var menu = document.querySelector('#cast-menu');
587  var menuItems = menu.menuItems;
588  for (var i = 0; i < menuItems.length; i++) {
589    var item = menuItems[i];
590    if (this.currentCast_ === null) {
591      // Playing on this computer.
592      if (item.castLabel === '')
593        item.checked = true;
594      else
595        item.checked = false;
596    } else {
597      // Playing on cast device.
598      if (item.castLabel === this.currentCast_.label)
599        item.checked = true;
600      else
601        item.checked = false;
602    }
603  }
604};
605
606/**
607 * Called when the current cast is disappear from the cast list.
608 * @private
609 */
610VideoPlayer.prototype.onCurrentCastDisappear_ = function() {
611  this.currentCast_ = null;
612  if (this.currentSession_) {
613    this.currentSession_.removeUpdateListener(this.onCastSessionUpdateBound_);
614    this.currentSession_ = null;
615  }
616  this.controls.showErrorMessage('GALLERY_VIDEO_DECODING_ERROR');
617  this.unloadVideo();
618};
619
620/**
621 * This method should be called when the session is updated.
622 * @param {boolean} alive Whether the session is alive or not.
623 * @private
624 */
625VideoPlayer.prototype.onCastSessionUpdate_ = function(alive) {
626  if (!alive)
627    this.unloadVideo();
628};
629
630/**
631 * Initialize the list of videos.
632 * @param {function(Array.<Object>)} callback Called with the video list when
633 *     it is ready.
634 */
635function initVideos(callback) {
636  if (window.videos) {
637    var videos = window.videos;
638    window.videos = null;
639    callback(videos);
640    return;
641  }
642
643  chrome.runtime.onMessage.addListener(
644      function(request, sender, sendResponse) {
645        var videos = window.videos;
646        window.videos = null;
647        callback(videos);
648      }.wrap(null));
649}
650
651var player = new VideoPlayer();
652
653/**
654 * Initializes the strings.
655 * @param {function()} callback Called when the sting data is ready.
656 */
657function initStrings(callback) {
658  chrome.fileManagerPrivate.getStrings(function(strings) {
659    loadTimeData.data = strings;
660    i18nTemplate.process(document, loadTimeData);
661    callback();
662  }.wrap(null));
663}
664
665var initPromise = Promise.all(
666    [new Promise(initVideos.wrap(null)),
667     new Promise(initStrings.wrap(null)),
668     new Promise(util.addPageLoadHandler.wrap(null))]);
669
670initPromise.then(function(results) {
671  var videos = results[0];
672  player.prepare(videos);
673  return new Promise(player.playFirstVideo.wrap(player));
674}.wrap(null));
675