Loading core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java +96 −55 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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) { Loading @@ -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). Loading @@ -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); Loading @@ -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. Loading @@ -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. Loading @@ -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; } } Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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 + "]"; } } Loading
core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java +96 −55 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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) { Loading @@ -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). Loading @@ -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); Loading @@ -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. Loading @@ -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. Loading @@ -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; } } Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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 + "]"; } }