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 |