Home | History | Annotate | Download | only in tts
      1 package com.android.settings.tts;
      2 
      3 import android.speech.tts.TextToSpeech;
      4 import com.android.settings.R;
      5 import android.os.Bundle;
      6 import com.android.settings.SettingsPreferenceFragment;
      7 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
      8 import android.support.v7.preference.PreferenceCategory;
      9 import android.speech.tts.TtsEngines;
     10 import android.speech.tts.TextToSpeech.EngineInfo;
     11 import com.android.settings.SettingsActivity;
     12 import com.android.settings.tts.TtsEnginePreference.RadioButtonGroupState;
     13 import android.widget.Checkable;
     14 import android.util.Log;
     15 import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
     16 import com.android.settings.search.Indexable;
     17 import com.android.settings.search.BaseSearchIndexProvider;
     18 import android.content.Context;
     19 import android.provider.SearchIndexableResource;
     20 
     21 import java.util.List;
     22 import java.util.Arrays;
     23 
     24 public class TtsEnginePreferenceFragment extends SettingsPreferenceFragment //implements
     25         implements RadioButtonGroupState, Indexable {
     26     private static final String TAG = "TtsEnginePrefFragment";
     27 
     28     private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
     29 
     30     /** The currently selected engine. */
     31     private String mCurrentEngine;
     32 
     33     /**
     34      * The engine checkbox that is currently checked. Saves us a bit of effort in deducing the right
     35      * one from the currently selected engine.
     36      */
     37     private Checkable mCurrentChecked;
     38 
     39     /**
     40      * The previously selected TTS engine. Useful for rollbacks if the users choice is not loaded or
     41      * fails a voice integrity check.
     42      */
     43     private String mPreviousEngine;
     44 
     45     private PreferenceCategory mEnginePreferenceCategory;
     46 
     47     private TextToSpeech mTts = null;
     48     private TtsEngines mEnginesHelper = null;
     49 
     50     @Override
     51     public void onCreate(Bundle savedInstanceState) {
     52         super.onCreate(savedInstanceState);
     53         addPreferencesFromResource(R.xml.tts_engine_picker);
     54 
     55         mEnginePreferenceCategory =
     56                 (PreferenceCategory) findPreference("tts_engine_preference_category");
     57         mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
     58 
     59         mTts = new TextToSpeech(getActivity().getApplicationContext(), null);
     60 
     61         initSettings();
     62     }
     63 
     64     @Override
     65     public int getMetricsCategory() {
     66         return MetricsEvent.TTS_ENGINE_SETTINGS;
     67     }
     68 
     69     @Override
     70     public void onDestroy() {
     71         super.onDestroy();
     72         if (mTts != null) {
     73             mTts.shutdown();
     74             mTts = null;
     75         }
     76     }
     77 
     78     private void initSettings() {
     79         if (mTts != null) {
     80             mCurrentEngine = mTts.getCurrentEngine();
     81         }
     82 
     83         mEnginePreferenceCategory.removeAll();
     84 
     85         SettingsActivity activity = (SettingsActivity) getActivity();
     86 
     87         List<EngineInfo> engines = mEnginesHelper.getEngines();
     88         for (EngineInfo engine : engines) {
     89             TtsEnginePreference enginePref =
     90                     new TtsEnginePreference(getPrefContext(), engine, this, activity);
     91             mEnginePreferenceCategory.addPreference(enginePref);
     92         }
     93     }
     94 
     95     @Override
     96     public Checkable getCurrentChecked() {
     97         return mCurrentChecked;
     98     }
     99 
    100     @Override
    101     public String getCurrentKey() {
    102         return mCurrentEngine;
    103     }
    104 
    105     @Override
    106     public void setCurrentChecked(Checkable current) {
    107         mCurrentChecked = current;
    108     }
    109 
    110     /**
    111      * The initialization listener used when the user changes his choice of engine (as opposed to
    112      * when then screen is being initialized for the first time).
    113      */
    114     private final TextToSpeech.OnInitListener mUpdateListener =
    115             new TextToSpeech.OnInitListener() {
    116                 @Override
    117                 public void onInit(int status) {
    118                     onUpdateEngine(status);
    119                 }
    120             };
    121 
    122     private void updateDefaultEngine(String engine) {
    123         Log.d(TAG, "Updating default synth to : " + engine);
    124 
    125         // Keep track of the previous engine that was being used. So that
    126         // we can reuse the previous engine.
    127         //
    128         // Note that if TextToSpeech#getCurrentEngine is not null, it means at
    129         // the very least that we successfully bound to the engine service.
    130         mPreviousEngine = mTts.getCurrentEngine();
    131 
    132         // Step 1: Shut down the existing TTS engine.
    133         Log.i(TAG, "Shutting down current tts engine");
    134         if (mTts != null) {
    135             try {
    136                 mTts.shutdown();
    137                 mTts = null;
    138             } catch (Exception e) {
    139                 Log.e(TAG, "Error shutting down TTS engine" + e);
    140             }
    141         }
    142 
    143         // Step 2: Connect to the new TTS engine.
    144         // Step 3 is continued on #onUpdateEngine (below) which is called when
    145         // the app binds successfully to the engine.
    146         Log.i(TAG, "Updating engine : Attempting to connect to engine: " + engine);
    147         mTts = new TextToSpeech(getActivity().getApplicationContext(), mUpdateListener, engine);
    148         Log.i(TAG, "Success");
    149     }
    150 
    151     /**
    152      * Step 3: We have now bound to the TTS engine the user requested. We will attempt to check
    153      * voice data for the engine if we successfully bound to it, or revert to the previous engine if
    154      * we didn't.
    155      */
    156     public void onUpdateEngine(int status) {
    157         if (status == TextToSpeech.SUCCESS) {
    158             Log.d(
    159                     TAG,
    160                     "Updating engine: Successfully bound to the engine: "
    161                             + mTts.getCurrentEngine());
    162             android.provider.Settings.Secure.putString(
    163                     getContentResolver(), TTS_DEFAULT_SYNTH, mTts.getCurrentEngine());
    164         } else {
    165             Log.d(TAG, "Updating engine: Failed to bind to engine, reverting.");
    166             if (mPreviousEngine != null) {
    167                 // This is guaranteed to at least bind, since mPreviousEngine would be
    168                 // null if the previous bind to this engine failed.
    169                 mTts =
    170                         new TextToSpeech(
    171                                 getActivity().getApplicationContext(), null, mPreviousEngine);
    172             }
    173             mPreviousEngine = null;
    174         }
    175     }
    176 
    177     @Override
    178     public void setCurrentKey(String key) {
    179         mCurrentEngine = key;
    180         updateDefaultEngine(mCurrentEngine);
    181     }
    182 
    183     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    184             new BaseSearchIndexProvider() {
    185                 @Override
    186                 public List<SearchIndexableResource> getXmlResourcesToIndex(
    187                         Context context, boolean enabled) {
    188                     final SearchIndexableResource sir = new SearchIndexableResource(context);
    189                     sir.xmlResId = R.xml.tts_engine_picker;
    190                     return Arrays.asList(sir);
    191                 }
    192             };
    193 }
    194