blob: 62c909f7a239fdf5a3c74f5e8b9930150d2d1906 [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) {
95 // Only one recognizer available, so don't show the list of choices.
96 removePreference(mRecognizerPref);
97 } else {
98 // Multiple recognizers available, so show the full list of choices.
99 populateRecognizerPreference(availableRecognitionServices);
Mike LeBeau92c33522010-01-25 18:18:45 -0500100 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800101 }
102
103 private void removePreference(Preference pref) {
104 if (pref != null) {
105 mParent.removePreference(pref);
106 }
107 }
108
109 private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
110 int size = recognizers.size();
111 CharSequence[] entries = new CharSequence[size];
112 CharSequence[] values = new CharSequence[size];
113
114 // Get the current value from the secure setting.
115 String currentSetting = Settings.Secure.getString(
116 getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
117
118 // Iterate through all the available recognizers and load up their info to show
119 // in the preference. Also build up a map of recognizer component names to their
120 // ResolveInfos - we'll need that a little later.
121 for (int i = 0; i < size; i++) {
122 ResolveInfo resolveInfo = recognizers.get(i);
123 String recognizerComponent =
124 new ComponentName(resolveInfo.serviceInfo.packageName,
125 resolveInfo.serviceInfo.name).flattenToString();
126
127 mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
Mike LeBeau92c33522010-01-25 18:18:45 -0500128
Mike LeBeau766a19b2010-02-11 22:57:12 -0800129 entries[i] = resolveInfo.loadLabel(getPackageManager());
130 values[i] = recognizerComponent;
131 }
132
133 mRecognizerPref.setEntries(entries);
134 mRecognizerPref.setEntryValues(values);
135
136 mRecognizerPref.setDefaultValue(currentSetting);
137 mRecognizerPref.setValue(currentSetting);
138
139 updateSettingsLink(currentSetting);
140 }
141
142 private void updateSettingsLink(String currentSetting) {
143 ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
144 ServiceInfo si = currentRecognizer.serviceInfo;
145 XmlResourceParser parser = null;
146 String settingsActivity = null;
147 try {
148 parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA);
149 if (parser == null) {
150 throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
151 " meta-data for " + si.packageName);
Mike LeBeau92c33522010-01-25 18:18:45 -0500152 }
Mike LeBeau766a19b2010-02-11 22:57:12 -0800153
154 AttributeSet attrs = Xml.asAttributeSet(parser);
155
156 int type;
157 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
158 && type != XmlPullParser.START_TAG) {
159 }
160
161 String nodeName = parser.getName();
162 if (!"recognition-service".equals(nodeName)) {
163 throw new XmlPullParserException(
164 "Meta-data does not start with recognition-service tag");
165 }
166
167 TypedArray array = getResources().obtainAttributes(attrs,
168 com.android.internal.R.styleable.RecognitionService);
169 settingsActivity = array.getString(
170 com.android.internal.R.styleable.RecognitionService_settingsActivity);
171 array.recycle();
172 } catch (XmlPullParserException e) {
173 Log.e(TAG, "error parsing recognition service meta-data", e);
174 } catch (IOException e) {
175 Log.e(TAG, "error parsing recognition service meta-data", e);
176 } finally {
177 if (parser != null) parser.close();
Mike LeBeau92c33522010-01-25 18:18:45 -0500178 }
179
Mike LeBeau766a19b2010-02-11 22:57:12 -0800180 if (settingsActivity == null) {
181 // No settings preference available - hide the preference.
182 Log.w(TAG, "no recognizer settings available for " + si.packageName);
183 mSettingsPref.setIntent(null);
184 mParent.removePreference(mSettingsPref);
185 } else {
186 Intent i = new Intent(Intent.ACTION_MAIN);
187 i.setComponent(new ComponentName(si.packageName, settingsActivity));
188 mSettingsPref.setIntent(i);
189 }
190 }
191
192 public boolean onPreferenceChange(Preference preference, Object newValue) {
193 if (preference == mRecognizerPref) {
194 String setting = (String) newValue;
195
196 // Put the new value back into secure settings.
197 Settings.Secure.putString(
198 getContentResolver(),
199 Settings.Secure.VOICE_RECOGNITION_SERVICE,
200 setting);
201
202 // Update the settings item so it points to the right settings.
203 updateSettingsLink(setting);
204 }
205 return true;
Mike LeBeau92c33522010-01-25 18:18:45 -0500206 }
207}