PageRenderTime 79ms CodeModel.GetById 33ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 1ms

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