blob: b07c69ee691d65ad9fc0f83ef293e7fed304aa85 [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;
Dianne Hackborn0382a492010-03-04 11:44:09 -080027import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.res.Resources;
Mike LeBeau766a19b2010-02-11 22:57:12 -080029import android.content.res.TypedArray;
30import android.content.res.XmlResourceParser;
Mike LeBeau92c33522010-01-25 18:18:45 -050031import android.os.Bundle;
Mike LeBeau766a19b2010-02-11 22:57:12 -080032import android.preference.ListPreference;
Mike LeBeau92c33522010-01-25 18:18:45 -050033import android.preference.Preference;
Mike LeBeau766a19b2010-02-11 22:57:12 -080034import android.preference.PreferenceCategory;
Mike LeBeau92c33522010-01-25 18:18:45 -050035import android.preference.PreferenceGroup;
Mike LeBeau766a19b2010-02-11 22:57:12 -080036import android.preference.PreferenceScreen;
37import android.preference.Preference.OnPreferenceChangeListener;
38import android.provider.Settings;
39import android.speech.RecognitionService;
40import android.util.AttributeSet;
41import android.util.Log;
42import android.util.Xml;
Mike LeBeau92c33522010-01-25 18:18:45 -050043
Mike LeBeau766a19b2010-02-11 22:57:12 -080044import java.io.IOException;
45import java.util.HashMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050046import java.util.List;
47
48/**
49 * Settings screen for voice input/output.
50 */
Amith Yamasanid7993472010-08-18 13:59:28 -070051public class VoiceInputOutputSettings extends SettingsPreferenceFragment
Mike LeBeau766a19b2010-02-11 22:57:12 -080052 implements OnPreferenceChangeListener {
53
54 private static final String TAG = "VoiceInputOutputSettings";
Mike LeBeau92c33522010-01-25 18:18:45 -050055
56 private static final String KEY_PARENT = "parent";
Mike LeBeau766a19b2010-02-11 22:57:12 -080057 private static final String KEY_VOICE_INPUT_CATEGORY = "voice_input_category";
58 private static final String KEY_RECOGNIZER = "recognizer";
59 private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings";
60
61 private PreferenceGroup mParent;
62 private PreferenceCategory mVoiceInputCategory;
63 private ListPreference mRecognizerPref;
64 private PreferenceScreen mSettingsPref;
65
66 private HashMap<String, ResolveInfo> mAvailableRecognizersMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050067
68 @Override
Amith Yamasanid7993472010-08-18 13:59:28 -070069 public void onCreate(Bundle icicle) {
Mike LeBeau92c33522010-01-25 18:18:45 -050070 super.onCreate(icicle);
71
72 addPreferencesFromResource(R.xml.voice_input_output_settings);
Mike LeBeau766a19b2010-02-11 22:57:12 -080073
74 mParent = (PreferenceGroup) findPreference(KEY_PARENT);
75 mVoiceInputCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_INPUT_CATEGORY);
76 mRecognizerPref = (ListPreference) mParent.findPreference(KEY_RECOGNIZER);
77 mRecognizerPref.setOnPreferenceChangeListener(this);
78 mSettingsPref = (PreferenceScreen) mParent.findPreference(KEY_RECOGNIZER_SETTINGS);
Mike LeBeau92c33522010-01-25 18:18:45 -050079
Mike LeBeau766a19b2010-02-11 22:57:12 -080080 mAvailableRecognizersMap = new HashMap<String, ResolveInfo>();
81
82 populateOrRemoveRecognizerPreference();
Mike LeBeau92c33522010-01-25 18:18:45 -050083 }
Mike LeBeau766a19b2010-02-11 22:57:12 -080084
85 private void populateOrRemoveRecognizerPreference() {
86 List<ResolveInfo> availableRecognitionServices = getPackageManager().queryIntentServices(
87 new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
88 int numAvailable = availableRecognitionServices.size();
Mike LeBeau92c33522010-01-25 18:18:45 -050089
Mike LeBeau766a19b2010-02-11 22:57:12 -080090 if (numAvailable == 0) {
91 // No recognizer available - remove all related preferences.
92 removePreference(mVoiceInputCategory);
93 removePreference(mRecognizerPref);
94 removePreference(mSettingsPref);
95 } else if (numAvailable == 1) {
Mike LeBeau4c2ffc52010-02-12 14:47:48 -080096 // Only one recognizer available, so don't show the list of choices, but do
97 // set up the link to settings for the available recognizer.
Mike LeBeau766a19b2010-02-11 22:57:12 -080098 removePreference(mRecognizerPref);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -080099
100 // But first set up the available recognizers map with just the one recognizer.
101 ResolveInfo resolveInfo = availableRecognitionServices.get(0);
102 String recognizerComponent =
103 new ComponentName(resolveInfo.serviceInfo.packageName,
Mike LeBeaueffc7542010-02-23 14:51:10 -0800104 resolveInfo.serviceInfo.name).flattenToShortString();
105
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800106 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
107
108 String currentSetting = Settings.Secure.getString(
109 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
110 updateSettingsLink(currentSetting);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800111 } else {
112 // Multiple recognizers available, so show the full list of choices.
113 populateRecognizerPreference(availableRecognitionServices);
Mike LeBeau92c33522010-01-25 18:18:45 -0500114 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800115 }
116
117 private void removePreference(Preference pref) {
118 if (pref != null) {
119 mParent.removePreference(pref);
120 }
121 }
122
123 private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
124 int size = recognizers.size();
125 CharSequence[] entries = new CharSequence[size];
126 CharSequence[] values = new CharSequence[size];
127
128 // Get the current value from the secure setting.
129 String currentSetting = Settings.Secure.getString(
130 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
131
132 // Iterate through all the available recognizers and load up their info to show
133 // in the preference. Also build up a map of recognizer component names to their
134 // ResolveInfos - we'll need that a little later.
135 for (int i = 0; i < size; i++) {
136 ResolveInfo resolveInfo = recognizers.get(i);
137 String recognizerComponent =
138 new ComponentName(resolveInfo.serviceInfo.packageName,
Mike LeBeaueffc7542010-02-23 14:51:10 -0800139 resolveInfo.serviceInfo.name).flattenToShortString();
Mike LeBeau766a19b2010-02-11 22:57:12 -0800140
141 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Mike LeBeau92c33522010-01-25 18:18:45 -0500142
Mike LeBeau766a19b2010-02-11 22:57:12 -0800143 entries[i] = resolveInfo.loadLabel(getPackageManager());
144 values[i] = recognizerComponent;
145 }
146
147 mRecognizerPref.setEntries(entries);
148 mRecognizerPref.setEntryValues(values);
149
150 mRecognizerPref.setDefaultValue(currentSetting);
151 mRecognizerPref.setValue(currentSetting);
152
153 updateSettingsLink(currentSetting);
154 }
155
156 private void updateSettingsLink(String currentSetting) {
157 ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
158 ServiceInfo si = currentRecognizer.serviceInfo;
159 XmlResourceParser parser = null;
160 String settingsActivity = null;
161 try {
162 parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA);
163 if (parser == null) {
164 throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
165 " meta-data for " + si.packageName);
Mike LeBeau92c33522010-01-25 18:18:45 -0500166 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800167
Dianne Hackborn0382a492010-03-04 11:44:09 -0800168 Resources res = getPackageManager().getResourcesForApplication(
169 si.applicationInfo);
170
Mike LeBeau766a19b2010-02-11 22:57:12 -0800171 AttributeSet attrs = Xml.asAttributeSet(parser);
172
173 int type;
174 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
175 && type != XmlPullParser.START_TAG) {
176 }
177
178 String nodeName = parser.getName();
179 if (!"recognition-service".equals(nodeName)) {
180 throw new XmlPullParserException(
181 "Meta-data does not start with recognition-service tag");
182 }
183
Dianne Hackborn0382a492010-03-04 11:44:09 -0800184 TypedArray array = res.obtainAttributes(attrs,
Mike LeBeau766a19b2010-02-11 22:57:12 -0800185 com.android.internal.R.styleable.RecognitionService);
186 settingsActivity = array.getString(
187 com.android.internal.R.styleable.RecognitionService_settingsActivity);
188 array.recycle();
189 } catch (XmlPullParserException e) {
190 Log.e(TAG, "error parsing recognition service meta-data", e);
191 } catch (IOException e) {
192 Log.e(TAG, "error parsing recognition service meta-data", e);
Dianne Hackborn0382a492010-03-04 11:44:09 -0800193 } catch (NameNotFoundException e) {
194 Log.e(TAG, "error parsing recognition service meta-data", e);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800195 } finally {
196 if (parser != null) parser.close();
Mike LeBeau92c33522010-01-25 18:18:45 -0500197 }
198
Mike LeBeau766a19b2010-02-11 22:57:12 -0800199 if (settingsActivity == null) {
200 // No settings preference available - hide the preference.
201 Log.w(TAG, "no recognizer settings available for " + si.packageName);
202 mSettingsPref.setIntent(null);
203 mParent.removePreference(mSettingsPref);
204 } else {
205 Intent i = new Intent(Intent.ACTION_MAIN);
206 i.setComponent(new ComponentName(si.packageName, settingsActivity));
207 mSettingsPref.setIntent(i);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800208 mRecognizerPref.setSummary(currentRecognizer.loadLabel(getPackageManager()));
Mike LeBeau766a19b2010-02-11 22:57:12 -0800209 }
210 }
211
212 public boolean onPreferenceChange(Preference preference, Object newValue) {
213 if (preference == mRecognizerPref) {
214 String setting = (String) newValue;
215
216 // Put the new value back into secure settings.
217 Settings.Secure.putString(
218 getContentResolver(),
219 Settings.Secure.VOICE_RECOGNITION_SERVICE,
220 setting);
221
222 // Update the settings item so it points to the right settings.
223 updateSettingsLink(setting);
224 }
225 return true;
Mike LeBeau92c33522010-01-25 18:18:45 -0500226 }
227}