Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / hotword_audio_verification / flow.js
index c8672df..abf7429 100644 (file)
@@ -7,7 +7,6 @@
   // Correspond to steps in the hotword opt-in flow.
   /** @const */ var HOTWORD_AUDIO_HISTORY = 'hotword-audio-history-container';
   /** @const */ var HOTWORD_ONLY_START = 'hotword-only-container';
-  /** @const */ var AUDIO_HISTORY_START = 'audio-history-container';
   /** @const */ var SPEECH_TRAINING = 'speech-training-container';
   /** @const */ var FINISHED = 'finished-container';
 
    * @const
    */
   var FLOWS = [
-    // TODO(kcarattini): Remove the first flow, since we will not be
-    // managing the Audio History Setting in Chrome anymore.
-    [AUDIO_HISTORY_START],
-    [HOTWORD_ONLY_START, SPEECH_TRAINING, FINISHED],
+    [HOTWORD_ONLY_START, FINISHED],
     [HOTWORD_AUDIO_HISTORY, SPEECH_TRAINING, FINISHED],
     [SPEECH_TRAINING, FINISHED]
   ];
 
   /**
+   * The launch mode. This enum needs to be kept in sync with that of
+   * the same name in hotword_service.h.
+   * @enum {number}
+   */
+  var LaunchMode = {
+    HOTWORD_ONLY: 0,
+    HOTWORD_AND_AUDIO_HISTORY: 1,
+    RETRAIN: 2
+  };
+
+  /**
    * Class to control the page flow of the always-on hotword and
    * Audio History opt-in process.
    * @constructor
   function Flow() {
     this.currentStepIndex_ = -1;
     this.currentFlow_ = [];
+
+    /**
+     * Whether this flow is currently in the process of training a voice model.
+     * @private {LaunchMode}
+     */
+    this.launchMode_ = LaunchMode.HOTWORD_AND_AUDIO_HISTORY;
+
+    /**
+     * Whether this flow is currently in the process of training a voice model.
+     * @private {boolean}
+     */
+    this.training_ = false;
+
+    /**
+     * Prefix of the element ids for the page that is currently training.
+     * @private {string}
+     */
+    this.trainingPagePrefix_ = '';
   }
 
   /**
       chrome.hotwordPrivate.getLaunchState(this.startFlowForMode_.bind(this));
   };
 
+  /**
+   * Starts the training process.
+   */
+  Flow.prototype.startTraining = function() {
+    // Don't start a training session if one already exists.
+    if (this.training_)
+      return;
+
+    this.training_ = true;
+    if (this.launchMode_ == LaunchMode.HOTWORD_ONLY) {
+      this.trainingPagePrefix_ = 'hotword-only';
+    } else if (this.launchMode_ == LaunchMode.HOTWORD_AND_AUDIO_HISTORY ||
+               this.launchMode_ == LaunchMode.RETRAIN) {
+      this.trainingPagePrefix_ = 'speech-training';
+    }
+
+    if (chrome.hotwordPrivate.onHotwordTriggered) {
+      chrome.hotwordPrivate.onHotwordTriggered.addListener(
+          this.handleHotwordTrigger_.bind(this));
+    }
+    if (chrome.hotwordPrivate.startTraining)
+      chrome.hotwordPrivate.startTraining();
+  };
+
+  /**
+   * Stops the training process.
+   */
+  Flow.prototype.stopTraining = function() {
+    if (!this.training_)
+      return;
+
+    this.training_ = false;
+    if (chrome.hotwordPrivate.onHotwordTriggered) {
+      chrome.hotwordPrivate.onHotwordTriggered.
+          removeListener(this.handleHotwordTrigger_);
+    }
+    if (chrome.hotwordPrivate.stopTraining)
+      chrome.hotwordPrivate.stopTraining();
+  };
+
+  /**
+   * Handles the speaker model finalized event.
+   */
+  Flow.prototype.onSpeakerModelFinalized = function() {
+    this.stopTraining();
+
+    if (chrome.hotwordPrivate.setAudioLoggingEnabled)
+      chrome.hotwordPrivate.setAudioLoggingEnabled(true, function() {});
+
+    if (chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled) {
+      chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled(true,
+          this.advanceStep.bind(this));
+    }
+  };
+
   // ---- private methods:
 
   /**
+   * Completes the training process.
+   * @private
+   */
+  Flow.prototype.finalizeSpeakerModel_ = function() {
+    if (!this.training_)
+      return;
+
+    if (chrome.hotwordPrivate.finalizeSpeakerModel)
+      chrome.hotwordPrivate.finalizeSpeakerModel();
+
+    // TODO(kcarattini): Implement a notification that speaker model has been
+    // finalized instead of setting a timeout.
+    setTimeout(this.onSpeakerModelFinalized.bind(this), 2000);
+  };
+
+  /**
+   * Handles a hotword trigger event and updates the training UI.
+   * @private
+   */
+  Flow.prototype.handleHotwordTrigger_ = function() {
+    var curStep =
+        $(this.trainingPagePrefix_ + '-training').querySelector('.listening');
+    // TODO(kcarattini): Localize this string.
+    curStep.querySelector('.text').textContent = 'Recorded';
+    curStep.classList.remove('listening');
+    curStep.classList.add('recorded');
+
+    var steps =
+        $(this.trainingPagePrefix_ + '-training').querySelectorAll('.train');
+    var index = Array.prototype.indexOf.call(steps, curStep);
+    if (steps[index + 1]) {
+      steps[index + 1].classList.remove('not-started');
+      steps[index + 1].classList.add('listening');
+      return;
+    }
+
+    // Only the last step makes it here.
+    var buttonElem = $(this.trainingPagePrefix_ + '-cancel-button');
+    // TODO(kcarattini): Localize this string.
+    buttonElem.textContent = 'Please wait ...';
+    buttonElem.classList.add('grayed-out');
+    buttonElem.classList.remove('finish-button');
+
+    this.finalizeSpeakerModel_();
+  };
+
+  /**
    * Gets and starts the appropriate flow for the launch mode.
+   * @param {chrome.hotwordPrivate.LaunchState} state Launch state of the
+   *     Hotword Audio Verification App.
    * @private
    */
   Flow.prototype.startFlowForMode_ = function(state) {
+    this.launchMode_ = state.launchMode;
     assert(state.launchMode >= 0 && state.launchMode < FLOWS.length,
            'Invalid Launch Mode.');
     this.currentFlow_ = FLOWS[state.launchMode];
     this.advanceStep();
+    // If the flow begins with a a training step, then start the training flow.
+    if (state.launchMode == LaunchMode.HOTWORD_ONLY ||
+        state.launchMode == LaunchMode.RETRAIN) {
+      this.startTraining();
+    }
   };
 
   /**
    */
   Flow.prototype.showStep_ = function() {
     var currentStep = this.currentFlow_[this.currentStepIndex_];
+    document.getElementById(currentStep).hidden = false;
+
     var previousStep = null;
     if (this.currentStepIndex_ > 0)
       previousStep = this.currentFlow_[this.currentStepIndex_ - 1];
     if (previousStep)
       document.getElementById(previousStep).hidden = true;
 
-    document.getElementById(currentStep).hidden = false;
+    chrome.app.window.current().show();
   };
 
   window.Flow = Flow;