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() { |
| 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() { | |
| 86 // Don't start a training session if one already exists. | |
| 87 if (this.training_) | |
| 88 return; | |
| 89 | |
| 90 this.training_ = true; | |
| 91 if (this.launchMode_ == LaunchMode.HOTWORD_ONLY || | |
| 92 this.launchMode_ == LaunchMode.RETRAIN) { | |
| 93 this.trainingPagePrefix_ = 'hotword-only'; | |
| 94 } | |
| 95 if (this.launchMode_ == LaunchMode.HOTWORD_AND_AUDIO_HISTORY) | |
| 96 this.trainingPagePrefix_ = 'speech-training'; | |
|
Dan Beam
2014/10/30 22:25:35
maybe this code should be:
switch (this.launchM
kcarattini
2014/10/31 00:00:43
Done.
| |
| 97 | |
| 98 if (chrome.hotwordPrivate.onHotwordTriggered) { | |
| 99 chrome.hotwordPrivate.onHotwordTriggered.addListener( | |
| 100 this.handleHotwordTrigger_.bind(this)); | |
| 101 } | |
| 102 if (chrome.hotwordPrivate.startTraining) | |
| 103 chrome.hotwordPrivate.startTraining(); | |
| 104 }; | |
| 105 | |
| 106 /** | |
| 107 * Stops the training process. | |
| 108 */ | |
| 109 Flow.prototype.stopTraining = function() { | |
| 110 if (!this.training_) | |
| 111 return; | |
| 112 | |
| 113 this.training_ = false; | |
| 114 if (chrome.hotwordPrivate.onHotwordTriggered) { | |
| 115 chrome.hotwordPrivate.onHotwordTriggered. | |
| 116 removeListener(this.handleHotwordTrigger_); | |
| 117 } | |
| 118 if (chrome.hotwordPrivate.stopTraining) | |
| 119 chrome.hotwordPrivate.stopTraining(); | |
|
rpetterson
2014/10/30 17:13:13
indent
kcarattini
2014/10/31 00:00:43
Done.
| |
| 120 }; | |
| 121 | |
| 122 /** | |
| 123 * Handles the speaker model finalized event. | |
| 124 */ | |
| 125 Flow.prototype.onSpeakerModelFinalized = function() { | |
| 126 this.stopTraining(); | |
| 127 | |
| 128 if (chrome.hotwordPrivate.setAudioLoggingEnabled) | |
| 129 chrome.hotwordPrivate.setAudioLoggingEnabled(true, function() {}); | |
|
rpetterson
2014/10/30 17:13:13
indent
kcarattini
2014/10/31 00:00:43
Done.
| |
| 130 | |
| 131 if (chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled) { | |
| 132 chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled(true, | |
| 133 this.advanceStep.bind(this)); | |
| 134 } | |
| 135 }; | |
| 136 | |
| 56 // ---- private methods: | 137 // ---- private methods: |
| 57 | 138 |
| 58 /** | 139 /** |
| 140 * Completes the training process. | |
| 141 * @private | |
| 142 */ | |
| 143 Flow.prototype.finalizeSpeakerModel_ = function() { | |
| 144 if (!this.training_) | |
| 145 return; | |
| 146 | |
| 147 if (chrome.hotwordPrivate.finalizeSpeakerModel) | |
| 148 chrome.hotwordPrivate.finalizeSpeakerModel(); | |
| 149 | |
| 150 // TODO(kcarattini): Implement a notification that speaker model has been | |
| 151 // finalized instead of setting a timeout. | |
| 152 setTimeout(this.onSpeakerModelFinalized.bind(this), 2000); | |
| 153 }; | |
| 154 | |
| 155 /** | |
| 156 * Handles a hotword trigger event and updates the training UI. | |
| 157 * @private | |
| 158 */ | |
| 159 Flow.prototype.handleHotwordTrigger_ = function() { | |
| 160 var curStep = | |
| 161 $(this.trainingPagePrefix_ + '-training').querySelector('.listening'); | |
| 162 // TODO(kcarattini): Localize this string. | |
| 163 curStep.querySelector('.text').textContent = 'Recorded'; | |
| 164 curStep.classList.remove('listening'); | |
| 165 curStep.classList.add('recorded'); | |
| 166 | |
| 167 var steps = | |
| 168 $(this.trainingPagePrefix_ + '-training').querySelectorAll('.train'); | |
| 169 var index = Array.prototype.indexOf.call(steps, curStep); | |
| 170 if (steps[index + 1]) { | |
| 171 steps[index + 1].classList.remove('not-started'); | |
| 172 steps[index + 1].classList.add('listening'); | |
| 173 return; | |
| 174 } | |
| 175 | |
| 176 // Only the last step makes it here. | |
| 177 var buttonElem = $(this.trainingPagePrefix_ + '-cancel-button'); | |
| 178 // TODO(kcarattini): Localize this string. | |
| 179 buttonElem.textContent = 'Please wait ...'; | |
| 180 buttonElem.classList.add('grayed-out'); | |
| 181 buttonElem.classList.remove('finish-button'); | |
| 182 | |
| 183 this.finalizeSpeakerModel_(); | |
| 184 }; | |
| 185 | |
| 186 /** | |
| 59 * Gets and starts the appropriate flow for the launch mode. | 187 * Gets and starts the appropriate flow for the launch mode. |
| 188 * @param {chrome.hotwordPrivate.LaunchState} state Launch state of the | |
| 189 * Hotword Audio Verification App. | |
| 60 * @private | 190 * @private |
| 61 */ | 191 */ |
| 62 Flow.prototype.startFlowForMode_ = function(state) { | 192 Flow.prototype.startFlowForMode_ = function(state) { |
| 193 this.launchMode_ = state.launchMode; | |
| 63 assert(state.launchMode >= 0 && state.launchMode < FLOWS.length, | 194 assert(state.launchMode >= 0 && state.launchMode < FLOWS.length, |
| 64 'Invalid Launch Mode.'); | 195 'Invalid Launch Mode.'); |
| 65 this.currentFlow_ = FLOWS[state.launchMode]; | 196 this.currentFlow_ = FLOWS[state.launchMode]; |
| 66 this.advanceStep(); | 197 this.advanceStep(); |
| 198 // If the flow begins with a a training step, then start the training flow. | |
| 199 if (state.launchMode == LaunchMode.HOTWORD_ONLY || | |
| 200 state.launchMode == LaunchMode.SPEECH_TRAINING) { | |
| 201 this.startTraining(); | |
| 202 } | |
| 67 }; | 203 }; |
| 68 | 204 |
| 69 /** | 205 /** |
| 70 * Displays the current step. If the current step is not the first step, | 206 * Displays the current step. If the current step is not the first step, |
| 71 * also hides the previous step. | 207 * also hides the previous step. |
| 72 * @private | 208 * @private |
| 73 */ | 209 */ |
| 74 Flow.prototype.showStep_ = function() { | 210 Flow.prototype.showStep_ = function() { |
| 75 var currentStep = this.currentFlow_[this.currentStepIndex_]; | 211 var currentStep = this.currentFlow_[this.currentStepIndex_]; |
| 76 var previousStep = null; | 212 var previousStep = null; |
| 77 if (this.currentStepIndex_ > 0) | 213 if (this.currentStepIndex_ > 0) |
| 78 previousStep = this.currentFlow_[this.currentStepIndex_ - 1]; | 214 previousStep = this.currentFlow_[this.currentStepIndex_ - 1]; |
| 79 | 215 |
| 80 if (previousStep) | 216 if (previousStep) |
| 81 document.getElementById(previousStep).hidden = true; | 217 document.getElementById(previousStep).hidden = true; |
| 82 | 218 |
| 83 document.getElementById(currentStep).hidden = false; | 219 document.getElementById(currentStep).hidden = false; |
| 84 }; | 220 }; |
| 85 | 221 |
| 86 window.Flow = Flow; | 222 window.Flow = Flow; |
| 87 })(); | 223 })(); |
| OLD | NEW |