Chromium Code Reviews| Index: chrome/browser/resources/hotword_audio_verification/flow.js |
| diff --git a/chrome/browser/resources/hotword_audio_verification/flow.js b/chrome/browser/resources/hotword_audio_verification/flow.js |
| index 635456a06650e4a47640fa85cbcd4ad929572492..b5b8c6352679d66e268f91862ce237691724d38b 100644 |
| --- a/chrome/browser/resources/hotword_audio_verification/flow.js |
| +++ b/chrome/browser/resources/hotword_audio_verification/flow.js |
| @@ -18,15 +18,23 @@ |
| * @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, 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 |
| @@ -34,6 +42,24 @@ |
| 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_ = ''; |
| } |
| /** |
| @@ -53,6 +79,99 @@ |
| chrome.hotwordPrivate.getLaunchState(this.startFlowForMode_.bind(this)); |
| }; |
| + /** |
| + * Starts the training process. |
| + */ |
| + Flow.prototype.startTraining = function() { |
|
Dan Beam
2014/10/30 02:57:54
should we check that !this.training_?
kcarattini
2014/10/30 05:56:17
Done.
|
| + this.training_ = true; |
| + if (this.launchMode_ == LaunchMode.HOTWORD_ONLY || |
| + this.launchMode_ == LaunchMode.RETRAIN) { |
| + this.trainingPagePrefix_ = 'hotword-only'; |
| + } |
| + if (this.launchMode_ == LaunchMode.HOTWORD_AND_AUDIO_HISTORY) |
| + this.trainingPagePrefix_ = 'speech-training'; |
| + |
| + if (chrome.hotwordPrivate.onHotwordTriggered) |
|
Dan Beam
2014/10/30 02:57:55
curlies
kcarattini
2014/10/30 05:56:18
Done.
|
| + chrome.hotwordPrivate.onHotwordTriggered.addListener( |
| + this.handleHotwordTrigger.bind(this)); |
| + if (chrome.hotwordPrivate.startTraining) |
| + chrome.hotwordPrivate.startTraining(); |
| + }; |
| + |
| + /** |
| + * Stops the training process. |
| + */ |
| + Flow.prototype.stopTraining = function() { |
|
Dan Beam
2014/10/30 02:57:54
should this actually be a check to ensure this.tra
kcarattini
2014/10/30 05:56:18
No, since this is called from all events that clos
|
| + if (this.training_) { |
| + 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)); |
| + } |
| + }; |
| + |
| + /** |
| + * Completes the training process. |
|
Dan Beam
2014/10/30 02:57:54
@private, finalizeSpeakerModel_
kcarattini
2014/10/30 05:56:17
Done.
|
| + */ |
| + Flow.prototype.finalizeSpeakerModel = function() { |
| + if (this.training_) { |
|
Dan Beam
2014/10/30 02:57:54
nit:
if (!this.training_)
return;
kcarattini
2014/10/30 05:56:18
Done.
|
| + 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. |
|
Dan Beam
2014/10/30 02:57:54
handleHotwordTrigger_, @private
kcarattini
2014/10/30 05:56:17
Done.
|
| + */ |
| + 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; |
| + } |
|
Dan Beam
2014/10/30 02:57:54
// Only the last step makes it here.
(or somethin
kcarattini
2014/10/30 05:56:17
Done.
|
| + |
| + // Update the 'Cancel' button. |
| + 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(); |
| + }; |
| + |
| // ---- private methods: |
| /** |
| @@ -60,10 +179,15 @@ |
| * @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.SPEECH_TRAINING) |
|
Dan Beam
2014/10/30 02:57:54
curlies
kcarattini
2014/10/30 05:56:17
Done.
|
| + this.startTraining(); |
| }; |
| /** |