blob: 94b256f62906e01be787ac50f52cd44774e40013 [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;
Jean-Michel Trivi80368622009-06-09 19:29:27 -070021import static android.provider.Settings.Secure.TTS_DEFAULT_LANG;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070022import static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
23import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -070024import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
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";
Jean-Michel Trivi80368622009-06-09 19:29:27 -070054 private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070055 private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
56 private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
57
58 private static final String LOCALE_DELIMITER = "-";
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070059
60 // TODO move this to android.speech.tts.TextToSpeech.Engine
61 private static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
62
63 private Preference mPlayExample = null;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070064 private Preference mInstallData = null;
Jean-Michel Trivied29a652009-06-05 18:37:29 -070065 private CheckBoxPreference mUseDefaultPref = null;
66 private ListPreference mDefaultRatePref = null;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070067 private ListPreference mDefaultLocPref = null;
68 private String mDefaultLanguage = null;
69 private String mDefaultCountry = null;
70 private String mDefaultLocVariant = null;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070071 private String mDefaultEng = "";
72
73 private boolean mEnableDemo = false;
74
75 private TextToSpeech mTts = null;
76
77 /**
78 * Request code (arbitrary value) for voice data check through
79 * startActivityForResult.
80 */
81 private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -070082 /**
83 * Request code (arbitrary value) for voice data installation through
84 * startActivityForResult.
85 */
86 private static final int VOICE_DATA_INSTALLATION = 1980;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070087
Jean-Michel Trivied29a652009-06-05 18:37:29 -070088 @Override
89 protected void onCreate(Bundle savedInstanceState) {
90 super.onCreate(savedInstanceState);
91
92 addPreferencesFromResource(R.xml.tts_settings);
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070093
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -070094 mEnableDemo = false;
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -070095 initClickers();
Jean-Michel Trivied29a652009-06-05 18:37:29 -070096 initDefaultSettings();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -070097 }
98
99
100 @Override
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700101 protected void onStart() {
102 super.onStart();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700103 // whenever we return to this screen, we don't know the state of the
104 // 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 -0700105 // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700106 initClickers();
107 updateWidgetState();
108 checkVoiceData();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700109 }
110
111
112 @Override
113 protected void onDestroy() {
114 super.onDestroy();
115 if (mTts != null) {
116 mTts.shutdown();
117 }
118 }
119
120
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700121 private void initClickers() {
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700122 mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700123 mPlayExample.setOnPreferenceClickListener(this);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700124
125 mInstallData = findPreference(KEY_TTS_INSTALL_DATA);
126 mInstallData.setOnPreferenceClickListener(this);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700127 }
128
129
130 private void initDefaultSettings() {
131 ContentResolver resolver = getContentResolver();
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700132 int intVal = 0;
133
134 // Find the default TTS values in the settings, initialize and store the
135 // settings if they are not found.
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700136
137 // "Use Defaults"
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700138 mUseDefaultPref = (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
139 try {
140 intVal = Settings.Secure.getInt(resolver, TTS_USE_DEFAULTS);
141 } catch (SettingNotFoundException e) {
142 // "use default" setting not found, initialize it
143 intVal = TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS;
144 Settings.Secure.putInt(resolver, TTS_USE_DEFAULTS, intVal);
145 }
146 mUseDefaultPref.setChecked(intVal == 1);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700147 mUseDefaultPref.setOnPreferenceChangeListener(this);
148
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700149 // Default engine
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700150 String engine = Settings.Secure.getString(resolver, TTS_DEFAULT_SYNTH);
151 if (engine == null) {
152 // TODO move FALLBACK_TTS_DEFAULT_SYNTH to TextToSpeech
153 engine = FALLBACK_TTS_DEFAULT_SYNTH;
154 Settings.Secure.putString(resolver, TTS_DEFAULT_SYNTH, engine);
155 }
156 mDefaultEng = engine;
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700157
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700158 // Default rate
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700159 mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
160 try {
161 intVal = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
162 } catch (SettingNotFoundException e) {
163 // default rate setting not found, initialize it
164 intVal = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE;
165 Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, intVal);
166 }
167 mDefaultRatePref.setValue(String.valueOf(intVal));
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700168 mDefaultRatePref.setOnPreferenceChangeListener(this);
169
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700170 // Default language / country / variant : these three values map to a single ListPref
171 // representing the matching Locale
172 String language = null;
173 String country = null;
174 String variant = null;
175 mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700176 language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700177 if (language != null) {
178 mDefaultLanguage = language;
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700179 } else {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700180 // default language setting not found, initialize it, as well as the country and variant
181 language = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
182 country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
183 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700184 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, language);
185 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
186 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700187 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700188 if (country == null) {
189 // country wasn't initialized yet because a default language was found
190 country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
191 if (country.compareTo("null") != 0) {
192 mDefaultCountry = country;
193 } else {
194 // default country setting not found, initialize it, as well as the variant;
195 country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
196 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700197 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
198 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700199 }
200 }
201 if (variant == null) {
202 // variant wasn't initialized yet because a default country was found
203 variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
204 if (variant.compareTo("null") != 0) {
205 mDefaultLocVariant = variant;
206 } else {
207 // default variant setting not found, initialize it
208 variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700209 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700210 }
211 }
212 // we now have the default lang/country/variant trio, build a string value from it
213 String localeString = new String(language);
214 if (country.compareTo("") != 0) {
215 localeString += LOCALE_DELIMITER + country;
216 } else {
217 localeString += LOCALE_DELIMITER + " ";
218 }
219 if (variant.compareTo("") != 0) {
220 localeString += LOCALE_DELIMITER + variant;
221 }
222 Log.v(TAG, "In initDefaultSettings: localeString=" + localeString);
223 // TODO handle the case where localeString isn't in the existing entries
224 mDefaultLocPref.setValue(localeString);
225 mDefaultLocPref.setOnPreferenceChangeListener(this);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700226 }
227
228
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700229 /**
230 * Ask the current default engine to launch the matching CHECK_TTS_DATA activity
231 * to check the required TTS files are properly installed.
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 /**
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700250 * Ask the current default engine to launch the matching INSTALL_TTS_DATA activity
251 * so the required TTS files are properly installed.
252 */
253 private void installVoiceData() {
254 PackageManager pm = getPackageManager();
255 Intent intent = new Intent();
256 intent.setAction("android.intent.action.INSTALL_TTS_DATA");
257 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
258 // query only the package that matches that of the default engine
259 for (int i = 0; i < resolveInfos.size(); i++) {
260 ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
261 if (mDefaultEng.equals(currentActivityInfo.packageName)) {
262 intent.setClassName(mDefaultEng, currentActivityInfo.name);
263 this.startActivityForResult(intent, VOICE_DATA_INSTALLATION);
264 }
265 }
266 }
267
268
269 /**
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700270 * Called when the TTS engine is initialized.
271 */
272 public void onInit(int status) {
273 if (status == TextToSpeech.TTS_SUCCESS) {
274 Log.v(TAG, "TTS engine for settings screen initialized.");
275 mEnableDemo = true;
276 } else {
277 Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
278 mEnableDemo = false;
279 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700280 updateWidgetState();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700281 }
282
283
284 /**
285 * Called when voice data integrity check returns
286 */
287 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
288 if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
289 if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
290 Log.v(TAG, "Voice data check passed");
291 if (mTts == null) {
292 mTts = new TextToSpeech(this, this);
293 }
294 } else {
295 Log.v(TAG, "Voice data check failed");
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700296 mEnableDemo = false;
297 updateWidgetState();
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700298 }
299 }
300 }
301
302
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700303 public boolean onPreferenceChange(Preference preference, Object objValue) {
304 if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
305 // "Use Defaults"
306 int value = (Boolean)objValue ? 1 : 0;
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700307 Settings.Secure.putInt(getContentResolver(), TTS_USE_DEFAULTS,
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700308 value);
309 Log.i(TAG, "TTS use default settings is "+objValue.toString());
310 } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
311 // Default rate
312 int value = Integer.parseInt((String) objValue);
313 try {
Jean-Michel Trivi80368622009-06-09 19:29:27 -0700314 Settings.Secure.putInt(getContentResolver(),
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700315 TTS_DEFAULT_RATE, value);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700316 if (mTts != null) {
317 mTts.setSpeechRate(value);
318 }
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700319 Log.i(TAG, "TTS default rate is "+value);
320 } catch (NumberFormatException e) {
321 Log.e(TAG, "could not persist default TTS rate setting", e);
322 }
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700323 } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700324 // Default locale
325 ContentResolver resolver = getContentResolver();
326 parseLocaleInfo((String) objValue);
327 Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
328 Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
329 Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
330 Log.v(TAG, "TTS default lang/country/variant set to "
331 + mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700332 }
333
334 return true;
335 }
336
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700337
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700338 /**
339 * Called when mPlayExample or mInstallData is clicked
340 */
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700341 public boolean onPreferenceClick(Preference preference) {
342 if (preference == mPlayExample) {
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700343 // Play example
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700344 if (mTts != null) {
345 mTts.speak(getResources().getString(R.string.tts_demo),
346 TextToSpeech.TTS_QUEUE_FLUSH, null);
347 }
348 return true;
349 }
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700350 if (preference == mInstallData) {
Jean-Michel Trivi2acc02e2009-06-25 10:03:43 -0700351 installVoiceData();
352 // quit this activity so it needs to be restarted after installation of the voice data
353 finish();
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700354 return true;
355 }
Jean-Michel Trivi74e565d2009-06-18 18:44:52 -0700356 return false;
357 }
358
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700359
360 private void updateWidgetState() {
361 mPlayExample.setEnabled(mEnableDemo);
362 mUseDefaultPref.setEnabled(mEnableDemo);
363 mDefaultRatePref.setEnabled(mEnableDemo);
Jean-Michel Trivi1e6a45a2009-06-22 16:03:40 -0700364 mDefaultLocPref.setEnabled(mEnableDemo);
365
366 mInstallData.setEnabled(!mEnableDemo);
367 }
368
369
370 private void parseLocaleInfo(String locale) {
371 StringTokenizer tokenizer = new StringTokenizer(locale, LOCALE_DELIMITER);
372 mDefaultLanguage = "";
373 mDefaultCountry = "";
374 mDefaultLocVariant = "";
375 if (tokenizer.hasMoreTokens()) {
376 mDefaultLanguage = tokenizer.nextToken().trim();
377 }
378 if (tokenizer.hasMoreTokens()) {
379 mDefaultCountry = tokenizer.nextToken().trim();
380 }
381 if (tokenizer.hasMoreTokens()) {
382 mDefaultLocVariant = tokenizer.nextToken().trim();
383 }
384 }
385
386
Jean-Michel Trivied29a652009-06-05 18:37:29 -0700387}