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