2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import static android.provider.Settings.Secure.TTS_USE_DEFAULTS;
20 import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
21 import static android.provider.Settings.Secure.TTS_DEFAULT_LANG;
22 import static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
23 import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
24 import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
26 import android.content.ContentResolver;
27 import android.content.Intent;
28 import android.content.pm.ActivityInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.os.Bundle;
32 import android.preference.ListPreference;
33 import android.preference.Preference;
34 import android.preference.PreferenceActivity;
35 import android.preference.CheckBoxPreference;
36 import android.provider.Settings;
37 import android.provider.Settings.SettingNotFoundException;
38 import android.speech.tts.TextToSpeech;
39 import android.util.Log;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.StringTokenizer;
45 public class TextToSpeechSettings extends PreferenceActivity implements
46 Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
47 TextToSpeech.OnInitListener {
49 private static final String TAG = "TextToSpeechSettings";
51 private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
52 private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
53 private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
54 private static final String KEY_TTS_DEFAULT_RATE = "tts_default_rate";
55 private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
56 private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
57 private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
58 // TODO move default Locale values to TextToSpeech.Engine
59 private static final String DEFAULT_LANG_VAL = "eng";
60 private static final String DEFAULT_COUNTRY_VAL = "USA";
61 private static final String DEFAULT_VARIANT_VAL = "";
63 private static final String LOCALE_DELIMITER = "-";
65 private static final String FALLBACK_TTS_DEFAULT_SYNTH =
66 TextToSpeech.Engine.DEFAULT_SYNTH;
68 private Preference mPlayExample = null;
69 private Preference mInstallData = null;
70 private CheckBoxPreference mUseDefaultPref = null;
71 private ListPreference mDefaultRatePref = null;
72 private ListPreference mDefaultLocPref = null;
73 private String mDefaultLanguage = null;
74 private String mDefaultCountry = null;
75 private String mDefaultLocVariant = null;
76 private String mDefaultEng = "";
77 private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
79 // Array of strings used to demonstrate TTS in the different languages.
80 private String[] mDemoStrings;
81 // Index of the current string to use for the demo.
82 private int mDemoStringIndex = 0;
84 private boolean mEnableDemo = false;
86 private TextToSpeech mTts = null;
89 * Request code (arbitrary value) for voice data check through
90 * startActivityForResult.
92 private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
95 protected void onCreate(Bundle savedInstanceState) {
96 super.onCreate(savedInstanceState);
98 addPreferencesFromResource(R.xml.tts_settings);
100 mDemoStrings = getResources().getStringArray(R.array.tts_demo_strings);
102 setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
106 initDefaultSettings();
111 protected void onStart() {
113 // whenever we return to this screen, we don't know the state of the
114 // system, so we have to recheck that we can play the demo, or it must be disabled.
115 // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
123 protected void onDestroy() {
131 private void initClickers() {
132 mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
133 mPlayExample.setOnPreferenceClickListener(this);
135 mInstallData = findPreference(KEY_TTS_INSTALL_DATA);
136 mInstallData.setOnPreferenceClickListener(this);
140 private void initDefaultSettings() {
141 ContentResolver resolver = getContentResolver();
143 // Find the default TTS values in the settings, initialize and store the
144 // settings if they are not found.
148 mUseDefaultPref = (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
150 useDefault = Settings.Secure.getInt(resolver, TTS_USE_DEFAULTS);
151 } catch (SettingNotFoundException e) {
152 // "use default" setting not found, initialize it
153 useDefault = TextToSpeech.Engine.USE_DEFAULTS;
154 Settings.Secure.putInt(resolver, TTS_USE_DEFAULTS, useDefault);
156 mUseDefaultPref.setChecked(useDefault == 1);
157 mUseDefaultPref.setOnPreferenceChangeListener(this);
160 String engine = Settings.Secure.getString(resolver, TTS_DEFAULT_SYNTH);
161 if (engine == null) {
162 // TODO move FALLBACK_TTS_DEFAULT_SYNTH to TextToSpeech
163 engine = FALLBACK_TTS_DEFAULT_SYNTH;
164 Settings.Secure.putString(resolver, TTS_DEFAULT_SYNTH, engine);
166 mDefaultEng = engine;
169 mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
171 mDefaultRate = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
172 } catch (SettingNotFoundException e) {
173 // default rate setting not found, initialize it
174 mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
175 Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, mDefaultRate);
177 mDefaultRatePref.setValue(String.valueOf(mDefaultRate));
178 mDefaultRatePref.setOnPreferenceChangeListener(this);
180 // Default language / country / variant : these three values map to a single ListPref
181 // representing the matching Locale
182 mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
184 mDefaultLocPref.setOnPreferenceChangeListener(this);
189 * Ask the current default engine to launch the matching CHECK_TTS_DATA activity
190 * to check the required TTS files are properly installed.
192 private void checkVoiceData() {
193 PackageManager pm = getPackageManager();
194 Intent intent = new Intent();
195 intent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
196 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
197 // query only the package that matches that of the default engine
198 for (int i = 0; i < resolveInfos.size(); i++) {
199 ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
200 if (mDefaultEng.equals(currentActivityInfo.packageName)) {
201 intent.setClassName(mDefaultEng, currentActivityInfo.name);
202 this.startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
209 * Ask the current default engine to launch the matching INSTALL_TTS_DATA activity
210 * so the required TTS files are properly installed.
212 private void installVoiceData() {
213 PackageManager pm = getPackageManager();
214 Intent intent = new Intent();
215 intent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
216 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
217 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
218 // query only the package that matches that of the default engine
219 for (int i = 0; i < resolveInfos.size(); i++) {
220 ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
221 if (mDefaultEng.equals(currentActivityInfo.packageName)) {
222 intent.setClassName(mDefaultEng, currentActivityInfo.name);
223 this.startActivity(intent);
230 * Called when the TTS engine is initialized.
232 public void onInit(int status) {
233 if (status == TextToSpeech.SUCCESS) {
234 Log.v(TAG, "TTS engine for settings screen initialized.");
236 mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry));
237 mTts.setSpeechRate((float)(mDefaultRate/100.0f));
239 Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
247 * Called when voice data integrity check returns
249 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
250 if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
251 if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
252 Log.v(TAG, "Voice data check passed");
254 mTts = new TextToSpeech(this, this);
257 Log.v(TAG, "Voice data check failed");
265 public boolean onPreferenceChange(Preference preference, Object objValue) {
266 if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
268 int value = (Boolean)objValue ? 1 : 0;
269 Settings.Secure.putInt(getContentResolver(), TTS_USE_DEFAULTS,
271 Log.i(TAG, "TTS use default settings is "+objValue.toString());
272 } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
274 mDefaultRate = Integer.parseInt((String) objValue);
276 Settings.Secure.putInt(getContentResolver(),
277 TTS_DEFAULT_RATE, mDefaultRate);
279 mTts.setSpeechRate((float)(mDefaultRate/100.0f));
281 Log.i(TAG, "TTS default rate is " + mDefaultRate);
282 } catch (NumberFormatException e) {
283 Log.e(TAG, "could not persist default TTS rate setting", e);
285 } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
287 ContentResolver resolver = getContentResolver();
288 parseLocaleInfo((String) objValue);
289 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
290 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
291 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
292 Log.v(TAG, "TTS default lang/country/variant set to "
293 + mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
295 mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry));
297 int newIndex = mDefaultLocPref.findIndexOfValue((String)objValue);
298 Log.v("Settings", " selected is " + newIndex);
299 mDemoStringIndex = newIndex > -1 ? newIndex : 0;
307 * Called when mPlayExample or mInstallData is clicked
309 public boolean onPreferenceClick(Preference preference) {
310 if (preference == mPlayExample) {
313 mTts.speak(mDemoStrings[mDemoStringIndex], TextToSpeech.QUEUE_FLUSH, null);
317 if (preference == mInstallData) {
319 // quit this activity so it needs to be restarted after installation of the voice data
327 private void updateWidgetState() {
328 mPlayExample.setEnabled(mEnableDemo);
329 mUseDefaultPref.setEnabled(mEnableDemo);
330 mDefaultRatePref.setEnabled(mEnableDemo);
331 mDefaultLocPref.setEnabled(mEnableDemo);
333 mInstallData.setEnabled(!mEnableDemo);
337 private void parseLocaleInfo(String locale) {
338 StringTokenizer tokenizer = new StringTokenizer(locale, LOCALE_DELIMITER);
339 mDefaultLanguage = "";
340 mDefaultCountry = "";
341 mDefaultLocVariant = "";
342 if (tokenizer.hasMoreTokens()) {
343 mDefaultLanguage = tokenizer.nextToken().trim();
345 if (tokenizer.hasMoreTokens()) {
346 mDefaultCountry = tokenizer.nextToken().trim();
348 if (tokenizer.hasMoreTokens()) {
349 mDefaultLocVariant = tokenizer.nextToken().trim();
355 * Initialize the default language in the UI and in the preferences.
356 * After this method has been invoked, the default language is a supported Locale.
358 private void initDefaultLang() {
359 // if there isn't already a default language preference
360 if (!hasLangPref()) {
361 // if the current Locale is supported
362 if (isCurrentLocSupported()) {
363 // then use the current Locale as the default language
364 useCurrentLocAsDefault();
366 // otherwise use a default supported Locale as the default language
367 useSupportedLocAsDefault();
371 // Update the language preference list with the default language and the matching
372 // demo string (at this stage there is a default language pref)
373 ContentResolver resolver = getContentResolver();
374 mDefaultLanguage = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
375 mDefaultCountry = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
376 mDefaultLocVariant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
378 // update the demo string
379 mDemoStringIndex = mDefaultLocPref.findIndexOfValue(mDefaultLanguage + LOCALE_DELIMITER
381 mDefaultLocPref.setValueIndex(mDemoStringIndex);
385 * (helper function for initDefaultLang() )
386 * Returns whether there is a default language in the TTS settings.
388 private boolean hasLangPref() {
389 String language = Settings.Secure.getString(getContentResolver(), TTS_DEFAULT_LANG);
390 return (language != null);
394 * (helper function for initDefaultLang() )
395 * Returns whether the current Locale is supported by this Settings screen
397 private boolean isCurrentLocSupported() {
398 String currentLocID = Locale.getDefault().getISO3Language() + LOCALE_DELIMITER
399 + Locale.getDefault().getISO3Country();
400 return (mDefaultLocPref.findIndexOfValue(currentLocID) > -1);
404 * (helper function for initDefaultLang() )
405 * Sets the default language in TTS settings to be the current Locale.
406 * This should only be used after checking that the current Locale is supported.
408 private void useCurrentLocAsDefault() {
409 Locale currentLocale = Locale.getDefault();
410 ContentResolver resolver = getContentResolver();
411 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, currentLocale.getISO3Language());
412 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, currentLocale.getISO3Country());
413 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, currentLocale.getVariant());
417 * (helper function for initDefaultLang() )
418 * Sets the default language in TTS settings to be one known to be supported
420 private void useSupportedLocAsDefault() {
421 ContentResolver resolver = getContentResolver();
422 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, DEFAULT_LANG_VAL);
423 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, DEFAULT_COUNTRY_VAL);
424 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);