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:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user