Index: chrome/browser/resources/hotword/state_manager.js |
diff --git a/chrome/browser/resources/hotword/state_manager.js b/chrome/browser/resources/hotword/state_manager.js |
index 39e176b278571580e1788d7458b88931c38ac542..81331e337f2ecae6eb91c84d088281367e73e3c2 100644 |
--- a/chrome/browser/resources/hotword/state_manager.js |
+++ b/chrome/browser/resources/hotword/state_manager.js |
@@ -6,6 +6,38 @@ cr.define('hotword', function() { |
'use strict'; |
/** |
+ * Trivial container class for session information. |
+ * @param {!hotword.constants.SessionSource} source Source of the hotword |
+ * session. |
+ * @param {!function()} triggerCb Callback invoked when the hotword has |
+ * triggered. |
+ * @param {!function()} startedCb Callback invoked when the session has |
+ * been started successfully. |
+ * @constructor |
+ * @struct |
+ * @private |
+ */ |
+ function Session_(source, triggerCb, startedCb) { |
+ /** |
+ * Source of the hotword session request. |
+ * @private {!hotword.constants.SessionSource} |
+ */ |
+ this.source_ = source; |
+ |
+ /** |
+ * Callback invoked when the hotword has triggered. |
+ * @private {!function()} |
+ */ |
+ this.triggerCb_ = triggerCb; |
+ |
+ /** |
+ * Callback invoked when the session has been started successfully. |
+ * @private {?function()} |
+ */ |
+ this.startedCb_ = startedCb; |
+ } |
+ |
+ /** |
* Class to manage hotwording state. Starts/stops the hotword detector based |
* on user settings, session requests, and any other factors that play into |
* whether or not hotwording should be running. |
@@ -32,16 +64,16 @@ cr.define('hotword', function() { |
this.pluginManager_ = null; |
/** |
- * Source of the current hotword session. |
- * @private {?hotword.constants.SessionSource} |
+ * Currently active hotwording sessions. |
+ * @private {!Array.<hotword.Session_>} |
*/ |
- this.sessionSource_ = null; |
+ this.sessions_ = []; |
/** |
- * Callback to run when the hotword detector has successfully started. |
- * @private {!function()} |
+ * Event that fires when the hotwording status has changed. |
+ * @type {!chrome.Event} |
*/ |
- this.sessionStartedCb_ = null; |
+ this.onStatusChanged = new chrome.Event(); |
/** |
* Hotword trigger audio notification... a.k.a The Chime (tm). |
@@ -80,6 +112,23 @@ cr.define('hotword', function() { |
}, |
/** |
+ * @return {boolean} True if hotwording is enabled. |
+ */ |
+ isEnabled: function() { |
+ assert(this.hotwordStatus_); |
+ return this.hotwordStatus_.enabled; |
+ }, |
+ |
+ /** |
+ * @return {boolean} True if always-on hotwording is enabled. |
+ */ |
+ isAlwaysOnEnabled: function() { |
+ assert(this.hotwordStatus_); |
+ return this.hotwordStatus_.enabled && |
+ this.hotwordStatus_.alwaysOnEnabled; |
+ }, |
+ |
+ /** |
* Callback for hotwordPrivate.getStatus() function. |
* @param {chrome.hotwordPrivate.StatusDetails} status Current hotword |
* status. |
@@ -89,6 +138,8 @@ cr.define('hotword', function() { |
hotword.debug('New hotword status', status); |
this.hotwordStatus_ = status; |
this.updateStateFromStatus_(); |
+ |
+ this.onStatusChanged.dispatch(); |
}, |
/** |
@@ -102,17 +153,12 @@ cr.define('hotword', function() { |
if (this.hotwordStatus_.enabled) { |
// Start the detector if there's a session, and shut it down if there |
// isn't. |
- // TODO(amistry): Support stacking sessions. This can happen when the |
- // user opens google.com or the NTP, then opens the launcher. Opening |
- // google.com will create one session, and opening the launcher will |
- // create the second. Closing the launcher should re-activate the |
- // google.com session. |
// NOTE(amistry): With always-on, we want a different behaviour with |
// sessions since the detector should always be running. The exception |
// being when the user triggers by saying 'Ok Google'. In that case, the |
// detector stops, so starting/stopping the launcher session should |
// restart the detector. |
- if (this.sessionSource_) |
+ if (this.sessions_.length) |
this.startDetector_(); |
else |
this.shutdownDetector_(); |
@@ -180,9 +226,12 @@ cr.define('hotword', function() { |
this.state_ = State_.RUNNING; |
this.pluginManager_.startRecognizer(); |
} |
- if (this.sessionStartedCb_) { |
- this.sessionStartedCb_(); |
- this.sessionStartedCb_ = null; |
+ for (var i = 0; i < this.sessions_.length; i++) { |
+ var session = this.sessions_[i]; |
+ if (session.startedCb_) { |
+ session.startedCb_(); |
+ session.startedCb_ = null; |
+ } |
} |
}, |
@@ -243,12 +292,28 @@ cr.define('hotword', function() { |
// Play the chime. |
this.chime_.play(); |
- chrome.hotwordPrivate.notifyHotwordRecognition('search', function() {}); |
+ // Implicitly clear the top session. A session needs to be started in |
+ // order to restart the detector. |
+ if (this.sessions_.length) { |
+ var session = this.sessions_.pop(); |
+ if (session.triggerCb_) |
+ session.triggerCb_(); |
+ } |
+ }, |
- // Implicitly clear the session. A session needs to be started in order to |
- // restart the detector. |
- this.sessionSource_ = null; |
- this.sessionStartedCb_ = null; |
+ /** |
+ * Remove a hotwording session from the given source. |
+ * @param {!hotword.constants.SessionSource} source Source of the hotword |
+ * session request. |
+ * @private |
+ */ |
+ removeSession_: function(source) { |
+ for (var i = 0; i < this.sessions_.length; i++) { |
+ if (this.sessions_[i].source_ == source) { |
+ this.sessions_.splice(i, 1); |
+ break; |
+ } |
+ } |
}, |
/** |
@@ -257,11 +322,13 @@ cr.define('hotword', function() { |
* session request. |
* @param {!function()} startedCb Callback invoked when the session has |
* been started successfully. |
+ * @param {!function()} triggerCb Callback invoked when the hotword has |
+ * triggered. |
*/ |
- startSession: function(source, startedCb) { |
+ startSession: function(source, startedCb, triggerCb) { |
hotword.debug('Starting session for source: ' + source); |
- this.sessionSource_ = source; |
- this.sessionStartedCb_ = startedCb; |
+ this.removeSession_(source); |
+ this.sessions_.push(new Session_(source, triggerCb, startedCb)); |
this.updateStateFromStatus_(); |
}, |
@@ -272,8 +339,7 @@ cr.define('hotword', function() { |
*/ |
stopSession: function(source) { |
hotword.debug('Stopping session for source: ' + source); |
- this.sessionSource_ = null; |
- this.sessionStartedCb_ = null; |
+ this.removeSession_(source); |
this.updateStateFromStatus_(); |
} |
}; |