summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandeep Siddhartha <sansid@google.com>2014-07-21 10:31:34 -0700
committerSandeep Siddhartha <sansid@google.com>2014-07-22 09:16:18 -0700
commit6daae9622672e0b38fc2efed29f68061d749cacc (patch)
tree94943fab0e4ab27952fffb07141456cfec65fbed
parent70441467f4dc232cd8e6142f0afc117787dc979b (diff)
downloadframeworks_base-6daae9622672e0b38fc2efed29f68061d749cacc.zip
frameworks_base-6daae9622672e0b38fc2efed29f68061d749cacc.tar.gz
frameworks_base-6daae9622672e0b38fc2efed29f68061d749cacc.tar.bz2
AlwaysOnHotwordDetector needs to reflect enrollment changes
Add a callback for when any sound model change happens. This helps the VIS to re-check the availability and either enroll the user, or start/stop recognition. Also shut down any active recognition when VIS dies, or a different hotword detector instance is obtained from VIS. Change-Id: I03f94e78c6ee307afe822a84aebc7e74c64de7b4
-rw-r--r--api/current.txt13
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java122
-rw-r--r--core/java/android/service/voice/IVoiceInteractionService.aidl2
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java96
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java23
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java18
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java52
7 files changed, 247 insertions, 79 deletions
diff --git a/api/current.txt b/api/current.txt
index cb54a5f..863a88b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27324,10 +27324,6 @@ package android.service.voice {
method public int getSupportedRecognitionModes();
method public int startRecognition(int);
method public int stopRecognition();
- field public static final int KEYPHRASE_ENROLLED = 2; // 0x2
- field public static final int KEYPHRASE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
- field public static final int KEYPHRASE_UNENROLLED = 1; // 0x1
- field public static final int KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
field public static final int MANAGE_ACTION_ENROLL = 0; // 0x0
field public static final int MANAGE_ACTION_RE_ENROLL = 1; // 0x1
field public static final int MANAGE_ACTION_UN_ENROLL = 2; // 0x2
@@ -27335,6 +27331,11 @@ package android.service.voice {
field public static final int RECOGNITION_FLAG_NONE = 0; // 0x0
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
+ field public static final int STATE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
+ field public static final int STATE_INVALID = -3; // 0xfffffffd
+ field public static final int STATE_KEYPHRASE_ENROLLED = 2; // 0x2
+ field public static final int STATE_KEYPHRASE_UNENROLLED = 1; // 0x1
+ field public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
field public static final int STATUS_ERROR = -2147483648; // 0x80000000
field public static final int STATUS_OK = 0; // 0x0
}
@@ -27346,10 +27347,12 @@ package android.service.voice {
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
- method public final android.service.voice.AlwaysOnHotwordDetector getAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback);
method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
method public void onReady();
+ method public void onShutdown();
+ method public void onSoundModelsChanged();
method public void startSession(android.os.Bundle);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index ad30f44..27a7b8e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -41,26 +41,32 @@ import java.util.List;
* always-on keyphrase detection APIs.
*/
public class AlwaysOnHotwordDetector {
- //---- States of Keyphrase availability ----//
+ //---- States of Keyphrase availability. Return codes for getAvailability() ----//
/**
- * Indicates that the given keyphrase is not available on the system because of the
- * hardware configuration.
+ * Indicates that this hotword detector is no longer valid for any recognition
+ * and should not be used anymore.
*/
- public static final int KEYPHRASE_HARDWARE_UNAVAILABLE = -2;
+ public static final int STATE_INVALID = -3;
/**
- * Indicates that the given keyphrase is not supported.
+ * Indicates that recognition for the given keyphrase is not available on the system
+ * because of the hardware configuration.
*/
- public static final int KEYPHRASE_UNSUPPORTED = -1;
+ public static final int STATE_HARDWARE_UNAVAILABLE = -2;
+ /**
+ * Indicates that recognition for the given keyphrase is not supported.
+ */
+ public static final int STATE_KEYPHRASE_UNSUPPORTED = -1;
/**
* Indicates that the given keyphrase is not enrolled.
*/
- public static final int KEYPHRASE_UNENROLLED = 1;
+ public static final int STATE_KEYPHRASE_UNENROLLED = 1;
/**
- * Indicates that the given keyphrase is currently enrolled but not being actively listened for.
+ * Indicates that the given keyphrase is currently enrolled and it's possible to start
+ * recognition for it.
*/
- public static final int KEYPHRASE_ENROLLED = 2;
+ public static final int STATE_KEYPHRASE_ENROLLED = 2;
- // Keyphrase management actions ----//
+ // Keyphrase management actions. Used in getManageIntent() ----//
/** Indicates that we need to enroll. */
public static final int MANAGE_ACTION_ENROLL = 0;
/** Indicates that we need to re-enroll. */
@@ -83,7 +89,7 @@ public class AlwaysOnHotwordDetector {
*/
public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 0x1;
- //---- Recognition mode flags ----//
+ //---- Recognition mode flags. Return codes for getSupportedRecognitionModes() ----//
// Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags.
/**
@@ -109,17 +115,20 @@ public class AlwaysOnHotwordDetector {
* This may be null if this keyphrase isn't supported by the enrollment application.
*/
private final KeyphraseMetadata mKeyphraseMetadata;
- /**
- * The sound model for the keyphrase, derived from the model management service
- * (IVoiceInteractionManagerService). May be null if the keyphrase isn't enrolled yet.
- */
- private final KeyphraseSoundModel mEnrolledSoundModel;
private final KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
private final IVoiceInteractionService mVoiceInteractionService;
private final IVoiceInteractionManagerService mModelManagementService;
private final SoundTriggerListener mInternalCallback;
private final Callback mExternalCallback;
private final boolean mDisabled;
+ private final Object mLock = new Object();
+
+ /**
+ * The sound model for the keyphrase, derived from the model management service
+ * (IVoiceInteractionManagerService). May be null if the keyphrase isn't enrolled yet.
+ */
+ private KeyphraseSoundModel mEnrolledSoundModel;
+ private boolean mInvalidated;
/**
* Callbacks for always-on hotword detection.
@@ -151,6 +160,7 @@ public class AlwaysOnHotwordDetector {
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionService voiceInteractionService,
IVoiceInteractionManagerService modelManagementService) {
+ mInvalidated = false;
mText = text;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
@@ -160,28 +170,34 @@ public class AlwaysOnHotwordDetector {
mVoiceInteractionService = voiceInteractionService;
mModelManagementService = modelManagementService;
if (mKeyphraseMetadata != null) {
- mEnrolledSoundModel = internalGetKeyphraseSoundModel(mKeyphraseMetadata.id);
- } else {
- mEnrolledSoundModel = null;
+ mEnrolledSoundModel = internalGetKeyphraseSoundModelLocked(mKeyphraseMetadata.id);
}
int initialAvailability = internalGetAvailabilityLocked();
- mDisabled = (initialAvailability == KEYPHRASE_HARDWARE_UNAVAILABLE)
- || (initialAvailability == KEYPHRASE_UNSUPPORTED);
+ mDisabled = (initialAvailability == STATE_HARDWARE_UNAVAILABLE)
+ || (initialAvailability == STATE_KEYPHRASE_UNSUPPORTED);
}
/**
* Gets the state of always-on hotword detection for the given keyphrase and locale
* on this system.
* Availability implies that the hardware on this system is capable of listening for
- * the given keyphrase or not.
+ * the given keyphrase or not. <p/>
+ * If the return code is one of {@link #STATE_HARDWARE_UNAVAILABLE} or
+ * {@link #STATE_KEYPHRASE_UNSUPPORTED}, no further interaction should be performed with this
+ * detector. <br/>
+ * If the state is {@link #STATE_KEYPHRASE_UNENROLLED} the caller may choose to begin
+ * an enrollment flow for the keyphrase. <br/>
+ * For {@value #STATE_KEYPHRASE_ENROLLED} a recognition can be started as desired. <br/>
+ * If the return code is {@link #STATE_INVALID}, this detector is stale and must not be used.
+ * A new detector should be obtained and used.
*
* @return Indicates if always-on hotword detection is available for the given keyphrase.
- * The return code is one of {@link #KEYPHRASE_HARDWARE_UNAVAILABLE},
- * {@link #KEYPHRASE_UNSUPPORTED}, {@link #KEYPHRASE_UNENROLLED} or
- * {@link #KEYPHRASE_ENROLLED}.
+ * The return code is one of {@link #STATE_HARDWARE_UNAVAILABLE},
+ * {@link #STATE_KEYPHRASE_UNSUPPORTED}, {@link #STATE_KEYPHRASE_UNENROLLED},
+ * {@link #STATE_KEYPHRASE_ENROLLED}, or {@link #STATE_INVALID}.
*/
public int getAvailability() {
- synchronized (this) {
+ synchronized (mLock) {
return internalGetAvailabilityLocked();
}
}
@@ -194,7 +210,7 @@ public class AlwaysOnHotwordDetector {
* before calling this method to avoid this exception.
*/
public int getSupportedRecognitionModes() {
- synchronized (this) {
+ synchronized (mLock) {
return getSupportedRecognitionModesLocked();
}
}
@@ -220,13 +236,13 @@ public class AlwaysOnHotwordDetector {
* before calling this method to avoid this exception.
*/
public int startRecognition(int recognitionFlags) {
- synchronized (this) {
+ synchronized (mLock) {
return startRecognitionLocked(recognitionFlags);
}
}
private int startRecognitionLocked(int recognitionFlags) {
- if (internalGetAvailabilityLocked() != KEYPHRASE_ENROLLED) {
+ if (internalGetAvailabilityLocked() != STATE_KEYPHRASE_ENROLLED) {
throw new UnsupportedOperationException(
"Recognition for the given keyphrase is not supported");
}
@@ -261,13 +277,13 @@ public class AlwaysOnHotwordDetector {
* before calling this method to avoid this exception.
*/
public int stopRecognition() {
- synchronized (this) {
+ synchronized (mLock) {
return stopRecognitionLocked();
}
}
- private synchronized int stopRecognitionLocked() {
- if (internalGetAvailabilityLocked() != KEYPHRASE_ENROLLED) {
+ private int stopRecognitionLocked() {
+ if (internalGetAvailabilityLocked() != STATE_KEYPHRASE_ENROLLED) {
throw new UnsupportedOperationException(
"Recognition for the given keyphrase is not supported");
}
@@ -312,6 +328,10 @@ public class AlwaysOnHotwordDetector {
}
private int internalGetAvailabilityLocked() {
+ if (mInvalidated) {
+ return STATE_INVALID;
+ }
+
ModuleProperties dspModuleProperties = null;
try {
dspModuleProperties =
@@ -321,23 +341,51 @@ public class AlwaysOnHotwordDetector {
}
// No DSP available
if (dspModuleProperties == null) {
- return KEYPHRASE_HARDWARE_UNAVAILABLE;
+ return STATE_HARDWARE_UNAVAILABLE;
}
// No enrollment application supports this keyphrase/locale
if (mKeyphraseMetadata == null) {
- return KEYPHRASE_UNSUPPORTED;
+ return STATE_KEYPHRASE_UNSUPPORTED;
}
+
// This keyphrase hasn't been enrolled.
if (mEnrolledSoundModel == null) {
- return KEYPHRASE_UNENROLLED;
+ return STATE_KEYPHRASE_UNENROLLED;
+ }
+ return STATE_KEYPHRASE_ENROLLED;
+ }
+
+ /**
+ * Invalidates this hotword detector so that any future calls to this result
+ * in an IllegalStateException.
+ *
+ * @hide
+ */
+ void invalidate() {
+ synchronized (mLock) {
+ mInvalidated = true;
+ }
+ }
+
+ /**
+ * Reloads the sound models from the service.
+ *
+ * @hide
+ */
+ void onSoundModelsChanged() {
+ synchronized (mLock) {
+ // TODO: This should stop the recognition if it was using an enrolled sound model
+ // that's no longer available.
+ if (mKeyphraseMetadata != null) {
+ mEnrolledSoundModel = internalGetKeyphraseSoundModelLocked(mKeyphraseMetadata.id);
+ }
}
- return KEYPHRASE_ENROLLED;
}
/**
* @return The corresponding {@link KeyphraseSoundModel} or null if none is found.
*/
- private KeyphraseSoundModel internalGetKeyphraseSoundModel(int keyphraseId) {
+ private KeyphraseSoundModel internalGetKeyphraseSoundModelLocked(int keyphraseId) {
List<KeyphraseSoundModel> soundModels;
try {
soundModels = mModelManagementService
diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl
index c9915a2..e8265a2 100644
--- a/core/java/android/service/voice/IVoiceInteractionService.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionService.aidl
@@ -21,4 +21,6 @@ package android.service.voice;
*/
oneway interface IVoiceInteractionService {
void ready();
+ void soundModelsChanged();
+ void shutdown();
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 982f43d..0c2ba26 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -28,8 +28,8 @@ import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-
import android.provider.Settings;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractionManagerService;
@@ -70,15 +70,27 @@ public class VoiceInteractionService extends Service {
@Override public void ready() {
mHandler.sendEmptyMessage(MSG_READY);
}
+ @Override public void shutdown() {
+ mHandler.sendEmptyMessage(MSG_SHUTDOWN);
+ }
+ @Override public void soundModelsChanged() {
+ mHandler.sendEmptyMessage(MSG_SOUND_MODELS_CHANGED);
+ }
};
MyHandler mHandler;
IVoiceInteractionManagerService mSystemService;
+ private final Object mLock = new Object();
+
private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
+ private AlwaysOnHotwordDetector mHotwordDetector;
+
static final int MSG_READY = 1;
+ static final int MSG_SHUTDOWN = 2;
+ static final int MSG_SOUND_MODELS_CHANGED = 3;
class MyHandler extends Handler {
@Override
@@ -87,6 +99,12 @@ public class VoiceInteractionService extends Service {
case MSG_READY:
onReady();
break;
+ case MSG_SHUTDOWN:
+ onShutdownInternal();
+ break;
+ case MSG_SOUND_MODELS_CHANGED:
+ onSoundModelsChangedInternal();
+ break;
default:
super.handleMessage(msg);
}
@@ -140,9 +158,10 @@ public class VoiceInteractionService extends Service {
/**
* Called during service initialization to tell you when the system is ready
- * to receive interaction from it. You should generally do initialization here
- * rather than in {@link #onCreate()}. Methods such as {@link #startSession}
- * and {@link #getAlwaysOnHotwordDetector} will not be operational until this point.
+ * to receive interaction from it. You should generally do initialization here
+ * rather than in {@link #onCreate()}. Methods such as {@link #startSession(Bundle)} and
+ * {@link #createAlwaysOnHotwordDetector(String, String, android.service.voice.AlwaysOnHotwordDetector.Callback)}
+ * will not be operational until this point.
*/
public void onReady() {
mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
@@ -150,22 +169,67 @@ public class VoiceInteractionService extends Service {
mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
}
+ private void onShutdownInternal() {
+ onShutdown();
+ // Stop any active recognitions when shutting down.
+ // This ensures that if implementations forget to stop any active recognition,
+ // It's still guaranteed to have been stopped.
+ // This helps with cases where the voice interaction implementation is changed
+ // by the user.
+ safelyShutdownHotwordDetector();
+ }
+
+ /**
+ * Called during service de-initialization to tell you when the system is shutting the
+ * service down.
+ */
+ public void onShutdown() {
+ }
+
+ private void onSoundModelsChangedInternal() {
+ synchronized (this) {
+ if (mHotwordDetector != null) {
+ // TODO: Stop recognition if a sound model that was being recognized gets deleted.
+ mHotwordDetector.onSoundModelsChanged();
+ }
+ }
+ onSoundModelsChanged();
+ }
+
+ /**
+ * Called when the sound models available for recognition change.
+ * This may be called if a new sound model is available or
+ * an existing one is updated or removed.
+ * Implementations must check the availability of the hotword detector if they own one
+ * by calling {@link AlwaysOnHotwordDetector#getAvailability()} before calling into it.
+ */
+ public void onSoundModelsChanged() {
+ }
+
/**
+ * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale.
+ * This instance must be retained and used by the client.
+ * Calling this a second time invalidates the previously created hotword detector
+ * which can no longer be used to manage recognition.
+ *
* @param keyphrase The keyphrase that's being used, for example "Hello Android".
* @param locale The locale for which the enrollment needs to be performed.
* This is a Java locale, for example "en_US".
* @param callback The callback to notify of detection events.
* @return An always-on hotword detector for the given keyphrase and locale.
*/
- public final AlwaysOnHotwordDetector getAlwaysOnHotwordDetector(
+ public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
String keyphrase, String locale, AlwaysOnHotwordDetector.Callback callback) {
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
- // TODO: Cache instances and return the same one instead of creating a new interactor
- // for the same keyphrase/locale combination.
- return new AlwaysOnHotwordDetector(keyphrase, locale, callback,
- mKeyphraseEnrollmentInfo, mInterface, mSystemService);
+ synchronized (mLock) {
+ // Allow only one concurrent recognition via the APIs.
+ safelyShutdownHotwordDetector();
+ mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
+ mKeyphraseEnrollmentInfo, mInterface, mSystemService);
+ }
+ return mHotwordDetector;
}
/**
@@ -176,4 +240,18 @@ public class VoiceInteractionService extends Service {
protected final KeyphraseEnrollmentInfo getKeyphraseEnrollmentInfo() {
return mKeyphraseEnrollmentInfo;
}
+
+ private void safelyShutdownHotwordDetector() {
+ try {
+ synchronized (mLock) {
+ if (mHotwordDetector != null) {
+ mHotwordDetector.stopRecognition();
+ mHotwordDetector.invalidate();
+ mHotwordDetector = null;
+ }
+ }
+ } catch (Exception ex) {
+ // Ignore.
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 2ce4971..7b2e4f1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -290,19 +290,22 @@ public class VoiceInteractionManagerService extends SystemService {
final long caller = Binder.clearCallingIdentity();
try {
- // If the keyphrases are not present in the model, delete the model.
+ boolean success = false;
if (model.keyphrases == null) {
- if (mDbHelper.deleteKeyphraseSoundModel(model.uuid)) {
- return SoundTriggerHelper.STATUS_OK;
- } else {
- return SoundTriggerHelper.STATUS_ERROR;
- }
+ // If the keyphrases are not present in the model, delete the model.
+ success = mDbHelper.deleteKeyphraseSoundModel(model.uuid);
} else {
- if (mDbHelper.addOrUpdateKeyphraseSoundModel(model)) {
- return SoundTriggerHelper.STATUS_OK;
- } else {
- return SoundTriggerHelper.STATUS_ERROR;
+ // Else update the model.
+ success = mDbHelper.addOrUpdateKeyphraseSoundModel(model);
+ }
+ if (success) {
+ // Notify the voice interaction service of a change in sound models.
+ if (mImpl != null && mImpl.mService != null) {
+ mImpl.notifySoundModelsChangedLocked();
}
+ return SoundTriggerHelper.STATUS_OK;
+ } else {
+ return SoundTriggerHelper.STATUS_ERROR;
}
} finally {
Binder.restoreCallingIdentity(caller);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 54af5d4..94f227c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -96,6 +96,13 @@ class VoiceInteractionManagerServiceImpl {
@Override
public void onServiceDisconnected(ComponentName name) {
+ try {
+ if (mService != null) {
+ mService.shutdown();
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in shutdown", e);
+ }
mService = null;
}
};
@@ -308,4 +315,15 @@ class VoiceInteractionManagerServiceImpl {
mContext.unregisterReceiver(mBroadcastReceiver);
}
}
+
+ void notifySoundModelsChangedLocked() {
+ if (mService == null) {
+ Slog.w(TAG, "Not bound to voice interaction service " + mComponent);
+ }
+ try {
+ mService.soundModelsChanged();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
+ }
+ }
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index e74307f..e750bb6 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -50,38 +50,54 @@ public class MainInteractionService extends VoiceInteractionService {
Log.i(TAG, "Keyphrase enrollment meta-data: "
+ Arrays.toString(getKeyphraseEnrollmentInfo().listKeyphraseMetadata()));
- mHotwordDetector = getAlwaysOnHotwordDetector("Hello There", "en-US", mHotwordCallback);
+ mHotwordDetector = createAlwaysOnHotwordDetector("Hello There", "en-US", mHotwordCallback);
+ testHotwordAvailabilityStates();
+ }
+
+ @Override
+ public void onSoundModelsChanged() {
int availability = mHotwordDetector.getAvailability();
Log.i(TAG, "Hotword availability = " + availability);
+ if (availability == AlwaysOnHotwordDetector.STATE_INVALID) {
+ mHotwordDetector = createAlwaysOnHotwordDetector("Hello There", "en-US", mHotwordCallback);
+ }
+ testHotwordAvailabilityStates();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Bundle args = new Bundle();
+ args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
+ startSession(args);
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+ private void testHotwordAvailabilityStates() {
+ int availability = mHotwordDetector.getAvailability();
+ Log.i(TAG, "Hotword availability = " + availability);
switch (availability) {
- case AlwaysOnHotwordDetector.KEYPHRASE_HARDWARE_UNAVAILABLE:
- Log.i(TAG, "KEYPHRASE_HARDWARE_UNAVAILABLE");
+ case AlwaysOnHotwordDetector.STATE_INVALID:
+ Log.i(TAG, "STATE_INVALID");
+ break;
+ case AlwaysOnHotwordDetector.STATE_HARDWARE_UNAVAILABLE:
+ Log.i(TAG, "STATE_HARDWARE_UNAVAILABLE");
break;
- case AlwaysOnHotwordDetector.KEYPHRASE_UNSUPPORTED:
- Log.i(TAG, "KEYPHRASE_UNSUPPORTED");
+ case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNSUPPORTED:
+ Log.i(TAG, "STATE_KEYPHRASE_UNSUPPORTED");
break;
- case AlwaysOnHotwordDetector.KEYPHRASE_UNENROLLED:
- Log.i(TAG, "KEYPHRASE_UNENROLLED");
+ case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED:
+ Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED");
Intent enroll = mHotwordDetector.getManageIntent(
AlwaysOnHotwordDetector.MANAGE_ACTION_ENROLL);
Log.i(TAG, "Need to enroll with " + enroll);
break;
- case AlwaysOnHotwordDetector.KEYPHRASE_ENROLLED:
- Log.i(TAG, "KEYPHRASE_ENROLLED");
+ case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED:
+ Log.i(TAG, "STATE_KEYPHRASE_ENROLLED");
int status = mHotwordDetector.startRecognition(
AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE);
Log.i(TAG, "startRecognition status = " + status);
break;
}
}
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Bundle args = new Bundle();
- args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
- startSession(args);
- stopSelf(startId);
- return START_NOT_STICKY;
- }
}