Merge "Support multiple Enrollment APKs" into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9e928c1f71
@@ -35,9 +35,11 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Enrollment information about the different available keyphrases.
|
||||
@@ -82,8 +84,16 @@ public class KeyphraseEnrollmentInfo {
|
||||
public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
|
||||
"com.android.intent.extra.VOICE_KEYPHRASE_LOCALE";
|
||||
|
||||
private KeyphraseMetadata[] mKeyphrases;
|
||||
private String mEnrollmentPackage;
|
||||
/**
|
||||
* List of available keyphrases.
|
||||
*/
|
||||
final private KeyphraseMetadata[] mKeyphrases;
|
||||
|
||||
/**
|
||||
* Map between KeyphraseMetadata and the package name of the enrollment app that provides it.
|
||||
*/
|
||||
final private Map<KeyphraseMetadata, String> mKeyphrasePackageMap;
|
||||
|
||||
private String mParseError;
|
||||
|
||||
public KeyphraseEnrollmentInfo(PackageManager pm) {
|
||||
@@ -94,15 +104,17 @@ public class KeyphraseEnrollmentInfo {
|
||||
new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
|
||||
if (ris == null || ris.isEmpty()) {
|
||||
// No application capable of enrolling for voice keyphrases is present.
|
||||
mParseError = "No enrollment application found";
|
||||
mParseError = "No enrollment applications found";
|
||||
mKeyphrasePackageMap = null;
|
||||
mKeyphrases = null;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
ApplicationInfo ai = null;
|
||||
List<String> parseErrors = new LinkedList<String>();
|
||||
mKeyphrasePackageMap = new HashMap<KeyphraseMetadata, String>();
|
||||
for (ResolveInfo ri : ris) {
|
||||
try {
|
||||
ai = pm.getApplicationInfo(
|
||||
ApplicationInfo ai = pm.getApplicationInfo(
|
||||
ri.activityInfo.packageName, PackageManager.GET_META_DATA);
|
||||
if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
|
||||
// The application isn't privileged (/system/priv-app).
|
||||
@@ -116,27 +128,45 @@ public class KeyphraseEnrollmentInfo {
|
||||
Slog.w(TAG, ai.packageName + " does not require MANAGE_VOICE_KEYPHRASES");
|
||||
continue;
|
||||
}
|
||||
mEnrollmentPackage = ai.packageName;
|
||||
found = true;
|
||||
break;
|
||||
|
||||
mKeyphrasePackageMap.put(
|
||||
getKeyphraseMetadataFromApplicationInfo(pm, ai, parseErrors),
|
||||
ai.packageName);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.w(TAG, "error parsing voice enrollment meta-data", e);
|
||||
String error = "error parsing voice enrollment meta-data for "
|
||||
+ ri.activityInfo.packageName;
|
||||
parseErrors.add(error + ": " + e);
|
||||
Slog.w(TAG, error, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (mKeyphrasePackageMap.isEmpty()) {
|
||||
String error = "No suitable enrollment application found";
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
mKeyphrases = null;
|
||||
mParseError = "No suitable enrollment application found";
|
||||
return;
|
||||
} else {
|
||||
mKeyphrases = mKeyphrasePackageMap.keySet().toArray(
|
||||
new KeyphraseMetadata[mKeyphrasePackageMap.size()]);
|
||||
}
|
||||
|
||||
if (!parseErrors.isEmpty()) {
|
||||
mParseError = TextUtils.join("\n", parseErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyphraseMetadata getKeyphraseMetadataFromApplicationInfo(PackageManager pm,
|
||||
ApplicationInfo ai, List<String> parseErrors) {
|
||||
XmlResourceParser parser = null;
|
||||
String packageName = ai.packageName;
|
||||
KeyphraseMetadata keyphraseMetadata = null;
|
||||
try {
|
||||
parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA);
|
||||
if (parser == null) {
|
||||
mParseError = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for "
|
||||
+ ai.packageName;
|
||||
return;
|
||||
String error = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for " + packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
Resources res = pm.getResourcesForApplication(ai);
|
||||
@@ -149,48 +179,55 @@ public class KeyphraseEnrollmentInfo {
|
||||
|
||||
String nodeName = parser.getName();
|
||||
if (!"voice-enrollment-application".equals(nodeName)) {
|
||||
mParseError = "Meta-data does not start with voice-enrollment-application tag";
|
||||
return;
|
||||
String error = "Meta-data does not start with voice-enrollment-application tag for "
|
||||
+ packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
TypedArray array = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.VoiceEnrollmentApplication);
|
||||
initializeKeyphrasesFromTypedArray(array);
|
||||
keyphraseMetadata = getKeyphraseFromTypedArray(array, packageName, parseErrors);
|
||||
array.recycle();
|
||||
} catch (XmlPullParserException e) {
|
||||
mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
|
||||
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
|
||||
return;
|
||||
String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
|
||||
parseErrors.add(error + ": " + e);
|
||||
Slog.w(TAG, error, e);
|
||||
} catch (IOException e) {
|
||||
mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
|
||||
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
|
||||
return;
|
||||
String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
|
||||
parseErrors.add(error + ": " + e);
|
||||
Slog.w(TAG, error, e);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
|
||||
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
|
||||
return;
|
||||
String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
|
||||
parseErrors.add(error + ": " + e);
|
||||
Slog.w(TAG, error, e);
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
return keyphraseMetadata;
|
||||
}
|
||||
|
||||
private void initializeKeyphrasesFromTypedArray(TypedArray array) {
|
||||
private KeyphraseMetadata getKeyphraseFromTypedArray(TypedArray array, String packageName,
|
||||
List<String> parseErrors) {
|
||||
// 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;
|
||||
String error = "No valid searchKeyphraseId specified in meta-data for " + packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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;
|
||||
String error = "No valid searchKeyphrase specified in meta-data for " + packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the supported locales.
|
||||
@@ -198,9 +235,11 @@ public class KeyphraseEnrollmentInfo {
|
||||
com.android.internal.R.styleable
|
||||
.VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
|
||||
if (searchKeyphraseSupportedLocales == null) {
|
||||
mParseError = "No valid searchKeyphraseSupportedLocales specified in meta-data";
|
||||
Slog.w(TAG, mParseError);
|
||||
return;
|
||||
String error = "No valid searchKeyphraseSupportedLocales specified in meta-data for "
|
||||
+ packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
ArraySet<Locale> locales = new ArraySet<>();
|
||||
// Try adding locales if the locale string is non-empty.
|
||||
@@ -214,9 +253,11 @@ public class KeyphraseEnrollmentInfo {
|
||||
// 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;
|
||||
String error = "Error reading searchKeyphraseSupportedLocales from meta-data for "
|
||||
+ packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,13 +265,13 @@ public class KeyphraseEnrollmentInfo {
|
||||
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;
|
||||
String error = "No valid searchKeyphraseRecognitionFlags specified in meta-data for "
|
||||
+ packageName;
|
||||
parseErrors.add(error);
|
||||
Slog.w(TAG, error);
|
||||
return null;
|
||||
}
|
||||
mKeyphrases = new KeyphraseMetadata[1];
|
||||
mKeyphrases[0] = new KeyphraseMetadata(searchKeyphraseId, searchKeyphrase, locales,
|
||||
recognitionModes);
|
||||
return new KeyphraseMetadata(searchKeyphraseId, searchKeyphrase, locales, recognitionModes);
|
||||
}
|
||||
|
||||
public String getParseError() {
|
||||
@@ -259,14 +300,15 @@ public class KeyphraseEnrollmentInfo {
|
||||
* given keyphrase/locale combination isn't possible.
|
||||
*/
|
||||
public Intent getManageKeyphraseIntent(int action, String keyphrase, Locale locale) {
|
||||
if (mEnrollmentPackage == null || mEnrollmentPackage.isEmpty()) {
|
||||
if (mKeyphrasePackageMap == null || mKeyphrasePackageMap.isEmpty()) {
|
||||
Slog.w(TAG, "No enrollment application exists");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getKeyphraseMetadata(keyphrase, locale) != null) {
|
||||
KeyphraseMetadata keyphraseMetadata = getKeyphraseMetadata(keyphrase, locale);
|
||||
if (keyphraseMetadata != null) {
|
||||
Intent intent = new Intent(ACTION_MANAGE_VOICE_KEYPHRASES)
|
||||
.setPackage(mEnrollmentPackage)
|
||||
.setPackage(mKeyphrasePackageMap.get(keyphraseMetadata))
|
||||
.putExtra(EXTRA_VOICE_KEYPHRASE_HINT_TEXT, keyphrase)
|
||||
.putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale.toLanguageTag())
|
||||
.putExtra(EXTRA_VOICE_KEYPHRASE_ACTION, action);
|
||||
@@ -298,14 +340,13 @@ public class KeyphraseEnrollmentInfo {
|
||||
return keyphraseMetadata;
|
||||
}
|
||||
}
|
||||
Slog.w(TAG, "Enrollment application doesn't support the given keyphrase/locale");
|
||||
Slog.w(TAG, "No Enrollment application supports the given keyphrase/locale");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeyphraseEnrollmentInfo [Keyphrases=" + Arrays.toString(mKeyphrases)
|
||||
+ ", EnrollmentPackage=" + mEnrollmentPackage + ", ParseError=" + mParseError
|
||||
+ "]";
|
||||
return "KeyphraseEnrollmentInfo [Keyphrases=" + mKeyphrasePackageMap.toString()
|
||||
+ ", ParseError=" + mParseError + "]";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user