diff options
author | Mike LeBeau <mlebeau@android.com> | 2010-02-11 22:57:12 -0800 |
---|---|---|
committer | Mike LeBeau <mlebeau@android.com> | 2010-02-12 13:45:04 -0800 |
commit | 766a19b27883c478ec263eb93dc5cc820b00b7af (patch) | |
tree | 855ffadf2df322090c2c041910da6ff6867cacbc /src/com/android/settings/VoiceInputOutputSettings.java | |
parent | eadeebd1df04405e71d5a7b4dfba08d6d6afcc27 (diff) | |
download | packages_apps_Settings-766a19b27883c478ec263eb93dc5cc820b00b7af.zip packages_apps_Settings-766a19b27883c478ec263eb93dc5cc820b00b7af.tar.gz packages_apps_Settings-766a19b27883c478ec263eb93dc5cc820b00b7af.tar.bz2 |
Dynamically populate a list of available recognition services in voice settings,
only showing the option to choose if there is more than one to choose from. Use
the new settingsActivity meta-data to target the appropriate settings activity
for the chosen recognizer.
Diffstat (limited to 'src/com/android/settings/VoiceInputOutputSettings.java')
-rw-r--r-- | src/com/android/settings/VoiceInputOutputSettings.java | 181 |
1 files changed, 159 insertions, 22 deletions
diff --git a/src/com/android/settings/VoiceInputOutputSettings.java b/src/com/android/settings/VoiceInputOutputSettings.java index 7586bd0..62c909f 100644 --- a/src/com/android/settings/VoiceInputOutputSettings.java +++ b/src/com/android/settings/VoiceInputOutputSettings.java @@ -16,55 +16,192 @@ package com.android.settings; -import android.content.Context; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.os.Bundle; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.preference.Preference.OnPreferenceChangeListener; +import android.provider.Settings; +import android.speech.RecognitionService; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; +import java.io.IOException; +import java.util.HashMap; import java.util.List; /** * Settings screen for voice input/output. */ -public class VoiceInputOutputSettings extends PreferenceActivity { +public class VoiceInputOutputSettings extends PreferenceActivity + implements OnPreferenceChangeListener { + + private static final String TAG = "VoiceInputOutputSettings"; private static final String KEY_PARENT = "parent"; - private static final String KEY_VOICE_SEARCH_SETTINGS = "voice_search_settings"; - private static final String KEY_KEYBOARD_SETTINGS = "keyboard_settings"; + private static final String KEY_VOICE_INPUT_CATEGORY = "voice_input_category"; + private static final String KEY_RECOGNIZER = "recognizer"; + private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings"; + + private PreferenceGroup mParent; + private PreferenceCategory mVoiceInputCategory; + private ListPreference mRecognizerPref; + private PreferenceScreen mSettingsPref; + + private HashMap<String, ResolveInfo> mAvailableRecognizersMap; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.voice_input_output_settings); + + mParent = (PreferenceGroup) findPreference(KEY_PARENT); + mVoiceInputCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_INPUT_CATEGORY); + mRecognizerPref = (ListPreference) mParent.findPreference(KEY_RECOGNIZER); + mRecognizerPref.setOnPreferenceChangeListener(this); + mSettingsPref = (PreferenceScreen) mParent.findPreference(KEY_RECOGNIZER_SETTINGS); + + mAvailableRecognizersMap = new HashMap<String, ResolveInfo>(); - removePreferenceIfNecessary(KEY_VOICE_SEARCH_SETTINGS); - removePreferenceIfNecessary(KEY_KEYBOARD_SETTINGS); + populateOrRemoveRecognizerPreference(); } - - /** - * Removes a preference if there is no activity to handle its intent. - */ - private void removePreferenceIfNecessary(String preferenceKey) { - PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT); + + private void populateOrRemoveRecognizerPreference() { + List<ResolveInfo> availableRecognitionServices = getPackageManager().queryIntentServices( + new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA); + int numAvailable = availableRecognitionServices.size(); - Preference preference = parent.findPreference(preferenceKey); - if (preference == null) { - return; + if (numAvailable == 0) { + // No recognizer available - remove all related preferences. + removePreference(mVoiceInputCategory); + removePreference(mRecognizerPref); + removePreference(mSettingsPref); + } else if (numAvailable == 1) { + // Only one recognizer available, so don't show the list of choices. + removePreference(mRecognizerPref); + } else { + // Multiple recognizers available, so show the full list of choices. + populateRecognizerPreference(availableRecognitionServices); + } + } + + private void removePreference(Preference pref) { + if (pref != null) { + mParent.removePreference(pref); } + } + + private void populateRecognizerPreference(List<ResolveInfo> recognizers) { + int size = recognizers.size(); + CharSequence[] entries = new CharSequence[size]; + CharSequence[] values = new CharSequence[size]; + + // Get the current value from the secure setting. + String currentSetting = Settings.Secure.getString( + getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE); + + // Iterate through all the available recognizers and load up their info to show + // in the preference. Also build up a map of recognizer component names to their + // ResolveInfos - we'll need that a little later. + for (int i = 0; i < size; i++) { + ResolveInfo resolveInfo = recognizers.get(i); + String recognizerComponent = + new ComponentName(resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name).flattenToString(); + + mAvailableRecognizersMap.put(recognizerComponent, resolveInfo); - Intent intent = preference.getIntent(); - if (intent != null) { - PackageManager pm = getPackageManager(); - if (!pm.queryIntentActivities(intent, 0).isEmpty()) { - return; + entries[i] = resolveInfo.loadLabel(getPackageManager()); + values[i] = recognizerComponent; + } + + mRecognizerPref.setEntries(entries); + mRecognizerPref.setEntryValues(values); + + mRecognizerPref.setDefaultValue(currentSetting); + mRecognizerPref.setValue(currentSetting); + + updateSettingsLink(currentSetting); + } + + private void updateSettingsLink(String currentSetting) { + ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting); + ServiceInfo si = currentRecognizer.serviceInfo; + XmlResourceParser parser = null; + String settingsActivity = null; + try { + parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA); + if (parser == null) { + throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA + + " meta-data for " + si.packageName); } + + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!"recognition-service".equals(nodeName)) { + throw new XmlPullParserException( + "Meta-data does not start with recognition-service tag"); + } + + TypedArray array = getResources().obtainAttributes(attrs, + com.android.internal.R.styleable.RecognitionService); + settingsActivity = array.getString( + com.android.internal.R.styleable.RecognitionService_settingsActivity); + array.recycle(); + } catch (XmlPullParserException e) { + Log.e(TAG, "error parsing recognition service meta-data", e); + } catch (IOException e) { + Log.e(TAG, "error parsing recognition service meta-data", e); + } finally { + if (parser != null) parser.close(); } - // Did not find a matching activity, so remove the preference. - parent.removePreference(preference); + if (settingsActivity == null) { + // No settings preference available - hide the preference. + Log.w(TAG, "no recognizer settings available for " + si.packageName); + mSettingsPref.setIntent(null); + mParent.removePreference(mSettingsPref); + } else { + Intent i = new Intent(Intent.ACTION_MAIN); + i.setComponent(new ComponentName(si.packageName, settingsActivity)); + mSettingsPref.setIntent(i); + } + } + + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == mRecognizerPref) { + String setting = (String) newValue; + + // Put the new value back into secure settings. + Settings.Secure.putString( + getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + setting); + + // Update the settings item so it points to the right settings. + updateSettingsLink(setting); + } + return true; } } |