blob: 4011038e21deb46c01a55e1a2e50c49c51c6d81c [file] [log] [blame]
Mike LeBeau92c33522010-01-25 18:18:45 -05001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings;
18
Mike LeBeau766a19b2010-02-11 22:57:12 -080019import org.xmlpull.v1.XmlPullParser;
20import org.xmlpull.v1.XmlPullParserException;
21
22import android.content.ComponentName;
Mike LeBeau92c33522010-01-25 18:18:45 -050023import android.content.Intent;
24import android.content.pm.PackageManager;
Mike LeBeau766a19b2010-02-11 22:57:12 -080025import android.content.pm.ResolveInfo;
26import android.content.pm.ServiceInfo;
27import android.content.res.TypedArray;
28import android.content.res.XmlResourceParser;
Mike LeBeau92c33522010-01-25 18:18:45 -050029import android.os.Bundle;
Mike LeBeau766a19b2010-02-11 22:57:12 -080030import android.preference.ListPreference;
Mike LeBeau92c33522010-01-25 18:18:45 -050031import android.preference.Preference;
32import android.preference.PreferenceActivity;
Mike LeBeau766a19b2010-02-11 22:57:12 -080033import android.preference.PreferenceCategory;
Mike LeBeau92c33522010-01-25 18:18:45 -050034import android.preference.PreferenceGroup;
Mike LeBeau766a19b2010-02-11 22:57:12 -080035import android.preference.PreferenceScreen;
36import android.preference.Preference.OnPreferenceChangeListener;
37import android.provider.Settings;
38import android.speech.RecognitionService;
39import android.util.AttributeSet;
40import android.util.Log;
41import android.util.Xml;
Mike LeBeau92c33522010-01-25 18:18:45 -050042
Mike LeBeau766a19b2010-02-11 22:57:12 -080043import java.io.IOException;
44import java.util.HashMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050045import java.util.List;
46
47/**
48 * Settings screen for voice input/output.
49 */
Mike LeBeau766a19b2010-02-11 22:57:12 -080050public class VoiceInputOutputSettings extends PreferenceActivity
51 implements OnPreferenceChangeListener {
52
53 private static final String TAG = "VoiceInputOutputSettings";
Mike LeBeau92c33522010-01-25 18:18:45 -050054
55 private static final String KEY_PARENT = "parent";
Mike LeBeau766a19b2010-02-11 22:57:12 -080056 private static final String KEY_VOICE_INPUT_CATEGORY = "voice_input_category";
57 private static final String KEY_RECOGNIZER = "recognizer";
58 private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings";
59
60 private PreferenceGroup mParent;
61 private PreferenceCategory mVoiceInputCategory;
62 private ListPreference mRecognizerPref;
63 private PreferenceScreen mSettingsPref;
64
65 private HashMap<String, ResolveInfo> mAvailableRecognizersMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050066
67 @Override
68 protected void onCreate(Bundle icicle) {
69 super.onCreate(icicle);
70
71 addPreferencesFromResource(R.xml.voice_input_output_settings);
Mike LeBeau766a19b2010-02-11 22:57:12 -080072
73 mParent = (PreferenceGroup) findPreference(KEY_PARENT);
74 mVoiceInputCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_INPUT_CATEGORY);
75 mRecognizerPref = (ListPreference) mParent.findPreference(KEY_RECOGNIZER);
76 mRecognizerPref.setOnPreferenceChangeListener(this);
77 mSettingsPref = (PreferenceScreen) mParent.findPreference(KEY_RECOGNIZER_SETTINGS);
Mike LeBeau92c33522010-01-25 18:18:45 -050078
Mike LeBeau766a19b2010-02-11 22:57:12 -080079 mAvailableRecognizersMap = new HashMap<String, ResolveInfo>();
80
81 populateOrRemoveRecognizerPreference();
Mike LeBeau92c33522010-01-25 18:18:45 -050082 }
Mike LeBeau766a19b2010-02-11 22:57:12 -080083
84 private void populateOrRemoveRecognizerPreference() {
85 List<ResolveInfo> availableRecognitionServices = getPackageManager().queryIntentServices(
86 new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
87 int numAvailable = availableRecognitionServices.size();
Mike LeBeau92c33522010-01-25 18:18:45 -050088
Mike LeBeau766a19b2010-02-11 22:57:12 -080089 if (numAvailable == 0) {
90 // No recognizer available - remove all related preferences.
91 removePreference(mVoiceInputCategory);
92 removePreference(mRecognizerPref);
93 removePreference(mSettingsPref);
94 } else if (numAvailable == 1) {
Mike LeBeau4c2ffc52010-02-12 14:47:48 -080095 // Only one recognizer available, so don't show the list of choices, but do
96 // set up the link to settings for the available recognizer.
Mike LeBeau766a19b2010-02-11 22:57:12 -080097 removePreference(mRecognizerPref);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -080098
99 // But first set up the available recognizers map with just the one recognizer.
100 ResolveInfo resolveInfo = availableRecognitionServices.get(0);
101 String recognizerComponent =
102 new ComponentName(resolveInfo.serviceInfo.packageName,
103 resolveInfo.serviceInfo.name).flattenToString();
104 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
105
106 String currentSetting = Settings.Secure.getString(
107 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
108 updateSettingsLink(currentSetting);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800109 } else {
110 // Multiple recognizers available, so show the full list of choices.
111 populateRecognizerPreference(availableRecognitionServices);
Mike LeBeau92c33522010-01-25 18:18:45 -0500112 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800113 }
114
115 private void removePreference(Preference pref) {
116 if (pref != null) {
117 mParent.removePreference(pref);
118 }
119 }
120
121 private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
122 int size = recognizers.size();
123 CharSequence[] entries = new CharSequence[size];
124 CharSequence[] values = new CharSequence[size];
125
126 // Get the current value from the secure setting.
127 String currentSetting = Settings.Secure.getString(
128 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
129
130 // Iterate through all the available recognizers and load up their info to show
131 // in the preference. Also build up a map of recognizer component names to their
132 // ResolveInfos - we'll need that a little later.
133 for (int i = 0; i < size; i++) {
134 ResolveInfo resolveInfo = recognizers.get(i);
135 String recognizerComponent =
136 new ComponentName(resolveInfo.serviceInfo.packageName,
137 resolveInfo.serviceInfo.name).flattenToString();
138
139 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Mike LeBeau92c33522010-01-25 18:18:45 -0500140
Mike LeBeau766a19b2010-02-11 22:57:12 -0800141 entries[i] = resolveInfo.loadLabel(getPackageManager());
142 values[i] = recognizerComponent;
143 }
144
145 mRecognizerPref.setEntries(entries);
146 mRecognizerPref.setEntryValues(values);
147
148 mRecognizerPref.setDefaultValue(currentSetting);
149 mRecognizerPref.setValue(currentSetting);
150
151 updateSettingsLink(currentSetting);
152 }
153
154 private void updateSettingsLink(String currentSetting) {
155 ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
156 ServiceInfo si = currentRecognizer.serviceInfo;
157 XmlResourceParser parser = null;
158 String settingsActivity = null;
159 try {
160 parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA);
161 if (parser == null) {
162 throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
163 " meta-data for " + si.packageName);
Mike LeBeau92c33522010-01-25 18:18:45 -0500164 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800165
166 AttributeSet attrs = Xml.asAttributeSet(parser);
167
168 int type;
169 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
170 && type != XmlPullParser.START_TAG) {
171 }
172
173 String nodeName = parser.getName();
174 if (!"recognition-service".equals(nodeName)) {
175 throw new XmlPullParserException(
176 "Meta-data does not start with recognition-service tag");
177 }
178
179 TypedArray array = getResources().obtainAttributes(attrs,
180 com.android.internal.R.styleable.RecognitionService);
181 settingsActivity = array.getString(
182 com.android.internal.R.styleable.RecognitionService_settingsActivity);
183 array.recycle();
184 } catch (XmlPullParserException e) {
185 Log.e(TAG, "error parsing recognition service meta-data", e);
186 } catch (IOException e) {
187 Log.e(TAG, "error parsing recognition service meta-data", e);
188 } finally {
189 if (parser != null) parser.close();
Mike LeBeau92c33522010-01-25 18:18:45 -0500190 }
191
Mike LeBeau766a19b2010-02-11 22:57:12 -0800192 if (settingsActivity == null) {
193 // No settings preference available - hide the preference.
194 Log.w(TAG, "no recognizer settings available for " + si.packageName);
195 mSettingsPref.setIntent(null);
196 mParent.removePreference(mSettingsPref);
197 } else {
198 Intent i = new Intent(Intent.ACTION_MAIN);
199 i.setComponent(new ComponentName(si.packageName, settingsActivity));
200 mSettingsPref.setIntent(i);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800201 mRecognizerPref.setSummary(currentRecognizer.loadLabel(getPackageManager()));
Mike LeBeau766a19b2010-02-11 22:57:12 -0800202 }
203 }
204
205 public boolean onPreferenceChange(Preference preference, Object newValue) {
206 if (preference == mRecognizerPref) {
207 String setting = (String) newValue;
208
209 // Put the new value back into secure settings.
210 Settings.Secure.putString(
211 getContentResolver(),
212 Settings.Secure.VOICE_RECOGNITION_SERVICE,
213 setting);
214
215 // Update the settings item so it points to the right settings.
216 updateSettingsLink(setting);
217 }
218 return true;
Mike LeBeau92c33522010-01-25 18:18:45 -0500219 }
220}