/tts/src/com/google/tts/TextToSpeechSettings.java

http://eyes-free.googlecode.com/ · Java · 805 lines · 583 code · 98 blank · 124 comment · 130 complexity · adac0d6eaff65460139882601ec14d26 MD5 · raw file

  1. /*
  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. package com.google.tts;
  17. import android.app.AlertDialog;
  18. import android.content.ContentResolver;
  19. import android.content.DialogInterface;
  20. import android.content.Intent;
  21. import android.content.SharedPreferences;
  22. import android.content.SharedPreferences.Editor;
  23. import android.content.pm.ActivityInfo;
  24. import android.content.pm.PackageManager;
  25. import android.content.pm.ResolveInfo;
  26. import android.os.Bundle;
  27. import android.os.Environment;
  28. import android.preference.ListPreference;
  29. import android.preference.Preference;
  30. import android.preference.Preference.OnPreferenceClickListener;
  31. import android.preference.PreferenceActivity;
  32. import android.preference.PreferenceGroup;
  33. import android.preference.PreferenceManager;
  34. import android.preference.PreferenceScreen;
  35. import android.preference.CheckBoxPreference;
  36. import android.speech.tts.TextToSpeech;
  37. import android.util.Log;
  38. import java.util.ArrayList;
  39. import java.util.List;
  40. import java.util.Locale;
  41. import java.util.StringTokenizer;
  42. public class TextToSpeechSettings extends PreferenceActivity implements
  43. Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
  44. TextToSpeechBeta.OnInitListener {
  45. private static final String TAG = "TextToSpeechSettings";
  46. private static final String SYSTEM_TTS = "com.svox.pico";
  47. private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
  48. private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
  49. private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
  50. private static final String KEY_TTS_DEFAULT_RATE = "tts_default_rate";
  51. private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
  52. private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
  53. private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
  54. private static final String KEY_TTS_DEFAULT_SYNTH = "tts_default_synth";
  55. private static final String KEY_TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
  56. private static final String KEY_PLUGIN_ENABLED_PREFIX = "ENABLED_";
  57. private static final String KEY_PLUGIN_SETTINGS_PREFIX = "SETTINGS_";
  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 = "";
  62. private static final String LOCALE_DELIMITER = "-";
  63. private static final String FALLBACK_TTS_DEFAULT_SYNTH = TextToSpeechBeta.Engine.DEFAULT_SYNTH;
  64. private SharedPreferences prefs;
  65. private Editor prefsEditor;
  66. private Preference mPlayExample = null;
  67. private Preference mInstallData = null;
  68. private CheckBoxPreference mUseDefaultPref = null;
  69. private ListPreference mDefaultRatePref = null;
  70. private ListPreference mDefaultLocPref = null;
  71. private ListPreference mDefaultSynthPref = null;
  72. private String mDefaultLanguage = null;
  73. private String mDefaultCountry = null;
  74. private String mDefaultLocVariant = null;
  75. private String mDefaultEng = "";
  76. private int mDefaultRate = TextToSpeechBeta.Engine.DEFAULT_RATE;
  77. // Array of strings used to demonstrate TTS in the different languages.
  78. private String[] mDemoStrings;
  79. // Index of the current string to use for the demo.
  80. private int mDemoStringIndex = 0;
  81. private boolean mEnableDemo = false;
  82. private boolean mVoicesMissing = false;
  83. private TextToSpeechBeta mTts = null;
  84. private boolean mTtsStarted = false;
  85. /**
  86. * Request code (arbitrary value) for voice data check through
  87. * startActivityForResult.
  88. */
  89. private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
  90. private static final int GET_SAMPLE_TEXT = 1983;
  91. @Override
  92. protected void onCreate(Bundle savedInstanceState) {
  93. super.onCreate(savedInstanceState);
  94. prefs = PreferenceManager.getDefaultSharedPreferences(this);
  95. prefsEditor = prefs.edit();
  96. addPreferencesFromResource(R.xml.tts_settings);
  97. addEngineSpecificSettings();
  98. mDemoStrings = getResources().getStringArray(R.array.tts_demo_strings);
  99. setVolumeControlStream(TextToSpeechBeta.Engine.DEFAULT_STREAM);
  100. mEnableDemo = false;
  101. mTtsStarted = false;
  102. Locale currentLocale = Locale.getDefault();
  103. mDefaultLanguage = currentLocale.getISO3Language();
  104. mDefaultCountry = currentLocale.getISO3Country();
  105. mDefaultLocVariant = currentLocale.getVariant();
  106. mTts = new TextToSpeechBeta(this, this);
  107. }
  108. @Override
  109. protected void onPause() {
  110. super.onPause();
  111. if ((mDefaultRatePref != null) && (mDefaultRatePref.getDialog() != null)) {
  112. mDefaultRatePref.getDialog().dismiss();
  113. }
  114. if ((mDefaultLocPref != null) && (mDefaultLocPref.getDialog() != null)) {
  115. mDefaultLocPref.getDialog().dismiss();
  116. }
  117. if ((mDefaultSynthPref != null) && (mDefaultSynthPref.getDialog() != null)) {
  118. mDefaultSynthPref.getDialog().dismiss();
  119. }
  120. }
  121. @Override
  122. protected void onStart() {
  123. super.onStart();
  124. if (mTtsStarted) {
  125. // whenever we return to this screen, we don't know the state of the
  126. // system, so we have to recheck that we can play the demo, or it
  127. // must be disabled.
  128. // TODO make the TTS service listen to "changes in the system", i.e.
  129. // sd card un/mount
  130. initClickers();
  131. updateWidgetState();
  132. checkVoiceData();
  133. }
  134. }
  135. @Override
  136. protected void onDestroy() {
  137. super.onDestroy();
  138. if (mTts != null) {
  139. mTts.shutdown();
  140. }
  141. }
  142. private void addEngineSpecificSettings() {
  143. PreferenceGroup enginesCategory = (PreferenceGroup) findPreference("tts_engines_section");
  144. Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
  145. ResolveInfo[] enginesArray = new ResolveInfo[0];
  146. PackageManager pm = getPackageManager();
  147. enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
  148. for (int i = 0; i < enginesArray.length; i++) {
  149. String prefKey = "";
  150. final String pluginPackageName = enginesArray[i].activityInfo.packageName;
  151. if (!enginesArray[i].activityInfo.packageName.equals(SYSTEM_TTS)) {
  152. CheckBoxPreference chkbxPref = new CheckBoxPreference(this);
  153. prefKey = KEY_PLUGIN_ENABLED_PREFIX + pluginPackageName;
  154. chkbxPref.setKey(prefKey);
  155. chkbxPref.setTitle(enginesArray[i].loadLabel(pm));
  156. enginesCategory.addPreference(chkbxPref);
  157. }
  158. if (pluginHasSettings(pluginPackageName)) {
  159. Preference pref = new Preference(this);
  160. prefKey = KEY_PLUGIN_SETTINGS_PREFIX + pluginPackageName;
  161. pref.setKey(prefKey);
  162. pref.setTitle(enginesArray[i].loadLabel(pm));
  163. CharSequence settingsLabel = getResources().getString(
  164. R.string.tts_engine_name_settings, enginesArray[i].loadLabel(pm));
  165. pref.setSummary(settingsLabel);
  166. pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
  167. public boolean onPreferenceClick(Preference preference) {
  168. Intent i = new Intent();
  169. i.setClassName(pluginPackageName, pluginPackageName + ".EngineSettings");
  170. startActivity(i);
  171. return true;
  172. }
  173. });
  174. enginesCategory.addPreference(pref);
  175. }
  176. }
  177. }
  178. private boolean pluginHasSettings(String pluginPackageName) {
  179. PackageManager pm = getPackageManager();
  180. Intent i = new Intent();
  181. i.setClassName(pluginPackageName, pluginPackageName + ".EngineSettings");
  182. if (pm.resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY) != null) {
  183. return true;
  184. }
  185. return false;
  186. }
  187. private void initClickers() {
  188. mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
  189. mPlayExample.setOnPreferenceClickListener(this);
  190. mInstallData = findPreference(KEY_TTS_INSTALL_DATA);
  191. mInstallData.setOnPreferenceClickListener(this);
  192. }
  193. private void initDefaultSettings() {
  194. ContentResolver resolver = getContentResolver();
  195. // Find the default TTS values in the settings, initialize and store the
  196. // settings if they are not found.
  197. // "Use Defaults"
  198. int useDefault = 0;
  199. mUseDefaultPref = (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
  200. useDefault = prefs.getInt(KEY_TTS_USE_DEFAULT, TextToSpeechBeta.Engine.USE_DEFAULTS);
  201. mUseDefaultPref.setChecked(useDefault == 1);
  202. mUseDefaultPref.setOnPreferenceChangeListener(this);
  203. // Default synthesis engine
  204. mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
  205. loadEngines();
  206. mDefaultSynthPref.setOnPreferenceChangeListener(this);
  207. String engine = prefs.getString(KEY_TTS_DEFAULT_SYNTH, FALLBACK_TTS_DEFAULT_SYNTH);
  208. mDefaultEng = engine;
  209. // Default rate
  210. mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
  211. mDefaultRate = prefs.getInt(KEY_TTS_DEFAULT_RATE, mDefaultRate);
  212. mDefaultRatePref.setValue(String.valueOf(mDefaultRate));
  213. mDefaultRatePref.setOnPreferenceChangeListener(this);
  214. // Default language / country / variant : these three values map to a
  215. // single ListPref
  216. // representing the matching Locale
  217. mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
  218. initDefaultLang();
  219. mDefaultLocPref.setOnPreferenceChangeListener(this);
  220. }
  221. /**
  222. * Ask the current default engine to launch the matching CHECK_TTS_DATA
  223. * activity to check the required TTS files are properly installed.
  224. */
  225. private void checkVoiceData() {
  226. PackageManager pm = getPackageManager();
  227. Intent intent = new Intent();
  228. intent.setAction(TextToSpeechBeta.Engine.ACTION_CHECK_TTS_DATA);
  229. List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
  230. // query only the package that matches that of the default engine
  231. for (int i = 0; i < resolveInfos.size(); i++) {
  232. ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
  233. if (mDefaultEng.equals(currentActivityInfo.packageName)) {
  234. intent.setClassName(mDefaultEng, currentActivityInfo.name);
  235. this.startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
  236. }
  237. }
  238. }
  239. /**
  240. * Ask the current default engine to launch the matching INSTALL_TTS_DATA
  241. * activity so the required TTS files are properly installed.
  242. */
  243. private void installVoiceData() {
  244. PackageManager pm = getPackageManager();
  245. Intent intent = new Intent();
  246. intent.setAction(TextToSpeechBeta.Engine.ACTION_INSTALL_TTS_DATA);
  247. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  248. List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
  249. // query only the package that matches that of the default engine
  250. for (int i = 0; i < resolveInfos.size(); i++) {
  251. ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
  252. if (mDefaultEng.equals(currentActivityInfo.packageName)) {
  253. intent.setClassName(mDefaultEng, currentActivityInfo.name);
  254. this.startActivity(intent);
  255. }
  256. }
  257. }
  258. /**
  259. * Ask the current default engine to return a string of sample text to be
  260. * spoken to the user.
  261. */
  262. private void getSampleText() {
  263. PackageManager pm = getPackageManager();
  264. Intent intent = new Intent();
  265. // TODO (clchen): Replace Intent string with the actual
  266. // Intent defined in the list of platform Intents.
  267. intent.setAction("android.speech.tts.engine.GET_SAMPLE_TEXT");
  268. intent.putExtra("language", mDefaultLanguage);
  269. intent.putExtra("country", mDefaultCountry);
  270. intent.putExtra("variant", mDefaultLocVariant);
  271. List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
  272. // query only the package that matches that of the default engine
  273. for (int i = 0; i < resolveInfos.size(); i++) {
  274. ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
  275. if (mDefaultEng.equals(currentActivityInfo.packageName)) {
  276. intent.setClassName(mDefaultEng, currentActivityInfo.name);
  277. this.startActivityForResult(intent, GET_SAMPLE_TEXT);
  278. }
  279. }
  280. // -- Only needed in TTS Extended to deal with pre-Froyo system Pico
  281. // The version of Pico built into the system for versions 4-7 of Android
  282. // does not return all the information needed by TTS Extended.
  283. // Compensate for that here by adding in the missing bits.
  284. if (mDefaultEng.equals(SYSTEM_TTS) && (Integer.parseInt(android.os.Build.VERSION.SDK) < 8)
  285. && (Integer.parseInt(android.os.Build.VERSION.SDK) > 3)) {
  286. intent.setClassName("com.google.tts", "com.google.tts.GetSampleText");
  287. this.startActivityForResult(intent, GET_SAMPLE_TEXT);
  288. }
  289. // -- End of workaround for pre-Froyo system Pico
  290. }
  291. /**
  292. * Called when the TTS engine is initialized.
  293. */
  294. public void onInit(int status, int version) {
  295. if (status == TextToSpeech.SUCCESS) {
  296. mEnableDemo = true;
  297. if (mDefaultLanguage == null) {
  298. mDefaultLanguage = Locale.getDefault().getISO3Language();
  299. }
  300. if (mDefaultCountry == null) {
  301. mDefaultCountry = Locale.getDefault().getISO3Country();
  302. }
  303. if (mDefaultLocVariant == null) {
  304. mDefaultLocVariant = new String();
  305. }
  306. initDefaultSettings();
  307. mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
  308. mTts.setSpeechRate((mDefaultRate / 100.0f));
  309. mTts.setEngineByPackageNameExtended(mDefaultEng);
  310. initClickers();
  311. updateWidgetState();
  312. checkVoiceData();
  313. mTtsStarted = true;
  314. Log.v(TAG, "TTS engine for settings screen initialized.");
  315. } else {
  316. Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
  317. mEnableDemo = false;
  318. }
  319. updateWidgetState();
  320. }
  321. /**
  322. * Called when voice data integrity check returns
  323. */
  324. @Override
  325. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  326. if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
  327. if (data == null) {
  328. // The CHECK_TTS_DATA activity for the plugin did not run
  329. // properly;
  330. // disable the preview and install controls and return.
  331. mEnableDemo = false;
  332. mVoicesMissing = false;
  333. updateWidgetState();
  334. return;
  335. }
  336. // TODO (clchen): Add these extras to TextToSpeech.Engine
  337. ArrayList<String> available = data.getStringArrayListExtra("availableVoices");
  338. ArrayList<String> unavailable = data.getStringArrayListExtra("unavailableVoices");
  339. // -- Only needed in TTS Extended to deal with pre-Froyo system Pico
  340. // The version of Pico built into the system for versions 4-7 of
  341. // Android
  342. // does not return all the information needed by TTS Extended.
  343. // Compensate for that here by adding in the missing bits.
  344. if (mDefaultEng.equals(SYSTEM_TTS)
  345. && (Integer.parseInt(android.os.Build.VERSION.SDK) < 8)
  346. && (Integer.parseInt(android.os.Build.VERSION.SDK) > 3)) {
  347. available = new ArrayList<String>();
  348. unavailable = new ArrayList<String>();
  349. if (resultCode < 0) {
  350. unavailable.add("deu-DEU");
  351. unavailable.add("eng-GBR");
  352. unavailable.add("eng-USA");
  353. unavailable.add("spa-ESP");
  354. unavailable.add("fra-FRA");
  355. unavailable.add("ita-ITA");
  356. } else {
  357. available.add("deu-DEU");
  358. available.add("eng-GBR");
  359. available.add("eng-USA");
  360. available.add("spa-ESP");
  361. available.add("fra-FRA");
  362. available.add("ita-ITA");
  363. }
  364. }
  365. // -- End of workaround for pre-Froyo system Pico
  366. if ((available == null) || (unavailable == null)) {
  367. // The CHECK_TTS_DATA activity for the plugin did not run
  368. // properly;
  369. // disable the preview and install controls and return.
  370. mEnableDemo = false;
  371. mVoicesMissing = false;
  372. updateWidgetState();
  373. return;
  374. }
  375. if (available.size() > 0) {
  376. if (mTts == null) {
  377. mTts = new TextToSpeechBeta(this, this);
  378. }
  379. ListPreference ttsLanguagePref = (ListPreference) findPreference("tts_default_lang");
  380. CharSequence[] entries = new CharSequence[available.size()];
  381. CharSequence[] entryValues = new CharSequence[available.size()];
  382. int selectedLanguageIndex = -1;
  383. String selectedLanguagePref = mDefaultLanguage;
  384. if (mDefaultCountry.length() > 0) {
  385. selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER
  386. + mDefaultCountry;
  387. }
  388. if (mDefaultLocVariant.length() > 0) {
  389. selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER
  390. + mDefaultLocVariant;
  391. }
  392. for (int i = 0; i < available.size(); i++) {
  393. String[] langCountryVariant = available.get(i).split("-");
  394. Locale loc = null;
  395. if (langCountryVariant.length == 1) {
  396. loc = new Locale(langCountryVariant[0]);
  397. } else if (langCountryVariant.length == 2) {
  398. loc = new Locale(langCountryVariant[0], langCountryVariant[1]);
  399. } else if (langCountryVariant.length == 3) {
  400. loc = new Locale(langCountryVariant[0], langCountryVariant[1],
  401. langCountryVariant[2]);
  402. }
  403. if (loc != null) {
  404. entries[i] = loc.getDisplayName();
  405. entryValues[i] = available.get(i);
  406. if (entryValues[i].equals(selectedLanguagePref)) {
  407. selectedLanguageIndex = i;
  408. }
  409. }
  410. }
  411. ttsLanguagePref.setEntries(entries);
  412. ttsLanguagePref.setEntryValues(entryValues);
  413. if (selectedLanguageIndex > -1) {
  414. ttsLanguagePref.setValueIndex(selectedLanguageIndex);
  415. }
  416. mEnableDemo = true;
  417. // Make sure that the default language can be used.
  418. int languageResult = mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry,
  419. mDefaultLocVariant));
  420. if (languageResult < TextToSpeech.LANG_AVAILABLE) {
  421. Locale currentLocale = Locale.getDefault();
  422. mDefaultLanguage = currentLocale.getISO3Language();
  423. mDefaultCountry = currentLocale.getISO3Country();
  424. mDefaultLocVariant = currentLocale.getVariant();
  425. languageResult = mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry,
  426. mDefaultLocVariant));
  427. // If the default Locale isn't supported, just choose the
  428. // first available
  429. // language so that there is at least something.
  430. if (languageResult < TextToSpeech.LANG_AVAILABLE) {
  431. parseLocaleInfo(ttsLanguagePref.getEntryValues()[0].toString());
  432. mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry,
  433. mDefaultLocVariant));
  434. }
  435. prefsEditor.putString(KEY_TTS_DEFAULT_LANG, mDefaultLanguage);
  436. prefsEditor.putString(KEY_TTS_DEFAULT_COUNTRY, mDefaultCountry);
  437. prefsEditor.putString(KEY_TTS_DEFAULT_VARIANT, mDefaultLocVariant);
  438. prefsEditor.commit();
  439. }
  440. } else {
  441. mEnableDemo = false;
  442. }
  443. if (unavailable.size() > 0) {
  444. mVoicesMissing = true;
  445. } else {
  446. mVoicesMissing = false;
  447. }
  448. updateWidgetState();
  449. } else if (requestCode == GET_SAMPLE_TEXT) {
  450. if (resultCode == TextToSpeech.LANG_AVAILABLE) {
  451. String sample = getString(R.string.tts_demo);
  452. if ((data != null) && (data.getStringExtra("sampleText") != null)) {
  453. sample = data.getStringExtra("sampleText");
  454. }
  455. if (mTts != null) {
  456. mTts.speak(sample, TextToSpeech.QUEUE_FLUSH, null);
  457. }
  458. } else {
  459. // TODO: Display an error here to the user.
  460. Log.e(TAG, "Did not have a sample string for the requested language");
  461. }
  462. }
  463. }
  464. public boolean onPreferenceChange(Preference preference, Object objValue) {
  465. if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
  466. // "Use Defaults"
  467. int value = (Boolean) objValue ? 1 : 0;
  468. prefsEditor.putInt(KEY_TTS_USE_DEFAULT, value);
  469. prefsEditor.commit();
  470. Log.i(TAG, "TTS use default settings is " + objValue.toString());
  471. } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
  472. // Default rate
  473. mDefaultRate = Integer.parseInt((String) objValue);
  474. try {
  475. prefsEditor.putInt(KEY_TTS_DEFAULT_RATE, mDefaultRate);
  476. prefsEditor.commit();
  477. if (mTts != null) {
  478. mTts.setSpeechRate((mDefaultRate / 100.0f));
  479. }
  480. Log.i(TAG, "TTS default rate is " + mDefaultRate);
  481. } catch (NumberFormatException e) {
  482. Log.e(TAG, "could not persist default TTS rate setting", e);
  483. }
  484. } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
  485. // Default locale
  486. ContentResolver resolver = getContentResolver();
  487. parseLocaleInfo((String) objValue);
  488. prefsEditor.putString(KEY_TTS_DEFAULT_LANG, mDefaultLanguage);
  489. prefsEditor.putString(KEY_TTS_DEFAULT_COUNTRY, mDefaultCountry);
  490. prefsEditor.putString(KEY_TTS_DEFAULT_VARIANT, mDefaultLocVariant);
  491. prefsEditor.commit();
  492. Log.v(TAG, "TTS default lang/country/variant set to " + mDefaultLanguage + "/"
  493. + mDefaultCountry + "/" + mDefaultLocVariant);
  494. if (mTts != null) {
  495. mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
  496. }
  497. int newIndex = mDefaultLocPref.findIndexOfValue((String) objValue);
  498. Log.v("Settings", " selected is " + newIndex);
  499. mDemoStringIndex = newIndex > -1 ? newIndex : 0;
  500. } else if (KEY_TTS_DEFAULT_SYNTH.equals(preference.getKey())) {
  501. mDefaultEng = objValue.toString();
  502. prefsEditor.putString(KEY_TTS_DEFAULT_SYNTH, mDefaultEng);
  503. prefsEditor.commit();
  504. if (mTts != null) {
  505. mTts.setEngineByPackageNameExtended(mDefaultEng);
  506. mEnableDemo = false;
  507. mVoicesMissing = false;
  508. updateWidgetState();
  509. checkVoiceData();
  510. }
  511. Log.v("Settings", "The default synth is: " + objValue.toString());
  512. }
  513. return true;
  514. }
  515. /**
  516. * Called when mPlayExample or mInstallData is clicked
  517. */
  518. public boolean onPreferenceClick(Preference preference) {
  519. if (preference == mPlayExample) {
  520. // Get the sample text from the TTS engine; onActivityResult will do
  521. // the actual speaking
  522. getSampleText();
  523. return true;
  524. }
  525. if (preference == mInstallData) {
  526. installVoiceData();
  527. // quit this activity so it needs to be restarted after installation
  528. // of the voice data
  529. finish();
  530. return true;
  531. }
  532. return false;
  533. }
  534. @Override
  535. public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
  536. if (preference instanceof CheckBoxPreference) {
  537. final CheckBoxPreference chkPref = (CheckBoxPreference) preference;
  538. if (!chkPref.getKey().equals(KEY_TTS_USE_DEFAULT)) {
  539. if (chkPref.isChecked()) {
  540. chkPref.setChecked(false);
  541. AlertDialog d = (new AlertDialog.Builder(this)).setTitle(
  542. android.R.string.dialog_alert_title).setIcon(
  543. android.R.drawable.ic_dialog_alert).setMessage(
  544. getString(R.string.tts_engine_security_warning, chkPref.getTitle()))
  545. .setCancelable(true).setPositiveButton(android.R.string.ok,
  546. new DialogInterface.OnClickListener() {
  547. public void onClick(DialogInterface dialog, int which) {
  548. chkPref.setChecked(true);
  549. loadEngines();
  550. }
  551. }).setNegativeButton(android.R.string.cancel,
  552. new DialogInterface.OnClickListener() {
  553. public void onClick(DialogInterface dialog, int which) {
  554. }
  555. }).create();
  556. d.show();
  557. } else {
  558. loadEngines();
  559. }
  560. return true;
  561. }
  562. }
  563. return false;
  564. }
  565. private void updateWidgetState() {
  566. mPlayExample.setEnabled(mEnableDemo);
  567. mUseDefaultPref.setEnabled(mEnableDemo);
  568. mDefaultRatePref.setEnabled(mEnableDemo);
  569. mDefaultLocPref.setEnabled(mEnableDemo);
  570. mInstallData.setEnabled(mVoicesMissing);
  571. }
  572. private void parseLocaleInfo(String locale) {
  573. StringTokenizer tokenizer = new StringTokenizer(locale, LOCALE_DELIMITER);
  574. mDefaultLanguage = "";
  575. mDefaultCountry = "";
  576. mDefaultLocVariant = "";
  577. if (tokenizer.hasMoreTokens()) {
  578. mDefaultLanguage = tokenizer.nextToken().trim();
  579. }
  580. if (tokenizer.hasMoreTokens()) {
  581. mDefaultCountry = tokenizer.nextToken().trim();
  582. }
  583. if (tokenizer.hasMoreTokens()) {
  584. mDefaultLocVariant = tokenizer.nextToken().trim();
  585. }
  586. }
  587. /**
  588. * Initialize the default language in the UI and in the preferences. After
  589. * this method has been invoked, the default language is a supported Locale.
  590. */
  591. private void initDefaultLang() {
  592. // if there isn't already a default language preference
  593. if (!hasLangPref()) {
  594. // if the current Locale is supported
  595. if (isCurrentLocSupported()) {
  596. // then use the current Locale as the default language
  597. useCurrentLocAsDefault();
  598. } else {
  599. // otherwise use a default supported Locale as the default
  600. // language
  601. useSupportedLocAsDefault();
  602. }
  603. }
  604. // Update the language preference list with the default language and the
  605. // matching
  606. // demo string (at this stage there is a default language pref)
  607. mDefaultLanguage = prefs.getString(KEY_TTS_DEFAULT_LANG, DEFAULT_LANG_VAL);
  608. mDefaultCountry = prefs.getString(KEY_TTS_DEFAULT_COUNTRY, DEFAULT_COUNTRY_VAL);
  609. mDefaultLocVariant = prefs.getString(KEY_TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);
  610. // update the demo string
  611. mDemoStringIndex = mDefaultLocPref.findIndexOfValue(mDefaultLanguage + LOCALE_DELIMITER
  612. + mDefaultCountry);
  613. if (mDemoStringIndex > -1) {
  614. mDefaultLocPref.setValueIndex(mDemoStringIndex);
  615. }
  616. }
  617. /**
  618. * (helper function for initDefaultLang() ) Returns whether there is a
  619. * default language in the TTS settings.
  620. */
  621. private boolean hasLangPref() {
  622. String language = prefs.getString(KEY_TTS_DEFAULT_LANG, null);
  623. if ((language == null) || (language.length() < 1)) {
  624. return false;
  625. }
  626. String country = prefs.getString(KEY_TTS_DEFAULT_COUNTRY, null);
  627. if (country == null) {
  628. return false;
  629. }
  630. String variant = prefs.getString(KEY_TTS_DEFAULT_VARIANT, null);
  631. if (variant == null) {
  632. return false;
  633. }
  634. return true;
  635. }
  636. /**
  637. * (helper function for initDefaultLang() ) Returns whether the current
  638. * Locale is supported by this Settings screen
  639. */
  640. private boolean isCurrentLocSupported() {
  641. String currentLocID = Locale.getDefault().getISO3Language() + LOCALE_DELIMITER
  642. + Locale.getDefault().getISO3Country();
  643. return (mDefaultLocPref.findIndexOfValue(currentLocID) > -1);
  644. }
  645. /**
  646. * (helper function for initDefaultLang() ) Sets the default language in TTS
  647. * settings to be the current Locale. This should only be used after
  648. * checking that the current Locale is supported.
  649. */
  650. private void useCurrentLocAsDefault() {
  651. Locale currentLocale = Locale.getDefault();
  652. prefsEditor.putString(KEY_TTS_DEFAULT_LANG, currentLocale.getISO3Language());
  653. prefsEditor.putString(KEY_TTS_DEFAULT_COUNTRY, currentLocale.getISO3Country());
  654. prefsEditor.putString(KEY_TTS_DEFAULT_VARIANT, currentLocale.getVariant());
  655. prefsEditor.commit();
  656. }
  657. /**
  658. * (helper function for initDefaultLang() ) Sets the default language in TTS
  659. * settings to be one known to be supported
  660. */
  661. private void useSupportedLocAsDefault() {
  662. prefsEditor.putString(KEY_TTS_DEFAULT_LANG, DEFAULT_LANG_VAL);
  663. prefsEditor.putString(KEY_TTS_DEFAULT_COUNTRY, DEFAULT_COUNTRY_VAL);
  664. prefsEditor.putString(KEY_TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);
  665. prefsEditor.commit();
  666. }
  667. private void loadEngines() {
  668. mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
  669. // TODO (clchen): Try to see if it is possible to be more efficient here
  670. // and not search for plugins again.
  671. Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
  672. ResolveInfo[] enginesArray = new ResolveInfo[0];
  673. PackageManager pm = getPackageManager();
  674. enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
  675. ArrayList<CharSequence> entries = new ArrayList<CharSequence>();
  676. ArrayList<CharSequence> values = new ArrayList<CharSequence>();
  677. String enabledEngines = "";
  678. for (int i = 0; i < enginesArray.length; i++) {
  679. String pluginPackageName = enginesArray[i].activityInfo.packageName;
  680. if (pluginPackageName.equals(SYSTEM_TTS)) {
  681. entries.add(enginesArray[i].loadLabel(pm));
  682. values.add(pluginPackageName);
  683. } else {
  684. CheckBoxPreference pref = (CheckBoxPreference) findPreference(KEY_PLUGIN_ENABLED_PREFIX
  685. + pluginPackageName);
  686. if ((pref != null) && pref.isChecked()) {
  687. entries.add(enginesArray[i].loadLabel(pm));
  688. values.add(pluginPackageName);
  689. enabledEngines = enabledEngines + pluginPackageName + " ";
  690. }
  691. }
  692. }
  693. prefsEditor.putString(KEY_TTS_ENABLED_PLUGINS, enabledEngines);
  694. prefsEditor.commit();
  695. CharSequence entriesArray[] = new CharSequence[entries.size()];
  696. CharSequence valuesArray[] = new CharSequence[values.size()];
  697. mDefaultSynthPref.setEntries(entries.toArray(entriesArray));
  698. mDefaultSynthPref.setEntryValues(values.toArray(valuesArray));
  699. // Set the selected engine based on the saved preference
  700. String selectedEngine = prefs.getString(KEY_TTS_DEFAULT_SYNTH, FALLBACK_TTS_DEFAULT_SYNTH);
  701. int selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(selectedEngine);
  702. if (selectedEngineIndex == -1) {
  703. selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(SYSTEM_TTS);
  704. }
  705. mDefaultSynthPref.setValueIndex(selectedEngineIndex);
  706. }
  707. }