eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

eSpeakActivity.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright (C) 2012 Reece H. Dunn
  3. * Copyright (C) 2009 The Android Open Source Project
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package com.reecedunn.espeak;
  18. import android.app.Activity;
  19. import android.app.AlertDialog;
  20. import android.app.Dialog;
  21. import android.content.DialogInterface;
  22. import android.content.Intent;
  23. import android.os.Build;
  24. import android.os.Bundle;
  25. import android.os.Handler;
  26. import android.os.Message;
  27. import android.preference.PreferenceActivity;
  28. import android.speech.tts.TextToSpeech;
  29. import android.util.Log;
  30. import android.util.Pair;
  31. import android.view.Menu;
  32. import android.view.MenuInflater;
  33. import android.view.MenuItem;
  34. import android.view.View;
  35. import android.widget.ListView;
  36. import java.lang.ref.WeakReference;
  37. import java.util.ArrayList;
  38. import java.util.List;
  39. import java.util.Locale;
  40. public class eSpeakActivity extends Activity {
  41. private static final String ACTION_TTS_SETTINGS = "com.android.settings.TTS_SETTINGS";
  42. /** Handler code for TTS initialization hand-off. */
  43. private static final int TTS_INITIALIZED = 1;
  44. private static final int REQUEST_CHECK = 1;
  45. private static final int REQUEST_DOWNLOAD = 2;
  46. private static final int REQUEST_DEFAULT = 3;
  47. private static final int DIALOG_SET_DEFAULT = 1;
  48. private static final int DIALOG_DOWNLOAD_FAILED = 2;
  49. private static final int DIALOG_ERROR = 3;
  50. private static final String TAG = "eSpeakActivity";
  51. private enum State {
  52. LOADING,
  53. FAILURE,
  54. SUCCESS
  55. }
  56. private State mState;
  57. private boolean mDownloadedVoiceData;
  58. private ArrayList<String> mVoices;
  59. private TextToSpeech mTts;
  60. private List<Pair<String,String>> mInformation;
  61. private InformationListAdapter mInformationView;
  62. @Override
  63. public void onCreate(Bundle savedInstanceState) {
  64. super.onCreate(savedInstanceState);
  65. setContentView(R.layout.main);
  66. mInformation = new ArrayList<Pair<String,String>>();
  67. mInformationView = new InformationListAdapter(this, mInformation);
  68. ((ListView)findViewById(R.id.properties)).setAdapter(mInformationView);
  69. setState(State.LOADING);
  70. checkVoiceData();
  71. }
  72. @Override
  73. public void onDestroy() {
  74. super.onDestroy();
  75. if (mTts != null) {
  76. mTts.shutdown();
  77. }
  78. }
  79. @Override
  80. public boolean onCreateOptionsMenu(Menu menu)
  81. {
  82. MenuInflater inflater = getMenuInflater();
  83. inflater.inflate(R.menu.options, menu);
  84. if (Build.VERSION.SDK_INT < 14) {
  85. // Hide the eSpeak setting menu item on pre-ICS.
  86. menu.getItem(R.id.espeakSettings).setVisible(false);
  87. }
  88. return true;
  89. }
  90. @Override
  91. public boolean onOptionsItemSelected(MenuItem item)
  92. {
  93. switch (item.getItemId())
  94. {
  95. case R.id.espeakSettings:
  96. startActivityForResult(new Intent(eSpeakActivity.this, TtsSettingsActivity.class), REQUEST_DEFAULT);
  97. return true;
  98. case R.id.ttsSettings:
  99. launchGeneralTtsSettings();
  100. return true;
  101. case R.id.updateVoices:
  102. downloadVoiceData();
  103. return true;
  104. }
  105. return super.onOptionsItemSelected(item);
  106. }
  107. /**
  108. * Sets the UI state.
  109. *
  110. * @param state The current state.
  111. */
  112. private void setState(State state) {
  113. mState = state;
  114. findViewById(R.id.loading).setVisibility((state == State.LOADING) ? View.VISIBLE
  115. : View.GONE);
  116. findViewById(R.id.success).setVisibility((state == State.SUCCESS) ? View.VISIBLE
  117. : View.GONE);
  118. findViewById(R.id.failure).setVisibility((state == State.FAILURE) ? View.VISIBLE
  119. : View.GONE);
  120. }
  121. /**
  122. * Launcher the voice data verifier.
  123. */
  124. private void checkVoiceData() {
  125. final Intent checkIntent = new Intent(this, CheckVoiceData.class);
  126. startActivityForResult(checkIntent, REQUEST_CHECK);
  127. }
  128. /**
  129. * Launches the voice data installer.
  130. */
  131. private void downloadVoiceData() {
  132. final Intent checkIntent = new Intent(this, DownloadVoiceData.class);
  133. startActivityForResult(checkIntent, REQUEST_DOWNLOAD);
  134. }
  135. /**
  136. * Initializes the TTS engine.
  137. */
  138. private void initializeEngine() {
  139. mTts = new TextToSpeech(this, mInitListener);
  140. }
  141. private void populateInformationView() {
  142. mInformation.clear();
  143. if (mTts != null) {
  144. Locale language = mTts.getLanguage();
  145. if (language != null) {
  146. final String currentLocale = getString(R.string.current_tts_locale);
  147. mInformation.add(new Pair<String,String>(currentLocale, mTts.getLanguage().getDisplayName()));
  148. }
  149. }
  150. final String availableVoices = getString(R.string.available_voices);
  151. if (mVoices == null) {
  152. mInformation.add(new Pair<String,String>(availableVoices, "0"));
  153. } else {
  154. mInformation.add(new Pair<String,String>(availableVoices, Integer.toString(mVoices.size())));
  155. }
  156. mInformationView.notifyDataSetChanged();
  157. }
  158. /**
  159. * Handles the result of voice data verification. If verification fails
  160. * following a successful installation, displays an error dialog. Otherwise,
  161. * either launches the installer or attempts to initialize the TTS engine.
  162. *
  163. * @param resultCode The result of voice data verification.
  164. * @param data The intent containing available voices.
  165. */
  166. private void onDataChecked(int resultCode, Intent data) {
  167. if (resultCode != TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
  168. if (mDownloadedVoiceData) {
  169. Log.e(TAG, "Voice data check failed (error code: " + resultCode + ").");
  170. setState(State.FAILURE);
  171. showDialog(DIALOG_ERROR);
  172. } else {
  173. downloadVoiceData();
  174. }
  175. return;
  176. }
  177. mVoices = data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
  178. initializeEngine();
  179. populateInformationView();
  180. }
  181. /**
  182. * Handles the result of voice data installation. Either shows a failure
  183. * dialog or launches the voice data verifier.
  184. *
  185. * @param resultCode
  186. */
  187. private void onDataDownloaded(int resultCode) {
  188. if (resultCode != RESULT_OK) {
  189. Log.e(TAG, "Voice data download failed.");
  190. setState(State.FAILURE);
  191. showDialog(DIALOG_DOWNLOAD_FAILED);
  192. return;
  193. }
  194. mDownloadedVoiceData = true;
  195. checkVoiceData();
  196. }
  197. /**
  198. * Handles the result of TTS engine initialization. Either displays an error
  199. * dialog or populates the activity's UI.
  200. *
  201. * @param status The TTS engine initialization status.
  202. */
  203. private void onInitialized(int status) {
  204. if (!getPackageName().equals(mTts.getDefaultEngine())) {
  205. showDialog(DIALOG_SET_DEFAULT);
  206. return;
  207. }
  208. if (status == TextToSpeech.ERROR) {
  209. Log.e(TAG, "Initialization failed (status: " + status + ").");
  210. setState(State.FAILURE);
  211. showDialog(DIALOG_ERROR);
  212. return;
  213. }
  214. populateInformationView();
  215. setState(State.SUCCESS);
  216. }
  217. @Override
  218. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  219. switch (requestCode) {
  220. case REQUEST_CHECK:
  221. onDataChecked(resultCode, data);
  222. break;
  223. case REQUEST_DOWNLOAD:
  224. onDataDownloaded(resultCode);
  225. break;
  226. case REQUEST_DEFAULT:
  227. initializeEngine();
  228. break;
  229. }
  230. super.onActivityResult(requestCode, resultCode, data);
  231. }
  232. @Override
  233. protected Dialog onCreateDialog(int id) {
  234. switch (id) {
  235. case DIALOG_SET_DEFAULT:
  236. return new AlertDialog.Builder(this).setTitle(R.string.app_name)
  237. .setMessage(R.string.set_default_message)
  238. .setNegativeButton(android.R.string.no, mFinishClickListener)
  239. .setPositiveButton(android.R.string.ok, mDialogClickListener).create();
  240. case DIALOG_DOWNLOAD_FAILED:
  241. return new AlertDialog.Builder(this).setTitle(R.string.app_name)
  242. .setMessage(R.string.voice_data_failed_message)
  243. .setNegativeButton(android.R.string.ok, mFinishClickListener)
  244. .setOnCancelListener(mFinishCancelListener).create();
  245. case DIALOG_ERROR:
  246. return new AlertDialog.Builder(this).setTitle(R.string.app_name)
  247. .setMessage(R.string.error_message)
  248. .setNegativeButton(android.R.string.no, mFinishClickListener)
  249. .setNegativeButton(android.R.string.ok, mReportClickListener)
  250. .setOnCancelListener(mFinishCancelListener).create();
  251. }
  252. return super.onCreateDialog(id);
  253. }
  254. private final DialogInterface.OnClickListener mDialogClickListener = new DialogInterface.OnClickListener() {
  255. @Override
  256. public void onClick(DialogInterface dialog, int which) {
  257. switch (which) {
  258. case DialogInterface.BUTTON_POSITIVE:
  259. launchGeneralTtsSettings();
  260. break;
  261. }
  262. }
  263. };
  264. private final DialogInterface.OnClickListener mReportClickListener = new DialogInterface.OnClickListener() {
  265. @Override
  266. public void onClick(DialogInterface dialog, int which) {
  267. // TODO: Send a crash report.
  268. finish();
  269. }
  270. };
  271. private final DialogInterface.OnClickListener mFinishClickListener = new DialogInterface.OnClickListener() {
  272. @Override
  273. public void onClick(DialogInterface dialog, int which) {
  274. finish();
  275. }
  276. };
  277. private final DialogInterface.OnCancelListener mFinishCancelListener = new DialogInterface.OnCancelListener() {
  278. @Override
  279. public void onCancel(DialogInterface dialog) {
  280. finish();
  281. }
  282. };
  283. private final TextToSpeech.OnInitListener mInitListener = new TextToSpeech.OnInitListener() {
  284. @Override
  285. public void onInit(int status) {
  286. mHandler.obtainMessage(TTS_INITIALIZED, status, 0).sendToTarget();
  287. }
  288. };
  289. private static class EspeakHandler extends Handler {
  290. private WeakReference<eSpeakActivity> mActivity;
  291. public EspeakHandler(eSpeakActivity activity)
  292. {
  293. mActivity = new WeakReference<eSpeakActivity>(activity);
  294. }
  295. @Override
  296. public void handleMessage(Message msg) {
  297. switch (msg.what) {
  298. case TTS_INITIALIZED:
  299. mActivity.get().onInitialized(msg.arg1);
  300. break;
  301. }
  302. }
  303. }
  304. private final Handler mHandler = new EspeakHandler(this);
  305. private void launchGeneralTtsSettings()
  306. {
  307. Intent intent;
  308. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
  309. {
  310. // The Text-to-Speech settings is a Fragment on 3.x:
  311. intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
  312. intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, "com.android.settings.TextToSpeechSettings");
  313. intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, intent.getExtras());
  314. }
  315. else
  316. {
  317. // The Text-to-Speech settings is an Activity on 2.x and 4.x:
  318. intent = new Intent(ACTION_TTS_SETTINGS);
  319. }
  320. startActivityForResult(intent, REQUEST_DEFAULT);
  321. }
  322. }