Merge "Support multiple Enrollment APKs" into nyc-dev

am: 9e928c1

* commit '9e928c1f715c53cc9cd6a85b3dcdcdc68cabc9c6':
  Support multiple Enrollment APKs

Change-Id: I66fbc18f3291a4178fdfb613c6a4e905edf5715e
This commit is contained in:
Chris Thornton
2016-04-11 16:45:59 +00:00
committed by android-build-merger

View File

@@ -35,9 +35,11 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
/** /**
* Enrollment information about the different available keyphrases. * Enrollment information about the different available keyphrases.
@@ -82,8 +84,16 @@ public class KeyphraseEnrollmentInfo {
public static final String EXTRA_VOICE_KEYPHRASE_LOCALE = public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
"com.android.intent.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; private String mParseError;
public KeyphraseEnrollmentInfo(PackageManager pm) { public KeyphraseEnrollmentInfo(PackageManager pm) {
@@ -94,15 +104,17 @@ public class KeyphraseEnrollmentInfo {
new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY); new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
if (ris == null || ris.isEmpty()) { if (ris == null || ris.isEmpty()) {
// No application capable of enrolling for voice keyphrases is present. // 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; return;
} }
boolean found = false; List<String> parseErrors = new LinkedList<String>();
ApplicationInfo ai = null; mKeyphrasePackageMap = new HashMap<KeyphraseMetadata, String>();
for (ResolveInfo ri : ris) { for (ResolveInfo ri : ris) {
try { try {
ai = pm.getApplicationInfo( ApplicationInfo ai = pm.getApplicationInfo(
ri.activityInfo.packageName, PackageManager.GET_META_DATA); ri.activityInfo.packageName, PackageManager.GET_META_DATA);
if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) { if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
// The application isn't privileged (/system/priv-app). // 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"); Slog.w(TAG, ai.packageName + " does not require MANAGE_VOICE_KEYPHRASES");
continue; continue;
} }
mEnrollmentPackage = ai.packageName;
found = true; mKeyphrasePackageMap.put(
break; getKeyphraseMetadataFromApplicationInfo(pm, ai, parseErrors),
ai.packageName);
} catch (PackageManager.NameNotFoundException e) { } 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; mKeyphrases = null;
mParseError = "No suitable enrollment application found"; } else {
return; 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; XmlResourceParser parser = null;
String packageName = ai.packageName;
KeyphraseMetadata keyphraseMetadata = null;
try { try {
parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA); parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA);
if (parser == null) { if (parser == null) {
mParseError = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for " String error = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for " + packageName;
+ ai.packageName; parseErrors.add(error);
return; Slog.w(TAG, error);
return null;
} }
Resources res = pm.getResourcesForApplication(ai); Resources res = pm.getResourcesForApplication(ai);
@@ -149,48 +179,55 @@ public class KeyphraseEnrollmentInfo {
String nodeName = parser.getName(); String nodeName = parser.getName();
if (!"voice-enrollment-application".equals(nodeName)) { if (!"voice-enrollment-application".equals(nodeName)) {
mParseError = "Meta-data does not start with voice-enrollment-application tag"; String error = "Meta-data does not start with voice-enrollment-application tag for "
return; + packageName;
parseErrors.add(error);
Slog.w(TAG, error);
return null;
} }
TypedArray array = res.obtainAttributes(attrs, TypedArray array = res.obtainAttributes(attrs,
com.android.internal.R.styleable.VoiceEnrollmentApplication); com.android.internal.R.styleable.VoiceEnrollmentApplication);
initializeKeyphrasesFromTypedArray(array); keyphraseMetadata = getKeyphraseFromTypedArray(array, packageName, parseErrors);
array.recycle(); array.recycle();
} catch (XmlPullParserException e) { } catch (XmlPullParserException e) {
mParseError = "Error parsing keyphrase enrollment meta-data: " + e; String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e); parseErrors.add(error + ": " + e);
return; Slog.w(TAG, error, e);
} catch (IOException e) { } catch (IOException e) {
mParseError = "Error parsing keyphrase enrollment meta-data: " + e; String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e); parseErrors.add(error + ": " + e);
return; Slog.w(TAG, error, e);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
mParseError = "Error parsing keyphrase enrollment meta-data: " + e; String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e); parseErrors.add(error + ": " + e);
return; Slog.w(TAG, error, e);
} finally { } finally {
if (parser != null) parser.close(); 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. // Get the keyphrase ID.
int searchKeyphraseId = array.getInt( int searchKeyphraseId = array.getInt(
com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId, -1); com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId, -1);
if (searchKeyphraseId <= 0) { if (searchKeyphraseId <= 0) {
mParseError = "No valid searchKeyphraseId specified in meta-data"; String error = "No valid searchKeyphraseId specified in meta-data for " + packageName;
Slog.w(TAG, mParseError); parseErrors.add(error);
return; Slog.w(TAG, error);
return null;
} }
// Get the keyphrase text. // Get the keyphrase text.
String searchKeyphrase = array.getString( String searchKeyphrase = array.getString(
com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphrase); com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphrase);
if (searchKeyphrase == null) { if (searchKeyphrase == null) {
mParseError = "No valid searchKeyphrase specified in meta-data"; String error = "No valid searchKeyphrase specified in meta-data for " + packageName;
Slog.w(TAG, mParseError); parseErrors.add(error);
return; Slog.w(TAG, error);
return null;
} }
// Get the supported locales. // Get the supported locales.
@@ -198,9 +235,11 @@ public class KeyphraseEnrollmentInfo {
com.android.internal.R.styleable com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseSupportedLocales); .VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
if (searchKeyphraseSupportedLocales == null) { if (searchKeyphraseSupportedLocales == null) {
mParseError = "No valid searchKeyphraseSupportedLocales specified in meta-data"; String error = "No valid searchKeyphraseSupportedLocales specified in meta-data for "
Slog.w(TAG, mParseError); + packageName;
return; parseErrors.add(error);
Slog.w(TAG, error);
return null;
} }
ArraySet<Locale> locales = new ArraySet<>(); ArraySet<Locale> locales = new ArraySet<>();
// Try adding locales if the locale string is non-empty. // 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 // 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 // to be affected by a malformed metadata because invalid locales were specified
// by the system application. // by the system application.
mParseError = "Error reading searchKeyphraseSupportedLocales from meta-data"; String error = "Error reading searchKeyphraseSupportedLocales from meta-data for "
Slog.w(TAG, mParseError, ex); + packageName;
return; 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 int recognitionModes = array.getInt(com.android.internal.R.styleable
.VoiceEnrollmentApplication_searchKeyphraseRecognitionFlags, -1); .VoiceEnrollmentApplication_searchKeyphraseRecognitionFlags, -1);
if (recognitionModes < 0) { if (recognitionModes < 0) {
mParseError = "No valid searchKeyphraseRecognitionFlags specified in meta-data"; String error = "No valid searchKeyphraseRecognitionFlags specified in meta-data for "
Slog.w(TAG, mParseError); + packageName;
return; parseErrors.add(error);
Slog.w(TAG, error);
return null;
} }
mKeyphrases = new KeyphraseMetadata[1]; return new KeyphraseMetadata(searchKeyphraseId, searchKeyphrase, locales, recognitionModes);
mKeyphrases[0] = new KeyphraseMetadata(searchKeyphraseId, searchKeyphrase, locales,
recognitionModes);
} }
public String getParseError() { public String getParseError() {
@@ -259,14 +300,15 @@ public class KeyphraseEnrollmentInfo {
* given keyphrase/locale combination isn't possible. * given keyphrase/locale combination isn't possible.
*/ */
public Intent getManageKeyphraseIntent(int action, String keyphrase, Locale locale) { 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"); Slog.w(TAG, "No enrollment application exists");
return null; return null;
} }
if (getKeyphraseMetadata(keyphrase, locale) != null) { KeyphraseMetadata keyphraseMetadata = getKeyphraseMetadata(keyphrase, locale);
if (keyphraseMetadata != null) {
Intent intent = new Intent(ACTION_MANAGE_VOICE_KEYPHRASES) 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_HINT_TEXT, keyphrase)
.putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale.toLanguageTag()) .putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale.toLanguageTag())
.putExtra(EXTRA_VOICE_KEYPHRASE_ACTION, action); .putExtra(EXTRA_VOICE_KEYPHRASE_ACTION, action);
@@ -298,14 +340,13 @@ public class KeyphraseEnrollmentInfo {
return keyphraseMetadata; 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; return null;
} }
@Override @Override
public String toString() { public String toString() {
return "KeyphraseEnrollmentInfo [Keyphrases=" + Arrays.toString(mKeyphrases) return "KeyphraseEnrollmentInfo [Keyphrases=" + mKeyphrasePackageMap.toString()
+ ", EnrollmentPackage=" + mEnrollmentPackage + ", ParseError=" + mParseError + ", ParseError=" + mParseError + "]";
+ "]";
} }
} }