blob: 81e624f57529be9672aebfe24fb6872076b339eb [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 android.content.ComponentName;
Mike LeBeau92c33522010-01-25 18:18:45 -050020import android.content.Intent;
21import android.content.pm.PackageManager;
Mike LeBeau766a19b2010-02-11 22:57:12 -080022import android.content.pm.ResolveInfo;
23import android.content.pm.ServiceInfo;
Dianne Hackborn0382a492010-03-04 11:44:09 -080024import android.content.pm.PackageManager.NameNotFoundException;
25import android.content.res.Resources;
Mike LeBeau766a19b2010-02-11 22:57:12 -080026import android.content.res.TypedArray;
27import android.content.res.XmlResourceParser;
Mike LeBeau766a19b2010-02-11 22:57:12 -080028import android.preference.ListPreference;
Mike LeBeau92c33522010-01-25 18:18:45 -050029import android.preference.Preference;
Mike LeBeau766a19b2010-02-11 22:57:12 -080030import android.preference.PreferenceCategory;
Mike LeBeau92c33522010-01-25 18:18:45 -050031import android.preference.PreferenceGroup;
Mike LeBeau766a19b2010-02-11 22:57:12 -080032import android.preference.PreferenceScreen;
33import android.preference.Preference.OnPreferenceChangeListener;
34import android.provider.Settings;
35import android.speech.RecognitionService;
Narayan Kamathe247cb82011-10-05 12:26:31 +010036import android.speech.tts.TtsEngines;
Mike LeBeau766a19b2010-02-11 22:57:12 -080037import android.util.AttributeSet;
38import android.util.Log;
39import android.util.Xml;
Mike LeBeau92c33522010-01-25 18:18:45 -050040
Mike LeBeau766a19b2010-02-11 22:57:12 -080041import java.io.IOException;
42import java.util.HashMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050043import java.util.List;
44
Amith Yamasanib44161f2010-12-10 13:17:34 -080045import org.xmlpull.v1.XmlPullParser;
46import org.xmlpull.v1.XmlPullParserException;
47
Mike LeBeau92c33522010-01-25 18:18:45 -050048/**
49 * Settings screen for voice input/output.
50 */
Amith Yamasanib44161f2010-12-10 13:17:34 -080051public class VoiceInputOutputSettings implements OnPreferenceChangeListener {
52
Mike LeBeau766a19b2010-02-11 22:57:12 -080053 private static final String TAG = "VoiceInputOutputSettings";
Amith Yamasanib44161f2010-12-10 13:17:34 -080054
Jean Chalard8ba5c422011-08-31 21:40:43 +090055 private static final String KEY_VOICE_CATEGORY = "voice_category";
Mike LeBeau766a19b2010-02-11 22:57:12 -080056 private static final String KEY_RECOGNIZER = "recognizer";
57 private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings";
Narayan Kamathe247cb82011-10-05 12:26:31 +010058 private static final String KEY_TTS_SETTINGS = "tts_settings";
59
Mike LeBeau766a19b2010-02-11 22:57:12 -080060 private PreferenceGroup mParent;
Jean Chalard8ba5c422011-08-31 21:40:43 +090061 private PreferenceCategory mVoiceCategory;
Mike LeBeau766a19b2010-02-11 22:57:12 -080062 private ListPreference mRecognizerPref;
Narayan Kamathe247cb82011-10-05 12:26:31 +010063 private Preference mRecognizerSettingsPref;
64 private Preference mTtsSettingsPref;
Mike LeBeau766a19b2010-02-11 22:57:12 -080065 private PreferenceScreen mSettingsPref;
Narayan Kamathe247cb82011-10-05 12:26:31 +010066 private final SettingsPreferenceFragment mFragment;
67 private final TtsEngines mTtsEngines;
Amith Yamasanib44161f2010-12-10 13:17:34 -080068
Mike LeBeau766a19b2010-02-11 22:57:12 -080069 private HashMap<String, ResolveInfo> mAvailableRecognizersMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050070
Amith Yamasanib44161f2010-12-10 13:17:34 -080071 public VoiceInputOutputSettings(SettingsPreferenceFragment fragment) {
72 mFragment = fragment;
Narayan Kamathe247cb82011-10-05 12:26:31 +010073 mTtsEngines = new TtsEngines(fragment.getPreferenceScreen().getContext());
Amith Yamasanib44161f2010-12-10 13:17:34 -080074 }
Mike LeBeau766a19b2010-02-11 22:57:12 -080075
Amith Yamasanib44161f2010-12-10 13:17:34 -080076 public void onCreate() {
77
Narayan Kamathe247cb82011-10-05 12:26:31 +010078 mParent = mFragment.getPreferenceScreen();
Jean Chalard8ba5c422011-08-31 21:40:43 +090079 mVoiceCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_CATEGORY);
80 mRecognizerPref = (ListPreference) mVoiceCategory.findPreference(KEY_RECOGNIZER);
Narayan Kamathe247cb82011-10-05 12:26:31 +010081 mRecognizerSettingsPref = mVoiceCategory.findPreference(KEY_RECOGNIZER_SETTINGS);
82 mTtsSettingsPref = mVoiceCategory.findPreference(KEY_TTS_SETTINGS);
Mike LeBeau766a19b2010-02-11 22:57:12 -080083 mRecognizerPref.setOnPreferenceChangeListener(this);
Amith Yamasanib44161f2010-12-10 13:17:34 -080084 mSettingsPref = (PreferenceScreen)
Jean Chalard8ba5c422011-08-31 21:40:43 +090085 mVoiceCategory.findPreference(KEY_RECOGNIZER_SETTINGS);
Amith Yamasanib44161f2010-12-10 13:17:34 -080086
Mike LeBeau766a19b2010-02-11 22:57:12 -080087 mAvailableRecognizersMap = new HashMap<String, ResolveInfo>();
Amith Yamasanib44161f2010-12-10 13:17:34 -080088
Narayan Kamathe247cb82011-10-05 12:26:31 +010089 populateOrRemovePreferences();
Mike LeBeau92c33522010-01-25 18:18:45 -050090 }
Amith Yamasanib44161f2010-12-10 13:17:34 -080091
Narayan Kamathe247cb82011-10-05 12:26:31 +010092 private void populateOrRemovePreferences() {
93 boolean hasRecognizerPrefs = populateOrRemoveRecognizerPrefs();
94 boolean hasTtsPrefs = populateOrRemoveTtsPrefs();
95 if (!hasRecognizerPrefs && !hasTtsPrefs) {
96 // There were no TTS settings and no recognizer settings,
97 // so it should be safe to hide the preference category
98 // entirely.
99 mFragment.getPreferenceScreen().removePreference(mVoiceCategory);
100 }
101 }
102
103 private boolean populateOrRemoveRecognizerPrefs() {
Amith Yamasanib44161f2010-12-10 13:17:34 -0800104 List<ResolveInfo> availableRecognitionServices =
105 mFragment.getPackageManager().queryIntentServices(
Narayan Kamathe247cb82011-10-05 12:26:31 +0100106 new Intent(RecognitionService.SERVICE_INTERFACE),
107 PackageManager.GET_META_DATA);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800108 int numAvailable = availableRecognitionServices.size();
Narayan Kamathe247cb82011-10-05 12:26:31 +0100109
Mike LeBeau766a19b2010-02-11 22:57:12 -0800110 if (numAvailable == 0) {
Narayan Kamathe247cb82011-10-05 12:26:31 +0100111 mVoiceCategory.removePreference(mRecognizerPref);
112 mVoiceCategory.removePreference(mRecognizerSettingsPref);
113 return false;
114 }
115
116 if (numAvailable == 1) {
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800117 // Only one recognizer available, so don't show the list of choices, but do
118 // set up the link to settings for the available recognizer.
Jean Chalard8ba5c422011-08-31 21:40:43 +0900119 mVoiceCategory.removePreference(mRecognizerPref);
Amith Yamasanib44161f2010-12-10 13:17:34 -0800120
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800121 // But first set up the available recognizers map with just the one recognizer.
122 ResolveInfo resolveInfo = availableRecognitionServices.get(0);
123 String recognizerComponent =
Narayan Kamathe247cb82011-10-05 12:26:31 +0100124 new ComponentName(resolveInfo.serviceInfo.packageName,
125 resolveInfo.serviceInfo.name).flattenToShortString();
126
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800127 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Narayan Kamathe247cb82011-10-05 12:26:31 +0100128
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800129 String currentSetting = Settings.Secure.getString(
Amith Yamasanib44161f2010-12-10 13:17:34 -0800130 mFragment.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800131 updateSettingsLink(currentSetting);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800132 } else {
133 // Multiple recognizers available, so show the full list of choices.
134 populateRecognizerPreference(availableRecognitionServices);
Mike LeBeau92c33522010-01-25 18:18:45 -0500135 }
Narayan Kamathe247cb82011-10-05 12:26:31 +0100136
137 // In this case, there was at least one available recognizer so
138 // we populated the settings.
139 return true;
140 }
141
142 private boolean populateOrRemoveTtsPrefs() {
143 if (mTtsEngines.getEngines().isEmpty()) {
144 mVoiceCategory.removePreference(mTtsSettingsPref);
145 return false;
146 }
147
148 return true;
Mike LeBeau766a19b2010-02-11 22:57:12 -0800149 }
Amith Yamasanib44161f2010-12-10 13:17:34 -0800150
Mike LeBeau766a19b2010-02-11 22:57:12 -0800151 private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
152 int size = recognizers.size();
153 CharSequence[] entries = new CharSequence[size];
154 CharSequence[] values = new CharSequence[size];
155
156 // Get the current value from the secure setting.
157 String currentSetting = Settings.Secure.getString(
Amith Yamasanib44161f2010-12-10 13:17:34 -0800158 mFragment.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800159
160 // Iterate through all the available recognizers and load up their info to show
161 // in the preference. Also build up a map of recognizer component names to their
162 // ResolveInfos - we'll need that a little later.
163 for (int i = 0; i < size; i++) {
164 ResolveInfo resolveInfo = recognizers.get(i);
165 String recognizerComponent =
166 new ComponentName(resolveInfo.serviceInfo.packageName,
Mike LeBeaueffc7542010-02-23 14:51:10 -0800167 resolveInfo.serviceInfo.name).flattenToShortString();
Mike LeBeau766a19b2010-02-11 22:57:12 -0800168
169 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Mike LeBeau92c33522010-01-25 18:18:45 -0500170
Amith Yamasanib44161f2010-12-10 13:17:34 -0800171 entries[i] = resolveInfo.loadLabel(mFragment.getPackageManager());
Mike LeBeau766a19b2010-02-11 22:57:12 -0800172 values[i] = recognizerComponent;
173 }
174
175 mRecognizerPref.setEntries(entries);
176 mRecognizerPref.setEntryValues(values);
177
178 mRecognizerPref.setDefaultValue(currentSetting);
179 mRecognizerPref.setValue(currentSetting);
180
181 updateSettingsLink(currentSetting);
182 }
183
184 private void updateSettingsLink(String currentSetting) {
185 ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
186 ServiceInfo si = currentRecognizer.serviceInfo;
187 XmlResourceParser parser = null;
188 String settingsActivity = null;
189 try {
Amith Yamasanib44161f2010-12-10 13:17:34 -0800190 parser = si.loadXmlMetaData(mFragment.getPackageManager(),
191 RecognitionService.SERVICE_META_DATA);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800192 if (parser == null) {
193 throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
194 " meta-data for " + si.packageName);
Mike LeBeau92c33522010-01-25 18:18:45 -0500195 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800196
Amith Yamasanib44161f2010-12-10 13:17:34 -0800197 Resources res = mFragment.getPackageManager().getResourcesForApplication(
Dianne Hackborn0382a492010-03-04 11:44:09 -0800198 si.applicationInfo);
199
Mike LeBeau766a19b2010-02-11 22:57:12 -0800200 AttributeSet attrs = Xml.asAttributeSet(parser);
201
202 int type;
203 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
204 && type != XmlPullParser.START_TAG) {
205 }
206
207 String nodeName = parser.getName();
208 if (!"recognition-service".equals(nodeName)) {
209 throw new XmlPullParserException(
210 "Meta-data does not start with recognition-service tag");
211 }
212
Dianne Hackborn0382a492010-03-04 11:44:09 -0800213 TypedArray array = res.obtainAttributes(attrs,
Mike LeBeau766a19b2010-02-11 22:57:12 -0800214 com.android.internal.R.styleable.RecognitionService);
215 settingsActivity = array.getString(
216 com.android.internal.R.styleable.RecognitionService_settingsActivity);
217 array.recycle();
218 } catch (XmlPullParserException e) {
219 Log.e(TAG, "error parsing recognition service meta-data", e);
220 } catch (IOException e) {
221 Log.e(TAG, "error parsing recognition service meta-data", e);
Dianne Hackborn0382a492010-03-04 11:44:09 -0800222 } catch (NameNotFoundException e) {
223 Log.e(TAG, "error parsing recognition service meta-data", e);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800224 } finally {
225 if (parser != null) parser.close();
Mike LeBeau92c33522010-01-25 18:18:45 -0500226 }
227
Mike LeBeau766a19b2010-02-11 22:57:12 -0800228 if (settingsActivity == null) {
229 // No settings preference available - hide the preference.
230 Log.w(TAG, "no recognizer settings available for " + si.packageName);
231 mSettingsPref.setIntent(null);
Jean Chalard8ba5c422011-08-31 21:40:43 +0900232 mVoiceCategory.removePreference(mSettingsPref);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800233 } else {
234 Intent i = new Intent(Intent.ACTION_MAIN);
235 i.setComponent(new ComponentName(si.packageName, settingsActivity));
236 mSettingsPref.setIntent(i);
Amith Yamasanib44161f2010-12-10 13:17:34 -0800237 mRecognizerPref.setSummary(currentRecognizer.loadLabel(mFragment.getPackageManager()));
Mike LeBeau766a19b2010-02-11 22:57:12 -0800238 }
239 }
240
241 public boolean onPreferenceChange(Preference preference, Object newValue) {
242 if (preference == mRecognizerPref) {
243 String setting = (String) newValue;
Amith Yamasanib44161f2010-12-10 13:17:34 -0800244
Mike LeBeau766a19b2010-02-11 22:57:12 -0800245 // Put the new value back into secure settings.
Amith Yamasanib44161f2010-12-10 13:17:34 -0800246 Settings.Secure.putString(mFragment.getContentResolver(),
Mike LeBeau766a19b2010-02-11 22:57:12 -0800247 Settings.Secure.VOICE_RECOGNITION_SERVICE,
248 setting);
Amith Yamasanib44161f2010-12-10 13:17:34 -0800249
Mike LeBeau766a19b2010-02-11 22:57:12 -0800250 // Update the settings item so it points to the right settings.
251 updateSettingsLink(setting);
252 }
253 return true;
Mike LeBeau92c33522010-01-25 18:18:45 -0500254 }
255}