blob: f77913f8d3c57d8954f0811d650afbbb694a42fd [file] [log] [blame]
Jean-Michel Trivied29a652009-06-05 18:37:29 -07001/*
2 * Copyright (C) 2009 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
19import static android.provider.Settings.Secure.TTS_USE_DEFAULTS;
20import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
21import static android.provider.Settings.Secure.TTS_DEFAULT_PITCH;
Jean-Michel Trivi80368622009-06-09 19:29:27 -070022import static android.provider.Settings.Secure.TTS_DEFAULT_LANG;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070023import static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
24import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
Jean-Michel Trivied29a652009-06-05 18:37:29 -070025
26import android.content.ContentResolver;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070027import android.content.Intent;
28import android.content.pm.ActivityInfo;
29import android.content.pm.PackageManager;
30import android.content.pm.ResolveInfo;
Jean-Michel Trivied29a652009-06-05 18:37:29 -070031import android.os.Bundle;
32import android.preference.ListPreference;
33import android.preference.Preference;
34import android.preference.PreferenceActivity;
35import android.preference.CheckBoxPreference;
36import android.provider.Settings;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070037import android.provider.Settings.SettingNotFoundException;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070038import android.speech.tts.TextToSpeech;
Jean-Michel Trivied29a652009-06-05 18:37:29 -070039import android.util.Log;
40
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070041import java.util.List;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070042import java.util.StringTokenizer;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070043
Jean-Michel Trivied29a652009-06-05 18:37:29 -070044public class TextToSpeechSettings extends PreferenceActivity implements
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070045 Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
46 TextToSpeech.OnInitListener {
Jean-Michel Trivied29a652009-06-05 18:37:29 -070047
48 private static final String TAG = "TextToSpeechSettings";
Jean-Michel Trivied29a652009-06-05 18:37:29 -070049
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070050 private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070051 private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070052 private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
Jean-Michel Trivied29a652009-06-05 18:37:29 -070053 private static final String KEY_TTS_DEFAULT_RATE = "tts_default_rate";
54 private static final String KEY_TTS_DEFAULT_PITCH = "tts_default_pitch";
Jean-Michel Trivi80368622009-06-09 19:29:27 -070055 private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070056 private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
57 private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
58
59 private static final String LOCALE_DELIMITER = "-";
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070060
61 // TODO move this to android.speech.tts.TextToSpeech.Engine
62 private static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
63
64 private Preference mPlayExample = null;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070065 private Preference mInstallData = null;
Jean-Michel Trivied29a652009-06-05 18:37:29 -070066 private CheckBoxPreference mUseDefaultPref = null;
67 private ListPreference mDefaultRatePref = null;
68 private ListPreference mDefaultPitchPref = null;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070069 private ListPreference mDefaultLocPref = null;
70 private String mDefaultLanguage = null;
71 private String mDefaultCountry = null;
72 private String mDefaultLocVariant = null;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070073 private String mDefaultEng = "";
74
75 private boolean mEnableDemo = false;
76
77 private TextToSpeech mTts = null;
78
79 /**
80 * Request code (arbitrary value) for voice data check through
81 * startActivityForResult.
82 */
83 private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
84
Jean-Michel Trivied29a652009-06-05 18:37:29 -070085 @Override
86 protected void onCreate(Bundle savedInstanceState) {
87 super.onCreate(savedInstanceState);
88
89 addPreferencesFromResource(R.xml.tts_settings);
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070090
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070091 initClickers();
Jean-Michel Trivied29a652009-06-05 18:37:29 -070092 initDefaultSettings();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070093 }
94
95
96 @Override
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070097 protected void onStart() {
98 super.onStart();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070099 // whenever we return to this screen, we don't know the state of the
100 // system, so we have to recheck that we can play the demo, or it must be disabled.
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700101 // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700102 mEnableDemo = false;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700103 initClickers();
104 updateWidgetState();
105 checkVoiceData();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700106 }
107
108
109 @Override
110 protected void onDestroy() {
111 super.onDestroy();
112 if (mTts != null) {
113 mTts.shutdown();
114 }
115 }
116
117
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700118 private void initClickers() {
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700119 mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700120 mPlayExample.setOnPreferenceClickListener(this);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700121
122 mInstallData = findPreference(KEY_TTS_INSTALL_DATA);
123 mInstallData.setOnPreferenceClickListener(this);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700124 }
125
126
127 private void initDefaultSettings() {
128 ContentResolver resolver = getContentResolver();
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700129 int intVal = 0;
130
131 // Find the default TTS values in the settings, initialize and store the
132 // settings if they are not found.
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700133
134 // "Use Defaults"
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700135 mUseDefaultPref = (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
136 try {
137 intVal = Settings.Secure.getInt(resolver, TTS_USE_DEFAULTS);
138 } catch (SettingNotFoundException e) {
139 // "use default" setting not found, initialize it
140 intVal = TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS;
141 Settings.Secure.putInt(resolver, TTS_USE_DEFAULTS, intVal);
142 }
143 mUseDefaultPref.setChecked(intVal == 1);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700144 mUseDefaultPref.setOnPreferenceChangeListener(this);
145
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700146 // Default engine
147 mDefaultEng = FALLBACK_TTS_DEFAULT_SYNTH;
148
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700149 // Default rate
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700150 mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
151 try {
152 intVal = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
153 } catch (SettingNotFoundException e) {
154 // default rate setting not found, initialize it
155 intVal = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE;
156 Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, intVal);
157 }
158 mDefaultRatePref.setValue(String.valueOf(intVal));
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700159 mDefaultRatePref.setOnPreferenceChangeListener(this);
160
161 // Default pitch
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700162 mDefaultPitchPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_PITCH);
163 try {
164 intVal = Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH);
165 } catch (SettingNotFoundException e) {
166 // default pitch setting not found, initialize it
167 intVal = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_PITCH;
168 Settings.Secure.putInt(resolver, TTS_DEFAULT_PITCH, intVal);
169 }
170 mDefaultPitchPref.setValue(String.valueOf(intVal));
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700171 mDefaultPitchPref.setOnPreferenceChangeListener(this);
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700172
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700173
174 // Default language / country / variant : these three values map to a single ListPref
175 // representing the matching Locale
176 String language = null;
177 String country = null;
178 String variant = null;
179 mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
180 language = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_LANG);
181 if (language != null) {
182 mDefaultLanguage = language;
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700183 } else {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700184 // default language setting not found, initialize it, as well as the country and variant
185 language = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
186 country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
187 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
188 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_LANG, language);
189 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_COUNTRY, country);
190 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_VARIANT, variant);
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700191 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700192 if (country == null) {
193 // country wasn't initialized yet because a default language was found
194 country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
195 if (country.compareTo("null") != 0) {
196 mDefaultCountry = country;
197 } else {
198 // default country setting not found, initialize it, as well as the variant;
199 country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
200 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
201 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_COUNTRY, country);
202 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_VARIANT, variant);
203 }
204 }
205 if (variant == null) {
206 // variant wasn't initialized yet because a default country was found
207 variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
208 if (variant.compareTo("null") != 0) {
209 mDefaultLocVariant = variant;
210 } else {
211 // default variant setting not found, initialize it
212 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
213 Settings.Secure.putString(resolver, KEY_TTS_DEFAULT_VARIANT, variant);
214 }
215 }
216 // we now have the default lang/country/variant trio, build a string value from it
217 String localeString = new String(language);
218 if (country.compareTo("") != 0) {
219 localeString += LOCALE_DELIMITER + country;
220 } else {
221 localeString += LOCALE_DELIMITER + " ";
222 }
223 if (variant.compareTo("") != 0) {
224 localeString += LOCALE_DELIMITER + variant;
225 }
226 Log.v(TAG, "In initDefaultSettings: localeString=" + localeString);
227 // TODO handle the case where localeString isn't in the existing entries
228 mDefaultLocPref.setValue(localeString);
229 mDefaultLocPref.setOnPreferenceChangeListener(this);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700230 }
231
232
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700233 private void checkVoiceData() {
234 PackageManager pm = getPackageManager();
235 Intent intent = new Intent();
236 intent.setAction("android.intent.action.CHECK_TTS_DATA");
237 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
238 // query only the package that matches that of the default engine
239 for (int i = 0; i < resolveInfos.size(); i++) {
240 ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
241 if (mDefaultEng.equals(currentActivityInfo.packageName)) {
242 intent.setClassName(mDefaultEng, currentActivityInfo.name);
243 this.startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
244 }
245 }
246 }
247
248
249 /**
250 * Called when the TTS engine is initialized.
251 */
252 public void onInit(int status) {
253 if (status == TextToSpeech.TTS_SUCCESS) {
254 Log.v(TAG, "TTS engine for settings screen initialized.");
255 mEnableDemo = true;
256 } else {
257 Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
258 mEnableDemo = false;
259 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700260 updateWidgetState();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700261 }
262
263
264 /**
265 * Called when voice data integrity check returns
266 */
267 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
268 if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
269 if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
270 Log.v(TAG, "Voice data check passed");
271 if (mTts == null) {
272 mTts = new TextToSpeech(this, this);
273 }
274 } else {
275 Log.v(TAG, "Voice data check failed");
276
277 }
278 }
279 }
280
281
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700282 public boolean onPreferenceChange(Preference preference, Object objValue) {
283 if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
284 // "Use Defaults"
285 int value = (Boolean)objValue ? 1 : 0;
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700286 Settings.Secure.putInt(getContentResolver(), TTS_USE_DEFAULTS,
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700287 value);
288 Log.i(TAG, "TTS use default settings is "+objValue.toString());
289 } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
290 // Default rate
291 int value = Integer.parseInt((String) objValue);
292 try {
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700293 Settings.Secure.putInt(getContentResolver(),
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700294 TTS_DEFAULT_RATE, value);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700295 if (mTts != null) {
296 mTts.setSpeechRate(value);
297 }
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700298 Log.i(TAG, "TTS default rate is "+value);
299 } catch (NumberFormatException e) {
300 Log.e(TAG, "could not persist default TTS rate setting", e);
301 }
302 } else if (KEY_TTS_DEFAULT_PITCH.equals(preference.getKey())) {
303 // Default pitch
304 int value = Integer.parseInt((String) objValue);
305 try {
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700306 Settings.Secure.putInt(getContentResolver(),
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700307 TTS_DEFAULT_PITCH, value);
308 Log.i(TAG, "TTS default pitch is "+value);
309 } catch (NumberFormatException e) {
310 Log.e(TAG, "could not persist default TTS pitch setting", e);
311 }
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700312 } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700313 // Default locale
314 ContentResolver resolver = getContentResolver();
315 parseLocaleInfo((String) objValue);
316 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
317 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
318 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
319 Log.v(TAG, "TTS default lang/country/variant set to "
320 + mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700321 }
322
323 return true;
324 }
325
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700326
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700327 /**
328 * Called when mPlayExample or mInstallData is clicked
329 */
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700330 public boolean onPreferenceClick(Preference preference) {
331 if (preference == mPlayExample) {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700332 // Play example
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700333 if (mTts != null) {
334 mTts.speak(getResources().getString(R.string.tts_demo),
335 TextToSpeech.TTS_QUEUE_FLUSH, null);
336 }
337 return true;
338 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700339 if (preference == mInstallData) {
340 // Install data
341 // TODO launch request for installer
342
343 return true;
344 }
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700345 return false;
346 }
347
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700348
349 private void updateWidgetState() {
350 mPlayExample.setEnabled(mEnableDemo);
351 mUseDefaultPref.setEnabled(mEnableDemo);
352 mDefaultRatePref.setEnabled(mEnableDemo);
353 mDefaultPitchPref.setEnabled(mEnableDemo);
354 mDefaultLocPref.setEnabled(mEnableDemo);
355
356 mInstallData.setEnabled(!mEnableDemo);
357 }
358
359
360 private void parseLocaleInfo(String locale) {
361 StringTokenizer tokenizer = new StringTokenizer(locale, LOCALE_DELIMITER);
362 mDefaultLanguage = "";
363 mDefaultCountry = "";
364 mDefaultLocVariant = "";
365 if (tokenizer.hasMoreTokens()) {
366 mDefaultLanguage = tokenizer.nextToken().trim();
367 }
368 if (tokenizer.hasMoreTokens()) {
369 mDefaultCountry = tokenizer.nextToken().trim();
370 }
371 if (tokenizer.hasMoreTokens()) {
372 mDefaultLocVariant = tokenizer.nextToken().trim();
373 }
374 }
375
376
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700377}