Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 (function() { | 5 (function() { |
| 6 | 6 |
| 7 // Correspond to steps in the hotword opt-in flow. | 7 // Correspond to steps in the hotword opt-in flow. |
| 8 /** @const */ var HOTWORD_AUDIO_HISTORY = 'hotword-audio-history-container'; | 8 /** @const */ var HOTWORD_AUDIO_HISTORY = 'hotword-audio-history-container'; |
| 9 /** @const */ var HOTWORD_ONLY_START = 'hotword-only-container'; | 9 /** @const */ var HOTWORD_ONLY_START = 'hotword-only-container'; |
| 10 /** @const */ var AUDIO_HISTORY_START = 'audio-history-container'; | 10 /** @const */ var AUDIO_HISTORY_START = 'audio-history-container'; |
| 11 /** @const */ var SPEECH_TRAINING = 'speech-training-container'; | 11 /** @const */ var SPEECH_TRAINING = 'speech-training-container'; |
| 12 /** @const */ var FINISHED = 'finished-container'; | 12 /** @const */ var FINISHED = 'finished-container'; |
| 13 | 13 |
| 14 /** | 14 /** |
| 15 * These flows correspond to the three LaunchModes as defined in | 15 * These flows correspond to the three LaunchModes as defined in |
| 16 * chrome/browser/search/hotword_service.h and should be kept in sync | 16 * chrome/browser/search/hotword_service.h and should be kept in sync |
| 17 * with them. | 17 * with them. |
| 18 * @const | 18 * @const |
| 19 */ | 19 */ |
| 20 var FLOWS = [ | 20 var FLOWS = [ |
| 21 // TODO(kcarattini): Remove the first flow, since we will not be | |
| 22 // managing the Audio History Setting in Chrome anymore. | |
| 23 [AUDIO_HISTORY_START], | |
| 24 [HOTWORD_ONLY_START, FINISHED], | 21 [HOTWORD_ONLY_START, FINISHED], |
| 25 [HOTWORD_AUDIO_HISTORY, SPEECH_TRAINING, FINISHED], | 22 [HOTWORD_AUDIO_HISTORY, SPEECH_TRAINING, FINISHED], |
| 26 [SPEECH_TRAINING, FINISHED] | 23 [SPEECH_TRAINING, FINISHED] |
| 27 ]; | 24 ]; |
| 28 | 25 |
| 29 /** | 26 /** |
| 27 * The launch mode. This enum needs to be kept in sync with that of | |
| 28 * the same name in hotword_service.h. | |
| 29 * @enum {number} | |
| 30 */ | |
| 31 var LaunchMode = { | |
| 32 HOTWORD_ONLY: 0, | |
| 33 HOTWORD_AND_AUDIO_HISTORY: 1, | |
| 34 RETRAIN: 2 | |
| 35 }; | |
| 36 | |
| 37 /** | |
| 30 * Class to control the page flow of the always-on hotword and | 38 * Class to control the page flow of the always-on hotword and |
| 31 * Audio History opt-in process. | 39 * Audio History opt-in process. |
| 32 * @constructor | 40 * @constructor |
| 33 */ | 41 */ |
| 34 function Flow() { | 42 function Flow() { |
| 35 this.currentStepIndex_ = -1; | 43 this.currentStepIndex_ = -1; |
| 36 this.currentFlow_ = []; | 44 this.currentFlow_ = []; |
| 45 | |
| 46 /** | |
| 47 * Whether this flow is currently in the process of training a voice model. | |
| 48 * @private {LaunchMode} | |
| 49 */ | |
| 50 this.launchMode_ = LaunchMode.HOTWORD_AND_AUDIO_HISTORY; | |
| 51 | |
| 52 /** | |
| 53 * Whether this flow is currently in the process of training a voice model. | |
| 54 * @private {boolean} | |
| 55 */ | |
| 56 this.training_ = false; | |
| 57 | |
| 58 /** | |
| 59 * Prefix of the element ids for the page that is currently training. | |
| 60 * @private {string} | |
| 61 */ | |
| 62 this.trainingPagePrefix_ = ''; | |
| 37 } | 63 } |
| 38 | 64 |
| 39 /** | 65 /** |
| 40 * Advances the current step. | 66 * Advances the current step. |
| 41 */ | 67 */ |
| 42 Flow.prototype.advanceStep = function() { | 68 Flow.prototype.advanceStep = function() { |
|
Dan Beam
2014/10/30 02:57:55
what happens if this is called while training? do
kcarattini
2014/10/30 05:56:18
It shouldn't matter if this is called while traini
| |
| 43 this.currentStepIndex_++; | 69 this.currentStepIndex_++; |
| 44 if (this.currentStepIndex_ < this.currentFlow_.length) | 70 if (this.currentStepIndex_ < this.currentFlow_.length) |
| 45 this.showStep_.apply(this); | 71 this.showStep_.apply(this); |
| 46 }; | 72 }; |
| 47 | 73 |
| 48 /** | 74 /** |
| 49 * Gets the appropriate flow and displays its first page. | 75 * Gets the appropriate flow and displays its first page. |
| 50 */ | 76 */ |
| 51 Flow.prototype.startFlow = function() { | 77 Flow.prototype.startFlow = function() { |
| 52 if (chrome.hotwordPrivate && chrome.hotwordPrivate.getLaunchState) | 78 if (chrome.hotwordPrivate && chrome.hotwordPrivate.getLaunchState) |
| 53 chrome.hotwordPrivate.getLaunchState(this.startFlowForMode_.bind(this)); | 79 chrome.hotwordPrivate.getLaunchState(this.startFlowForMode_.bind(this)); |
| 54 }; | 80 }; |
| 55 | 81 |
| 82 /** | |
| 83 * Starts the training process. | |
| 84 */ | |
| 85 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.
| |
| 86 this.training_ = true; | |
| 87 if (this.launchMode_ == LaunchMode.HOTWORD_ONLY || | |
| 88 this.launchMode_ == LaunchMode.RETRAIN) { | |
| 89 this.trainingPagePrefix_ = 'hotword-only'; | |
| 90 } | |
| 91 if (this.launchMode_ == LaunchMode.HOTWORD_AND_AUDIO_HISTORY) | |
| 92 this.trainingPagePrefix_ = 'speech-training'; | |
| 93 | |
| 94 if (chrome.hotwordPrivate.onHotwordTriggered) | |
|
Dan Beam
2014/10/30 02:57:55
curlies
kcarattini
2014/10/30 05:56:18
Done.
| |
| 95 chrome.hotwordPrivate.onHotwordTriggered.addListener( | |
| 96 this.handleHotwordTrigger.bind(this)); | |
| 97 if (chrome.hotwordPrivate.startTraining) | |
| 98 chrome.hotwordPrivate.startTraining(); | |
| 99 }; | |
| 100 | |
| 101 /** | |
| 102 * Stops the training process. | |
| 103 */ | |
| 104 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
| |
| 105 if (this.training_) { | |
| 106 this.training_ = false; | |
| 107 if (chrome.hotwordPrivate.onHotwordTriggered) { | |
| 108 chrome.hotwordPrivate.onHotwordTriggered. | |
| 109 removeListener(this.handleHotwordTrigger); | |
| 110 } | |
| 111 if (chrome.hotwordPrivate.stopTraining) | |
| 112 chrome.hotwordPrivate.stopTraining(); | |
| 113 } | |
| 114 }; | |
| 115 | |
| 116 /** | |
| 117 * Handles the speaker model finalized event. | |
| 118 */ | |
| 119 Flow.prototype.onSpeakerModelFinalized = function() { | |
| 120 this.stopTraining(); | |
| 121 | |
| 122 if (chrome.hotwordPrivate.setAudioLoggingEnabled) | |
| 123 chrome.hotwordPrivate.setAudioLoggingEnabled(true, function() {}); | |
| 124 | |
| 125 if (chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled) { | |
| 126 chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled(true, | |
| 127 this.advanceStep.bind(this)); | |
| 128 } | |
| 129 }; | |
| 130 | |
| 131 /** | |
| 132 * Completes the training process. | |
|
Dan Beam
2014/10/30 02:57:54
@private, finalizeSpeakerModel_
kcarattini
2014/10/30 05:56:17
Done.
| |
| 133 */ | |
| 134 Flow.prototype.finalizeSpeakerModel = function() { | |
| 135 if (this.training_) { | |
|
Dan Beam
2014/10/30 02:57:54
nit:
if (!this.training_)
return;
kcarattini
2014/10/30 05:56:18
Done.
| |
| 136 if (chrome.hotwordPrivate.finalizeSpeakerModel) | |
| 137 chrome.hotwordPrivate.finalizeSpeakerModel(); | |
| 138 | |
| 139 // TODO(kcarattini): Implement a notification that speaker model has been | |
| 140 // finalized instead of setting a timeout. | |
| 141 setTimeout(this.onSpeakerModelFinalized.bind(this), 2000); | |
| 142 } | |
| 143 }; | |
| 144 | |
| 145 /** | |
| 146 * 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.
| |
| 147 */ | |
| 148 Flow.prototype.handleHotwordTrigger = function() { | |
| 149 var curStep = | |
| 150 $(this.trainingPagePrefix_ + '-training').querySelector('.listening'); | |
| 151 // TODO(kcarattini): Localize this string. | |
| 152 curStep.querySelector('.text').textContent = 'Recorded'; | |
| 153 curStep.classList.remove('listening'); | |
| 154 curStep.classList.add('recorded'); | |
| 155 | |
| 156 var steps = | |
| 157 $(this.trainingPagePrefix_ + '-training').querySelectorAll('.train'); | |
| 158 var index = Array.prototype.indexOf.call(steps, curStep); | |
| 159 if (steps[index + 1]) { | |
| 160 steps[index + 1].classList.remove('not-started'); | |
| 161 steps[index + 1].classList.add('listening'); | |
| 162 return; | |
| 163 } | |
|
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.
| |
| 164 | |
| 165 // Update the 'Cancel' button. | |
| 166 var buttonElem = $(this.trainingPagePrefix_ + '-cancel-button'); | |
| 167 // TODO(kcarattini): Localize this string. | |
| 168 buttonElem.textContent = 'Please wait ...'; | |
| 169 buttonElem.classList.add('grayed-out'); | |
| 170 buttonElem.classList.remove('finish-button'); | |
| 171 | |
| 172 this.finalizeSpeakerModel(); | |
| 173 }; | |
| 174 | |
| 56 // ---- private methods: | 175 // ---- private methods: |
| 57 | 176 |
| 58 /** | 177 /** |
| 59 * Gets and starts the appropriate flow for the launch mode. | 178 * Gets and starts the appropriate flow for the launch mode. |
|
Dan Beam
2014/10/30 02:57:54
@param {WhateverTypeStateIs} state Doc comment abo
kcarattini
2014/10/30 05:56:18
Done.
| |
| 60 * @private | 179 * @private |
| 61 */ | 180 */ |
| 62 Flow.prototype.startFlowForMode_ = function(state) { | 181 Flow.prototype.startFlowForMode_ = function(state) { |
| 182 this.launchMode_ = state.launchMode; | |
| 63 assert(state.launchMode >= 0 && state.launchMode < FLOWS.length, | 183 assert(state.launchMode >= 0 && state.launchMode < FLOWS.length, |
| 64 'Invalid Launch Mode.'); | 184 'Invalid Launch Mode.'); |
| 65 this.currentFlow_ = FLOWS[state.launchMode]; | 185 this.currentFlow_ = FLOWS[state.launchMode]; |
| 66 this.advanceStep(); | 186 this.advanceStep(); |
| 187 // If the flow begins with a a training step, then start the training flow. | |
| 188 if (state.launchMode == LaunchMode.HOTWORD_ONLY || | |
| 189 state.launchMode == LaunchMode.SPEECH_TRAINING) | |
|
Dan Beam
2014/10/30 02:57:54
curlies
kcarattini
2014/10/30 05:56:17
Done.
| |
| 190 this.startTraining(); | |
| 67 }; | 191 }; |
| 68 | 192 |
| 69 /** | 193 /** |
| 70 * Displays the current step. If the current step is not the first step, | 194 * Displays the current step. If the current step is not the first step, |
| 71 * also hides the previous step. | 195 * also hides the previous step. |
| 72 * @private | 196 * @private |
| 73 */ | 197 */ |
| 74 Flow.prototype.showStep_ = function() { | 198 Flow.prototype.showStep_ = function() { |
| 75 var currentStep = this.currentFlow_[this.currentStepIndex_]; | 199 var currentStep = this.currentFlow_[this.currentStepIndex_]; |
| 76 var previousStep = null; | 200 var previousStep = null; |
| 77 if (this.currentStepIndex_ > 0) | 201 if (this.currentStepIndex_ > 0) |
| 78 previousStep = this.currentFlow_[this.currentStepIndex_ - 1]; | 202 previousStep = this.currentFlow_[this.currentStepIndex_ - 1]; |
| 79 | 203 |
| 80 if (previousStep) | 204 if (previousStep) |
| 81 document.getElementById(previousStep).hidden = true; | 205 document.getElementById(previousStep).hidden = true; |
| 82 | 206 |
| 83 document.getElementById(currentStep).hidden = false; | 207 document.getElementById(currentStep).hidden = false; |
| 84 }; | 208 }; |
| 85 | 209 |
| 86 window.Flow = Flow; | 210 window.Flow = Flow; |
| 87 })(); | 211 })(); |
| OLD | NEW |