am 68f133b4: am a8d8e4c4: am e829259d: Merge "Fix the Locale story in the hotword API" into lmp-dev

* commit '68f133b422733f89c9e226c636ce6153d4e86f1c':
  Fix the Locale story in the hotword API
This commit is contained in:
Sandeep Siddhartha
2014-08-25 08:23:41 +00:00
committed by Android Git Automerger
7 changed files with 102 additions and 49 deletions

View File

@@ -27528,7 +27528,7 @@ package android.service.voice {
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback);
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, 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();

View File

@@ -25,6 +25,8 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.service.voice.AlwaysOnHotwordDetector;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;
@@ -35,6 +37,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
/**
* Enrollment information about the different available keyphrases.
@@ -151,33 +154,8 @@ public class KeyphraseEnrollmentInfo {
TypedArray array = res.obtainAttributes(attrs,
com.android.internal.R.styleable.VoiceEnrollmentApplication);
int searchKeyphraseId = array.getInt(
com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId,
-1);
if (searchKeyphraseId != -1) {
String searchKeyphrase = array.getString(com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphrase);
if (searchKeyphrase == null) {
searchKeyphrase = "";
}
String searchKeyphraseSupportedLocales =
array.getString(com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
String[] supportedLocales = new String[0];
// Get all the supported locales from the comma-delimted string.
if (searchKeyphraseSupportedLocales != null
&& !searchKeyphraseSupportedLocales.isEmpty()) {
supportedLocales = searchKeyphraseSupportedLocales.split(",");
}
int recognitionModes = array.getInt(com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseRecognitionFlags, 0);
mKeyphrases = new KeyphraseMetadata[1];
mKeyphrases[0] = new KeyphraseMetadata(
searchKeyphraseId, searchKeyphrase, supportedLocales, recognitionModes);
} else {
mParseError = "searchKeyphraseId not specified in meta-data";
return;
}
initializeKeyphrasesFromTypedArray(array);
array.recycle();
} catch (XmlPullParserException e) {
mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
@@ -195,6 +173,65 @@ public class KeyphraseEnrollmentInfo {
}
}
private void initializeKeyphrasesFromTypedArray(TypedArray array) {
// Get the keyphrase ID.
int searchKeyphraseId = array.getInt(
com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId, -1);
if (searchKeyphraseId <= 0) {
mParseError = "No valid searchKeyphraseId specified in meta-data";
Slog.w(TAG, mParseError);
return;
}
// Get the keyphrase text.
String searchKeyphrase = array.getString(
com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphrase);
if (searchKeyphrase == null) {
mParseError = "No valid searchKeyphrase specified in meta-data";
Slog.w(TAG, mParseError);
return;
}
// Get the supported locales.
String searchKeyphraseSupportedLocales = array.getString(
com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
if (searchKeyphraseSupportedLocales == null) {
mParseError = "No valid searchKeyphraseSupportedLocales specified in meta-data";
Slog.w(TAG, mParseError);
return;
}
ArraySet<Locale> locales = new ArraySet<>();
// Try adding locales if the locale string is non-empty.
if (!TextUtils.isEmpty(searchKeyphraseSupportedLocales)) {
try {
String[] supportedLocalesDelimited = searchKeyphraseSupportedLocales.split(",");
for (int i = 0; i < supportedLocalesDelimited.length; i++) {
locales.add(Locale.forLanguageTag(supportedLocalesDelimited[i]));
}
} catch (Exception ex) {
// We catch a generic exception here because we don't want the system service
// to be affected by a malformed metadata because invalid locales were specified
// by the system application.
mParseError = "Error reading searchKeyphraseSupportedLocales from meta-data";
Slog.w(TAG, mParseError, ex);
return;
}
}
// Get the supported recognition modes.
int recognitionModes = array.getInt(com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseRecognitionFlags, -1);
if (recognitionModes < 0) {
mParseError = "No valid searchKeyphraseRecognitionFlags specified in meta-data";
Slog.w(TAG, mParseError);
return;
}
mKeyphrases = new KeyphraseMetadata[1];
mKeyphrases[0] = new KeyphraseMetadata(searchKeyphraseId, searchKeyphrase, locales,
recognitionModes);
}
public String getParseError() {
return mParseError;
}
@@ -217,11 +254,10 @@ public class KeyphraseEnrollmentInfo {
* or {@link AlwaysOnHotwordDetector#MANAGE_ACTION_UN_ENROLL}
* @param keyphrase The keyphrase that the user needs to be enrolled to.
* @param locale The locale for which the enrollment needs to be performed.
* This is a Java locale, for example "en_US".
* @return An {@link Intent} to manage the keyphrase. This can be null if managing the
* given keyphrase/locale combination isn't possible.
*/
public Intent getManageKeyphraseIntent(int action, String keyphrase, String locale) {
public Intent getManageKeyphraseIntent(int action, String keyphrase, Locale locale) {
if (mEnrollmentPackage == null || mEnrollmentPackage.isEmpty()) {
Slog.w(TAG, "No enrollment application exists");
return null;
@@ -248,7 +284,7 @@ public class KeyphraseEnrollmentInfo {
* @return The metadata, if the enrollment client supports the given keyphrase
* and locale, null otherwise.
*/
public KeyphraseMetadata getKeyphraseMetadata(String keyphrase, String locale) {
public KeyphraseMetadata getKeyphraseMetadata(String keyphrase, Locale locale) {
if (mKeyphrases == null || mKeyphrases.length == 0) {
Slog.w(TAG, "Enrollment application doesn't support keyphrases");
return null;

View File

@@ -18,6 +18,8 @@ package android.hardware.soundtrigger;
import android.util.ArraySet;
import java.util.Locale;
/**
* A Voice Keyphrase metadata read from the enrollment application.
*
@@ -26,17 +28,14 @@ import android.util.ArraySet;
public class KeyphraseMetadata {
public final int id;
public final String keyphrase;
public final ArraySet<String> supportedLocales;
public final ArraySet<Locale> supportedLocales;
public final int recognitionModeFlags;
public KeyphraseMetadata(int id, String keyphrase, String[] supportedLocales,
public KeyphraseMetadata(int id, String keyphrase, ArraySet<Locale> supportedLocales,
int recognitionModeFlags) {
this.id = id;
this.keyphrase = keyphrase;
this.supportedLocales = new ArraySet<String>(supportedLocales.length);
for (String locale : supportedLocales) {
this.supportedLocales.add(locale);
}
this.supportedLocales = supportedLocales;
this.recognitionModeFlags = recognitionModeFlags;
}
@@ -56,7 +55,7 @@ public class KeyphraseMetadata {
/**
* @return Indicates if we support the given locale.
*/
public boolean supportsLocale(String locale) {
public boolean supportsLocale(Locale locale) {
return supportedLocales.isEmpty() || supportedLocales.contains(locale);
}
}

View File

@@ -39,10 +39,10 @@ import android.util.Slog;
import com.android.internal.app.IVoiceInteractionManagerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
/**
* A class that lets a VoiceInteractionService implementation interact with
@@ -167,7 +167,7 @@ public class AlwaysOnHotwordDetector {
private static final int MSG_DETECTION_RESUME = 5;
private final String mText;
private final String mLocale;
private final Locale mLocale;
/**
* The metadata of the Keyphrase, derived from the enrollment application.
* This may be null if this keyphrase isn't supported by the enrollment application.
@@ -317,7 +317,7 @@ public class AlwaysOnHotwordDetector {
*
* @hide
*/
public AlwaysOnHotwordDetector(String text, String locale, Callback callback,
public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionService voiceInteractionService,
IVoiceInteractionManagerService modelManagementService) {
@@ -491,8 +491,6 @@ public class AlwaysOnHotwordDetector {
*/
void onSoundModelsChanged() {
synchronized (mLock) {
// FIXME: This should stop the recognition if it was using an enrolled sound model
// that's no longer available.
if (mAvailability == STATE_INVALID
|| mAvailability == STATE_HARDWARE_UNAVAILABLE
|| mAvailability == STATE_KEYPHRASE_UNSUPPORTED) {
@@ -500,6 +498,13 @@ public class AlwaysOnHotwordDetector {
return;
}
// Stop the recognition before proceeding.
// This is done because we want to stop the recognition on an older model if it changed
// or was deleted.
// The availability change callback should ensure that the client starts recognition
// again if needed.
stopRecognitionLocked();
// Execute a refresh availability task - which should then notify of a change.
new RefreshAvailabiltyTask().execute();
}

View File

@@ -35,6 +35,7 @@ import com.android.internal.app.IVoiceInteractionManagerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Locale;
/**
@@ -163,7 +164,7 @@ 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(Bundle)} and
* {@link #createAlwaysOnHotwordDetector(String, String, android.service.voice.AlwaysOnHotwordDetector.Callback)}
* {@link #createAlwaysOnHotwordDetector(String, Locale, android.service.voice.AlwaysOnHotwordDetector.Callback)}
* will not be operational until this point.
*/
public void onReady() {
@@ -199,6 +200,17 @@ public class VoiceInteractionService extends Service {
}
}
/**
* FIXME: Remove once the prebuilts are updated.
*
* @hide
*/
@Deprecated
public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
String keyphrase, String locale, AlwaysOnHotwordDetector.Callback callback) {
return createAlwaysOnHotwordDetector(keyphrase, new Locale(locale), callback);
}
/**
* Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale.
* This instance must be retained and used by the client.
@@ -207,12 +219,11 @@ public class VoiceInteractionService extends Service {
*
* @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 createAlwaysOnHotwordDetector(
String keyphrase, String locale, AlwaysOnHotwordDetector.Callback callback) {
String keyphrase, Locale locale, AlwaysOnHotwordDetector.Callback callback) {
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}

View File

@@ -6930,8 +6930,8 @@
<attr name="searchKeyphraseId" format="integer" />
<!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide @SystemApi -->
<attr name="searchKeyphrase" format="string" />
<!-- A comma separated list of java locales that are supported for this keyphrase,
or empty if not locale dependent. @hide @SystemApi -->
<!-- A comma separated list of BCP-47 language tag for locales that are supported
for this keyphrase, or empty if not locale dependent. @hide @SystemApi -->
<attr name="searchKeyphraseSupportedLocales" format="string" />
<!-- Flags for supported recognition modes. @hide @SystemApi -->
<attr name="searchKeyphraseRecognitionFlags">

View File

@@ -25,6 +25,7 @@ import android.service.voice.VoiceInteractionService;
import android.util.Log;
import java.util.Arrays;
import java.util.Locale;
public class MainInteractionService extends VoiceInteractionService {
static final String TAG = "MainInteractionService";
@@ -67,7 +68,8 @@ public class MainInteractionService extends VoiceInteractionService {
Log.i(TAG, "Keyphrase enrollment meta-data: "
+ Arrays.toString(getKeyphraseEnrollmentInfo().listKeyphraseMetadata()));
mHotwordDetector = createAlwaysOnHotwordDetector("Hello There", "en-US", mHotwordCallback);
mHotwordDetector = createAlwaysOnHotwordDetector(
"Hello There", new Locale("en-US"), mHotwordCallback);
}
@Override