blob: 30beddad7458987fbc725065f80f4fb1a12a263e [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;
34import android.preference.PreferenceActivity;
Mike LeBeau766a19b2010-02-11 22:57:12 -080035import android.preference.PreferenceCategory;
Mike LeBeau92c33522010-01-25 18:18:45 -050036import android.preference.PreferenceGroup;
Mike LeBeau766a19b2010-02-11 22:57:12 -080037import android.preference.PreferenceScreen;
38import android.preference.Preference.OnPreferenceChangeListener;
39import android.provider.Settings;
40import android.speech.RecognitionService;
41import android.util.AttributeSet;
42import android.util.Log;
43import android.util.Xml;
Mike LeBeau92c33522010-01-25 18:18:45 -050044
Mike LeBeau766a19b2010-02-11 22:57:12 -080045import java.io.IOException;
46import java.util.HashMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050047import java.util.List;
48
49/**
50 * Settings screen for voice input/output.
51 */
Mike LeBeau766a19b2010-02-11 22:57:12 -080052public class VoiceInputOutputSettings extends PreferenceActivity
53 implements OnPreferenceChangeListener {
54
55 private static final String TAG = "VoiceInputOutputSettings";
Mike LeBeau92c33522010-01-25 18:18:45 -050056
57 private static final String KEY_PARENT = "parent";
Mike LeBeau766a19b2010-02-11 22:57:12 -080058 private static final String KEY_VOICE_INPUT_CATEGORY = "voice_input_category";
59 private static final String KEY_RECOGNIZER = "recognizer";
60 private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings";
61
62 private PreferenceGroup mParent;
63 private PreferenceCategory mVoiceInputCategory;
64 private ListPreference mRecognizerPref;
65 private PreferenceScreen mSettingsPref;
66
67 private HashMap<String, ResolveInfo> mAvailableRecognizersMap;
Mike LeBeau92c33522010-01-25 18:18:45 -050068
69 @Override
70 protected void onCreate(Bundle icicle) {
71 super.onCreate(icicle);
72
73 addPreferencesFromResource(R.xml.voice_input_output_settings);
Mike LeBeau766a19b2010-02-11 22:57:12 -080074
75 mParent = (PreferenceGroup) findPreference(KEY_PARENT);
76 mVoiceInputCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_INPUT_CATEGORY);
77 mRecognizerPref = (ListPreference) mParent.findPreference(KEY_RECOGNIZER);
78 mRecognizerPref.setOnPreferenceChangeListener(this);
79 mSettingsPref = (PreferenceScreen) mParent.findPreference(KEY_RECOGNIZER_SETTINGS);
Mike LeBeau92c33522010-01-25 18:18:45 -050080
Mike LeBeau766a19b2010-02-11 22:57:12 -080081 mAvailableRecognizersMap = new HashMap<String, ResolveInfo>();
82
83 populateOrRemoveRecognizerPreference();
Mike LeBeau92c33522010-01-25 18:18:45 -050084 }
Mike LeBeau766a19b2010-02-11 22:57:12 -080085
86 private void populateOrRemoveRecognizerPreference() {
87 List<ResolveInfo> availableRecognitionServices = getPackageManager().queryIntentServices(
88 new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
89 int numAvailable = availableRecognitionServices.size();
Mike LeBeau92c33522010-01-25 18:18:45 -050090
Mike LeBeau766a19b2010-02-11 22:57:12 -080091 if (numAvailable == 0) {
92 // No recognizer available - remove all related preferences.
93 removePreference(mVoiceInputCategory);
94 removePreference(mRecognizerPref);
95 removePreference(mSettingsPref);
96 } else if (numAvailable == 1) {
Mike LeBeau4c2ffc52010-02-12 14:47:48 -080097 // Only one recognizer available, so don't show the list of choices, but do
98 // set up the link to settings for the available recognizer.
Mike LeBeau766a19b2010-02-11 22:57:12 -080099 removePreference(mRecognizerPref);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800100
101 // But first set up the available recognizers map with just the one recognizer.
102 ResolveInfo resolveInfo = availableRecognitionServices.get(0);
103 String recognizerComponent =
104 new ComponentName(resolveInfo.serviceInfo.packageName,
Mike LeBeaueffc7542010-02-23 14:51:10 -0800105 resolveInfo.serviceInfo.name).flattenToShortString();
106
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800107 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
108
109 String currentSetting = Settings.Secure.getString(
110 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
111 updateSettingsLink(currentSetting);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800112 } else {
113 // Multiple recognizers available, so show the full list of choices.
114 populateRecognizerPreference(availableRecognitionServices);
Mike LeBeau92c33522010-01-25 18:18:45 -0500115 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800116 }
117
118 private void removePreference(Preference pref) {
119 if (pref != null) {
120 mParent.removePreference(pref);
121 }
122 }
123
124 private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
125 int size = recognizers.size();
126 CharSequence[] entries = new CharSequence[size];
127 CharSequence[] values = new CharSequence[size];
128
129 // Get the current value from the secure setting.
130 String currentSetting = Settings.Secure.getString(
131 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
132
133 // Iterate through all the available recognizers and load up their info to show
134 // in the preference. Also build up a map of recognizer component names to their
135 // ResolveInfos - we'll need that a little later.
136 for (int i = 0; i < size; i++) {
137 ResolveInfo resolveInfo = recognizers.get(i);
138 String recognizerComponent =
139 new ComponentName(resolveInfo.serviceInfo.packageName,
Mike LeBeaueffc7542010-02-23 14:51:10 -0800140 resolveInfo.serviceInfo.name).flattenToShortString();
Mike LeBeau766a19b2010-02-11 22:57:12 -0800141
142 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Mike LeBeau92c33522010-01-25 18:18:45 -0500143
Mike LeBeau766a19b2010-02-11 22:57:12 -0800144 entries[i] = resolveInfo.loadLabel(getPackageManager());
145 values[i] = recognizerComponent;
146 }
147
148 mRecognizerPref.setEntries(entries);
149 mRecognizerPref.setEntryValues(values);
150
151 mRecognizerPref.setDefaultValue(currentSetting);
152 mRecognizerPref.setValue(currentSetting);
153
154 updateSettingsLink(currentSetting);
155 }
156
157 private void updateSettingsLink(String currentSetting) {
158 ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
159 ServiceInfo si = currentRecognizer.serviceInfo;
160 XmlResourceParser parser = null;
161 String settingsActivity = null;
162 try {
163 parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA);
164 if (parser == null) {
165 throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
166 " meta-data for " + si.packageName);
Mike LeBeau92c33522010-01-25 18:18:45 -0500167 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800168
Dianne Hackborn0382a492010-03-04 11:44:09 -0800169 Resources res = getPackageManager().getResourcesForApplication(
170 si.applicationInfo);
171
Mike LeBeau766a19b2010-02-11 22:57:12 -0800172 AttributeSet attrs = Xml.asAttributeSet(parser);
173
174 int type;
175 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
176 && type != XmlPullParser.START_TAG) {
177 }
178
179 String nodeName = parser.getName();
180 if (!"recognition-service".equals(nodeName)) {
181 throw new XmlPullParserException(
182 "Meta-data does not start with recognition-service tag");
183 }
184
Dianne Hackborn0382a492010-03-04 11:44:09 -0800185 TypedArray array = res.obtainAttributes(attrs,
Mike LeBeau766a19b2010-02-11 22:57:12 -0800186 com.android.internal.R.styleable.RecognitionService);
187 settingsActivity = array.getString(
188 com.android.internal.R.styleable.RecognitionService_settingsActivity);
189 array.recycle();
190 } catch (XmlPullParserException e) {
191 Log.e(TAG, "error parsing recognition service meta-data", e);
192 } catch (IOException e) {
193 Log.e(TAG, "error parsing recognition service meta-data", e);
Dianne Hackborn0382a492010-03-04 11:44:09 -0800194 } catch (NameNotFoundException e) {
195 Log.e(TAG, "error parsing recognition service meta-data", e);
Mike LeBeau766a19b2010-02-11 22:57:12 -0800196 } finally {
197 if (parser != null) parser.close();
Mike LeBeau92c33522010-01-25 18:18:45 -0500198 }
199
Mike LeBeau766a19b2010-02-11 22:57:12 -0800200 if (settingsActivity == null) {
201 // No settings preference available - hide the preference.
202 Log.w(TAG, "no recognizer settings available for " + si.packageName);
203 mSettingsPref.setIntent(null);
204 mParent.removePreference(mSettingsPref);
205 } else {
206 Intent i = new Intent(Intent.ACTION_MAIN);
207 i.setComponent(new ComponentName(si.packageName, settingsActivity));
208 mSettingsPref.setIntent(i);
Mike LeBeau4c2ffc52010-02-12 14:47:48 -0800209 mRecognizerPref.setSummary(currentRecognizer.loadLabel(getPackageManager()));
Mike LeBeau766a19b2010-02-11 22:57:12 -0800210 }
211 }
212
213 public boolean onPreferenceChange(Preference preference, Object newValue) {
214 if (preference == mRecognizerPref) {
215 String setting = (String) newValue;
216
217 // Put the new value back into secure settings.
218 Settings.Secure.putString(
219 getContentResolver(),
220 Settings.Secure.VOICE_RECOGNITION_SERVICE,
221 setting);
222
223 // Update the settings item so it points to the right settings.
224 updateSettingsLink(setting);
225 }
226 return true;
Mike LeBeau92c33522010-01-25 18:18:45 -0500227 }
228}