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.
This commit is contained in:
@@ -2073,6 +2073,14 @@ found in the list of installed applications.</string>
|
||||
<string name="voice_search_settings_title">Voice search</string>
|
||||
<!-- Title of keyboard settings list item within voice input/output settings -->
|
||||
<string name="keyboard_settings_title">Android keyboard</string>
|
||||
<!-- Title for the 'voice input' category of voice input/output settings -->
|
||||
<string name="voice_input_category">Voice input</string>
|
||||
<!-- Title for the 'voice output' category of voice input/output settings -->
|
||||
<string name="voice_output_category">Voice output</string>
|
||||
<!-- Title for the voice recognizer setting in voice input/output settings -->
|
||||
<string name="recognizer_title">Voice recognizer</string>
|
||||
<!-- Title for the link to settings for the chosen voice recognizer in voice input/output settings -->
|
||||
<string name="recognizer_settings_title">Voice recognizer settings</string>
|
||||
|
||||
<!-- Text-To-Speech (TTS) settings --><skip />
|
||||
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings related to the text-to-speech functionality -->
|
||||
|
@@ -18,18 +18,21 @@
|
||||
android:title="@string/voice_input_output_settings_title"
|
||||
android:key="parent">
|
||||
|
||||
<PreferenceScreen android:key="voice_search_settings"
|
||||
android:title="@string/voice_search_settings_title">
|
||||
<intent android:action="android.speech.action.VOICE_SEARCH_SETTINGS"/>
|
||||
</PreferenceScreen>
|
||||
<PreferenceCategory android:key="voice_input_category"
|
||||
android:title="@string/voice_input_category" />
|
||||
|
||||
<!-- TODO: Link to a specific voice settings activity within LatinIME when it exists. -->
|
||||
<PreferenceScreen android:key="keyboard_settings"
|
||||
android:title="@string/keyboard_settings_title">
|
||||
<intent android:action="android.intent.action.MAIN"
|
||||
android:targetPackage="com.android.inputmethod.latin"
|
||||
android:targetClass="com.android.inputmethod.latin.LatinIMESettings" />
|
||||
</PreferenceScreen>
|
||||
<!-- entries, entryValues, and defaultValue will be populated programmatically. -->
|
||||
<ListPreference
|
||||
android:key="recognizer"
|
||||
android:title="@string/recognizer_title"
|
||||
android:dialogTitle="@string/recognizer_title" />
|
||||
|
||||
<!-- An intent for this preference will be populated programmatically. -->
|
||||
<PreferenceScreen android:key="recognizer_settings"
|
||||
android:title="@string/recognizer_settings_title" />
|
||||
|
||||
<PreferenceCategory android:key="voice_output_category"
|
||||
android:title="@string/voice_output_category" />
|
||||
|
||||
<PreferenceScreen android:key="tts_settings"
|
||||
android:title="@string/tts_settings_title">
|
||||
|
@@ -16,24 +16,53 @@
|
||||
|
||||
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) {
|
||||
@@ -41,30 +70,138 @@ public class VoiceInputOutputSettings extends PreferenceActivity {
|
||||
|
||||
addPreferencesFromResource(R.xml.voice_input_output_settings);
|
||||
|
||||
removePreferenceIfNecessary(KEY_VOICE_SEARCH_SETTINGS);
|
||||
removePreferenceIfNecessary(KEY_KEYBOARD_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>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Intent intent = preference.getIntent();
|
||||
if (intent != null) {
|
||||
PackageManager pm = getPackageManager();
|
||||
if (!pm.queryIntentActivities(intent, 0).isEmpty()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Did not find a matching activity, so remove the preference.
|
||||
parent.removePreference(preference);
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user