Source: js/devtools/devtools_auth.js

'use strict';
/* global Service, DevToolsAuthDialog */

(function(exports) {

  /**
   * DevToolsAuth displays a prompt asking the user to scan a QR code as part of
   * pairing the device with a machine running Firefox desktop.  This takes
   * place when debugging via WiFi to exchange keys.
   * @requires DevToolsAuthDialog
   * @requires ScreenManager
   * @class DevToolsAuth
   */
  function DevToolsAuth() {
    window.addEventListener('mozChromeEvent', this);
  }

  DevToolsAuth.prototype = {

    /**
     * General event handler interface.
     * Displays the pair dialog when needed.
     * @memberof DevToolsAuth.prototype
     * @param  {DOMEvent} evt The event.
     */
    handleEvent: function(e) {
      if (e.detail.type !== 'devtools-auth') {
        return;
      }
      if (e.detail.action === 'start') {
        this.start();
      }
      if (e.detail.action === 'capture') {
        this.capture();
      }
      if (e.detail.action === 'stop') {
        this.stop();
      }
    },

    get dialog() {
      if (!this._dialog) {
        this._dialog = new DevToolsAuthDialog({
          onHide: this.onHide.bind(this)
        });
      }
      return this._dialog;
    },

    get canvas() {
      if (!this._canvas) {
        this._canvas = document.createElement('canvas');
      }
      return this._canvas;
    },

    /**
     * Begin capturing images that DevTools will attempt to find a QR code in
     * for authentication.
     * @memberof DevToolsAuth.prototype
     */
    start: function() {
      // We want the user's attention, so we need to turn the screen on if it's
      // off.
      Service.request('turnScreenOn');

      this.dialog.show();

      var getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia;
      getUserMedia = getUserMedia.bind(navigator);

      getUserMedia({
        video: {
          width: { min: 480 },
          height: { min: 480 }
        },
        audio: false
      }, function(stream) {
        var video = this.dialog.video;

        video.addEventListener('loadedmetadata', function onMetadata() {
          video.removeEventListener('loadedmetadata', onMetadata);
          this._resizeCanvas();
          this.capture();
        }.bind(this));

        video.mozSrcObject = stream;
        video.play();
      }.bind(this), function(e) {
        console.error('Unable to access camera: ' + e);
      });
    },

    /**
     * Capture another image and send to DevTools.
     * @memberof DevToolsAuth.prototype
     */
    capture: function() {
      var video = this.dialog.video;
      var canvas = this.canvas;
      var context = canvas.getContext('2d');
      context.drawImage(video, 0, 0, canvas.width, canvas.height);
      var url = canvas.toDataURL('image/jpeg');
      this._checkImage(url);
    },

    /**
     * An image was successfully decoded, so further capture can stop.
     * @memberof DevToolsAuth.prototype
     */
    stop: function() {
      this.dialog.hide('complete');
    },

    /**
     * Dialog is now hidden, perform cleanup.
     * @memberof DevToolsAuth.prototype
     */
    onHide: function(reason) {
      var video = this.dialog.video;
      video.pause();
      if (video.mozSrcObject) {
        video.mozSrcObject.stop();
        video.mozSrcObject = null;
      }
      this._canvas = null;
      if (reason !== 'complete') {
        this.abort();
      }
    },

    /**
     * User chose to abort the auth process.
     * @memberof DevToolsAuth.prototype
     */
    abort: function() {
      var event = document.createEvent('CustomEvent');
      event.initCustomEvent('mozContentEvent', true, true,
                            { type: 'devtools-auth',
                              action: 'abort' });
      window.dispatchEvent(event);
    },

    _resizeCanvas: function() {
      var video = this.dialog.video;
      this.canvas.width = video.videoWidth;
      this.canvas.height = video.videoHeight;
    },

    /**
     * Dispatches an event to check a possible pairing candidate image.
     * @memberof DevToolsAuth.prototype
     * @param  {String} url Object URL of the image to check
     */
    _checkImage: function(url) {
      var event = document.createEvent('CustomEvent');
      event.initCustomEvent('mozContentEvent', true, true,
                            { type: 'devtools-auth',
                              action: 'capture',
                              url: url });
      window.dispatchEvent(event);
    }
  };

  exports.DevToolsAuth = DevToolsAuth;

}(window));