Source: js/home_gesture.js

'use strict';
/* global ScreenLayout */
/* global SettingsListener */

(function(exports) {

  /**
   * HomeGesture is used as an alternative to the software home button for
   * devices without physical home buttons.
   * HomeGesture will trigger a 'home' event for a single swipe from the bottom
   * and a 'holdhome' event with a two-finger swipe from the bottom.
   * @class HomeGesture
   * @requires ScreenLayout
   * @requires SettingsListener
   */
  function HomeGesture() {

    this.isTablet = !ScreenLayout.getCurrentLayout('tiny');
    this.hasHardwareHomeButton =
      ScreenLayout.getCurrentLayout('hardwareHomeButton');
    this.homeBar = document.getElementById('bottom-panel');
  }

  HomeGesture.prototype = {

    /**
     * Whether or not the HomeGesture is enabled.
     * @memberof HomeGesture.prototype
     * @type {Boolean}
     */
    enabled: false,

    /**
     * True when the user starts the home gesture.
     * @memberof HomeGesture.prototype
     * @type {Boolean}
     */
    _moving: false,

    /**
     * True when the user is swiping with two or more fingers.
     * @memberof HomeGesture.prototype
     * @type {Boolean}
     */
    _multiTouch: false,

    /**
     * The position of the touchstart event.
     * @memberof HomeGesture.prototype
     * @type {Integer}
     */
    _startY1: 0,

    /**
     * Minimum moving distance to home in pixel of screen height
     * @memberof HomeGesture.prototype
     * @type {Integer}
     */
    MINUMUM_DISTANCE: 50,

    /**
     * Starts the HomeGesture instance.
     * @memberof HomeGesture.prototype
     * @param  {Boolean} enable Whether or not the HomeGesture is enabled.
     */
    start: function() {
      window.addEventListener('software-button-enabled', this);
      window.addEventListener('software-button-disabled', this);
      this.homeBar.addEventListener('touchstart', this, true);
      this.homeBar.addEventListener('touchend', this, true);
      // This 'click' listener can prevent other element which
      // have click listener steal 'touchstart'.
      this.homeBar.addEventListener('click', this, true);

      if (!this.hasHardwareHomeButton && this.isTablet) {
        // enable gesture for tablet without hardware home button
        // as default
        this.toggle(true);
      } else {
        SettingsListener.observe('homegesture.enabled', false,
          function onObserve(value) {
            this.toggle(value);
          }.bind(this));
      }
    },

    /**
     * Toggles the state of the HomeGesture.
     * @memberof HomeGesture.prototype
     * @param  {Boolean} enable Whether or not the HomeGesture is enabled.
     */
    toggle: function(enable) {
      if (enable === this.enabled) {
        return;
      }

      if (enable) {
        this.publish('homegesture-enabled');
        window.addEventListener('lockscreen-appclose', this);
        window.addEventListener('lockscreen-appopened', this);
        window.addEventListener('utilitytrayshow', this);
        window.addEventListener('utilitytrayhide', this);
        this.homeBar.classList.add('visible');
      } else {
        this.publish('homegesture-disabled');
        window.removeEventListener('lockscreen-appclose', this);
        window.removeEventListener('lockscreen-appopened', this);
        window.removeEventListener('utilitytrayshow', this);
        window.removeEventListener('utilitytrayhide', this);
        this.homeBar.classList.remove('visible');
      }
      this.enabled = enable;
    },

    /**
     * General event handler interface.
     * @memberof HomeGesture.prototype
     * @param  {DOMEvent} evt The event.
     */
    handleEvent: function(evt) {
      switch (evt.type) {
        case 'touchstart':
          evt.preventDefault();
          this._moving = true;
          this._startY1 = evt.changedTouches[0].pageY;
          if (evt.touches.length > 1) {
            this._multiTouch = true;
          }
          break;
        case 'touchend':
          var progress = Math.abs(this._startY1 - evt.changedTouches[0].pageY);
          if (this._moving &&
              (progress >= this.MINUMUM_DISTANCE)) {
            if (this._multiTouch) {
              window.dispatchEvent(new CustomEvent('holdhome'));
            } else {
              window.dispatchEvent(new CustomEvent('home'));
            }
          }
          this._multiTouch = false;
          this._moving = false;
          break;
        // hide gesture function when utilitytray/lockscreen display
        case 'lockscreen-appopened':
        case 'utilitytrayshow':
          this.homeBar.classList.remove('visible');
          break;
        case 'lockscreen-appclose':
        case 'utilitytrayhide':
          this.homeBar.classList.add('visible');
          break;
        case 'software-button-disabled':
          // at least one of software home button or gesture is enabled
          // when no hardware home button
          if (!this.hasHardwareHomeButton && !this.enabled) {
            SettingsListener.getSettingsLock().set({
              'homegesture.enabled': true});
          }
          break;
        case 'software-button-enabled':
          if (this.enabled) {
            SettingsListener.getSettingsLock().set({
              'homegesture.enabled': false});
          }
          break;
      }
    },

    /**
     * Shortcut to publish a custom event.
     * @memberof HomeGesture.prototype
     * @param  {String} type The event type.
     */
    publish: function(type) {
      window.dispatchEvent(new CustomEvent(type));
    }
  };

  exports.HomeGesture = HomeGesture;

}(window));