[Eraser strings] Remove unused Supervised User infobar and corresponding strings
[chromium-blink-merge.git] / chrome / browser / resources / hotword / audio_client.js
blobf74f84b15f372f3d49363ddb4cf2fd6560e07640
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
3 // found in the LICENSE file.
5 'use strict';
7 /**
8 * @fileoverview This is the audio client content script injected into eligible
9 * Google.com and New tab pages for interaction between the Webpage and the
10 * Hotword extension.
13 (function() {
14 /**
15 * @constructor
17 var AudioClient = function() {
18 /** @private {Element} */
19 this.speechOverlay_ = null;
21 /** @private {number} */
22 this.checkSpeechUiRetries_ = 0;
24 /**
25 * Port used to communicate with the audio manager.
26 * @private {?Port}
28 this.port_ = null;
30 /**
31 * Keeps track of the effects of different commands. Used to verify that
32 * proper UIs are shown to the user.
33 * @private {Object<AudioClient.CommandToPage, Object>}
35 this.uiStatus_ = null;
37 /**
38 * Bound function used to handle commands sent from the page to this script.
39 * @private {Function}
41 this.handleCommandFromPageFunc_ = null;
44 /**
45 * Messages sent to the page to control the voice search UI.
46 * @enum {string}
48 AudioClient.CommandToPage = {
49 HOTWORD_VOICE_TRIGGER: 'vt',
50 HOTWORD_STARTED: 'hs',
51 HOTWORD_ENDED: 'hd',
52 HOTWORD_TIMEOUT: 'ht',
53 HOTWORD_ERROR: 'he'
56 /**
57 * Messages received from the page used to indicate voice search state.
58 * @enum {string}
60 AudioClient.CommandFromPage = {
61 SPEECH_START: 'ss',
62 SPEECH_END: 'se',
63 SPEECH_RESET: 'sr',
64 SHOWING_HOTWORD_START: 'shs',
65 SHOWING_ERROR_MESSAGE: 'sem',
66 SHOWING_TIMEOUT_MESSAGE: 'stm',
67 CLICKED_RESUME: 'hcc',
68 CLICKED_RESTART: 'hcr',
69 CLICKED_DEBUG: 'hcd'
72 /**
73 * Errors that are sent to the hotword extension.
74 * @enum {string}
76 AudioClient.Error = {
77 NO_SPEECH_UI: 'ac1',
78 NO_HOTWORD_STARTED_UI: 'ac2',
79 NO_HOTWORD_TIMEOUT_UI: 'ac3',
80 NO_HOTWORD_ERROR_UI: 'ac4'
83 /**
84 * @const {string}
85 * @private
87 AudioClient.HOTWORD_EXTENSION_ID_ = 'nbpagnldghgfoolbancepceaanlmhfmd';
89 /**
90 * Number of times to retry checking a transient error.
91 * @const {number}
92 * @private
94 AudioClient.MAX_RETRIES = 3;
96 /**
97 * Delay to wait in milliseconds before rechecking for any transient errors.
98 * @const {number}
99 * @private
101 AudioClient.RETRY_TIME_MS_ = 2000;
104 * DOM ID for the speech UI overlay.
105 * @const {string}
106 * @private
108 AudioClient.SPEECH_UI_OVERLAY_ID_ = 'spch';
111 * @const {string}
112 * @private
114 AudioClient.HELP_CENTER_URL_ =
115 'https://support.google.com/chrome/?p=ui_hotword_search';
118 * @const {string}
119 * @private
121 AudioClient.CLIENT_PORT_NAME_ = 'chwcpn';
124 * Existence of the Audio Client.
125 * @const {string}
126 * @private
128 AudioClient.EXISTS_ = 'chwace';
131 * Checks for the presence of speech overlay UI DOM elements.
132 * @private
134 AudioClient.prototype.checkSpeechOverlayUi_ = function() {
135 if (!this.speechOverlay_) {
136 window.setTimeout(this.delayedCheckSpeechOverlayUi_.bind(this),
137 AudioClient.RETRY_TIME_MS_);
138 } else {
139 this.checkSpeechUiRetries_ = 0;
144 * Function called to check for the speech UI overlay after some time has
145 * passed since an initial check. Will either retry triggering the speech
146 * or sends an error message depending on the number of retries.
147 * @private
149 AudioClient.prototype.delayedCheckSpeechOverlayUi_ = function() {
150 this.speechOverlay_ = document.getElementById(
151 AudioClient.SPEECH_UI_OVERLAY_ID_);
152 if (!this.speechOverlay_) {
153 if (this.checkSpeechUiRetries_++ < AudioClient.MAX_RETRIES) {
154 this.sendCommandToPage_(AudioClient.CommandToPage.VOICE_TRIGGER);
155 this.checkSpeechOverlayUi_();
156 } else {
157 this.sendCommandToExtension_(AudioClient.Error.NO_SPEECH_UI);
159 } else {
160 this.checkSpeechUiRetries_ = 0;
165 * Checks that the triggered UI is actually displayed.
166 * @param {AudioClient.CommandToPage} command Command that was send.
167 * @private
169 AudioClient.prototype.checkUi_ = function(command) {
170 this.uiStatus_[command].timeoutId =
171 window.setTimeout(this.failedCheckUi_.bind(this, command),
172 AudioClient.RETRY_TIME_MS_);
176 * Function called when the UI verification is not called in time. Will either
177 * retry the command or sends an error message, depending on the number of
178 * retries for the command.
179 * @param {AudioClient.CommandToPage} command Command that was sent.
180 * @private
182 AudioClient.prototype.failedCheckUi_ = function(command) {
183 if (this.uiStatus_[command].tries++ < AudioClient.MAX_RETRIES) {
184 this.sendCommandToPage_(command);
185 this.checkUi_(command);
186 } else {
187 this.sendCommandToExtension_(this.uiStatus_[command].error);
192 * Confirm that an UI element has been shown.
193 * @param {AudioClient.CommandToPage} command UI to confirm.
194 * @private
196 AudioClient.prototype.verifyUi_ = function(command) {
197 if (this.uiStatus_[command].timeoutId) {
198 window.clearTimeout(this.uiStatus_[command].timeoutId);
199 this.uiStatus_[command].timeoutId = null;
200 this.uiStatus_[command].tries = 0;
205 * Sends a command to the audio manager.
206 * @param {string} commandStr command to send to plugin.
207 * @private
209 AudioClient.prototype.sendCommandToExtension_ = function(commandStr) {
210 if (this.port_)
211 this.port_.postMessage({'cmd': commandStr});
215 * Handles a message from the audio manager.
216 * @param {{cmd: string}} commandObj Command from the audio manager.
217 * @private
219 AudioClient.prototype.handleCommandFromExtension_ = function(commandObj) {
220 var command = commandObj['cmd'];
221 if (command) {
222 switch (command) {
223 case AudioClient.CommandToPage.HOTWORD_VOICE_TRIGGER:
224 this.sendCommandToPage_(command);
225 this.checkSpeechOverlayUi_();
226 break;
227 case AudioClient.CommandToPage.HOTWORD_STARTED:
228 this.sendCommandToPage_(command);
229 this.checkUi_(command);
230 break;
231 case AudioClient.CommandToPage.HOTWORD_ENDED:
232 this.sendCommandToPage_(command);
233 break;
234 case AudioClient.CommandToPage.HOTWORD_TIMEOUT:
235 this.sendCommandToPage_(command);
236 this.checkUi_(command);
237 break;
238 case AudioClient.CommandToPage.HOTWORD_ERROR:
239 this.sendCommandToPage_(command);
240 this.checkUi_(command);
241 break;
247 * @param {AudioClient.CommandToPage} commandStr Command to send.
248 * @private
250 AudioClient.prototype.sendCommandToPage_ = function(commandStr) {
251 window.postMessage({'type': commandStr}, '*');
255 * Handles a message from the html window.
256 * @param {!MessageEvent} messageEvent Message event from the window.
257 * @private
259 AudioClient.prototype.handleCommandFromPage_ = function(messageEvent) {
260 if (messageEvent.source == window && messageEvent.data.type) {
261 var command = messageEvent.data.type;
262 switch (command) {
263 case AudioClient.CommandFromPage.SPEECH_START:
264 this.speechActive_ = true;
265 this.sendCommandToExtension_(command);
266 break;
267 case AudioClient.CommandFromPage.SPEECH_END:
268 this.speechActive_ = false;
269 this.sendCommandToExtension_(command);
270 break;
271 case AudioClient.CommandFromPage.SPEECH_RESET:
272 this.speechActive_ = false;
273 this.sendCommandToExtension_(command);
274 break;
275 case 'SPEECH_RESET': // Legacy, for embedded NTP.
276 this.speechActive_ = false;
277 this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_END);
278 break;
279 case AudioClient.CommandFromPage.CLICKED_RESUME:
280 this.sendCommandToExtension_(command);
281 break;
282 case AudioClient.CommandFromPage.CLICKED_RESTART:
283 this.sendCommandToExtension_(command);
284 break;
285 case AudioClient.CommandFromPage.CLICKED_DEBUG:
286 window.open(AudioClient.HELP_CENTER_URL_, '_blank');
287 break;
288 case AudioClient.CommandFromPage.SHOWING_HOTWORD_START:
289 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_STARTED);
290 break;
291 case AudioClient.CommandFromPage.SHOWING_ERROR_MESSAGE:
292 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_ERROR);
293 break;
294 case AudioClient.CommandFromPage.SHOWING_TIMEOUT_MESSAGE:
295 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_TIMEOUT);
296 break;
302 * Initialize the content script.
304 AudioClient.prototype.initialize = function() {
305 if (AudioClient.EXISTS_ in window)
306 return;
307 window[AudioClient.EXISTS_] = true;
309 // UI verification object.
310 this.uiStatus_ = {};
311 this.uiStatus_[AudioClient.CommandToPage.HOTWORD_STARTED] = {
312 timeoutId: null,
313 tries: 0,
314 error: AudioClient.Error.NO_HOTWORD_STARTED_UI
316 this.uiStatus_[AudioClient.CommandToPage.HOTWORD_TIMEOUT] = {
317 timeoutId: null,
318 tries: 0,
319 error: AudioClient.Error.NO_HOTWORD_TIMEOUT_UI
321 this.uiStatus_[AudioClient.CommandToPage.HOTWORD_ERROR] = {
322 timeoutId: null,
323 tries: 0,
324 error: AudioClient.Error.NO_HOTWORD_ERROR_UI
327 this.handleCommandFromPageFunc_ = this.handleCommandFromPage_.bind(this);
328 window.addEventListener('message', this.handleCommandFromPageFunc_, false);
329 this.initPort_();
333 * Initialize the communications port with the audio manager. This
334 * function will be also be called again if the audio-manager
335 * disconnects for some reason (such as the extension
336 * background.html page being reloaded).
337 * @private
339 AudioClient.prototype.initPort_ = function() {
340 this.port_ = chrome.runtime.connect(
341 AudioClient.HOTWORD_EXTENSION_ID_,
342 {'name': AudioClient.CLIENT_PORT_NAME_});
343 // Note that this listen may have to be destroyed manually if AudioClient
344 // is ever destroyed on this tab.
345 this.port_.onDisconnect.addListener(
346 (function(e) {
347 if (this.handleCommandFromPageFunc_) {
348 window.removeEventListener(
349 'message', this.handleCommandFromPageFunc_, false);
351 delete window[AudioClient.EXISTS_];
352 }).bind(this));
354 // See note above.
355 this.port_.onMessage.addListener(
356 this.handleCommandFromExtension_.bind(this));
358 if (this.speechActive_) {
359 this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_START);
360 } else {
361 // It's possible for this script to be injected into the page after it has
362 // completed loaded (i.e. when prerendering). In this case, this script
363 // won't receive a SPEECH_RESET from the page to forward onto the
364 // extension. To make up for this, always send a SPEECH_RESET. This means
365 // in most cases, the extension will receive SPEECH_RESET twice, one from
366 // this sendCommandToExtension_ and the one forwarded from the page. But
367 // that's OK and the extension can handle it.
368 this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_RESET);
372 // Initializes as soon as the code is ready, do not wait for the page.
373 new AudioClient().initialize();
374 })();