TextToSpeech.java revision 76d9c3cb4f6f8c027959d2951e35a8b37762a1f3
1/* 2 * Copyright (C) 2009 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16package android.speech.tts; 17 18import android.speech.tts.ITts; 19import android.speech.tts.ITtsCallback; 20 21import android.annotation.SdkConstant; 22import android.annotation.SdkConstant.SdkConstantType; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.content.ServiceConnection; 27import android.media.AudioManager; 28import android.os.IBinder; 29import android.os.RemoteException; 30import android.util.Log; 31 32import java.util.HashMap; 33import java.util.Locale; 34 35/** 36 * 37 * Synthesizes speech from text for immediate playback or to create a sound file. 38 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its 39 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be 40 * notified of the completion of the initialization.<br> 41 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method 42 * to release the native resources used by the TextToSpeech engine. 43 * 44 */ 45public class TextToSpeech { 46 47 /** 48 * Denotes a successful operation. 49 */ 50 public static final int SUCCESS = 0; 51 /** 52 * Denotes a generic operation failure. 53 */ 54 public static final int ERROR = -1; 55 56 /** 57 * Queue mode where all entries in the playback queue (media to be played 58 * and text to be synthesized) are dropped and replaced by the new entry. 59 */ 60 public static final int QUEUE_FLUSH = 0; 61 /** 62 * Queue mode where the new entry is added at the end of the playback queue. 63 */ 64 public static final int QUEUE_ADD = 1; 65 66 67 /** 68 * Denotes the language is available exactly as specified by the locale. 69 */ 70 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2; 71 72 73 /** 74 * Denotes the language is available for the language and country specified 75 * by the locale, but not the variant. 76 */ 77 public static final int LANG_COUNTRY_AVAILABLE = 1; 78 79 80 /** 81 * Denotes the language is available for the language by the locale, 82 * but not the country and variant. 83 */ 84 public static final int LANG_AVAILABLE = 0; 85 86 /** 87 * Denotes the language data is missing. 88 */ 89 public static final int LANG_MISSING_DATA = -1; 90 91 /** 92 * Denotes the language is not supported. 93 */ 94 public static final int LANG_NOT_SUPPORTED = -2; 95 96 97 /** 98 * Broadcast Action: The TextToSpeech synthesizer has completed processing 99 * of all the text in the speech queue. 100 */ 101 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 102 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = 103 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED"; 104 105 106 /** 107 * Interface definition of a callback to be invoked indicating the completion of the 108 * TextToSpeech engine initialization. 109 */ 110 public interface OnInitListener { 111 /** 112 * Called to signal the completion of the TextToSpeech engine initialization. 113 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. 114 */ 115 public void onInit(int status); 116 } 117 118 /** 119 * Interface definition of a callback to be invoked indicating the TextToSpeech engine has 120 * completed synthesizing an utterance with an utterance ID set. 121 * 122 */ 123 public interface OnUtteranceCompletedListener { 124 /** 125 * Called to signal the completion of the synthesis of the utterance that was identified 126 * with the string parameter. This identifier is the one originally passed in the 127 * parameter hashmap of the synthesis request in 128 * {@link TextToSpeech#speak(String, int, HashMap)} or 129 * {@link TextToSpeech#synthesizeToFile(String, HashMap, String)} with the 130 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID} key. 131 * @param utteranceId the identifier of the utterance. 132 */ 133 public void onUtteranceCompleted(String utteranceId); 134 } 135 136 137 /** 138 * Internal constants for the TextToSpeech functionality 139 * 140 */ 141 public class Engine { 142 // default values for a TTS engine when settings are not found in the provider 143 /** 144 * {@hide} 145 */ 146 public static final int DEFAULT_RATE = 100; // 1x 147 /** 148 * {@hide} 149 */ 150 public static final int DEFAULT_PITCH = 100;// 1x 151 /** 152 * {@hide} 153 */ 154 public static final int USE_DEFAULTS = 0; // false 155 /** 156 * {@hide} 157 */ 158 public static final String DEFAULT_SYNTH = "com.svox.pico"; 159 160 // default values for rendering 161 /** 162 * Default audio stream used when playing synthesized speech. 163 */ 164 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC; 165 166 // return codes for a TTS engine's check data activity 167 /** 168 * Indicates success when checking the installation status of the resources used by the 169 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 170 */ 171 public static final int CHECK_VOICE_DATA_PASS = 1; 172 /** 173 * Indicates failure when checking the installation status of the resources used by the 174 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 175 */ 176 public static final int CHECK_VOICE_DATA_FAIL = 0; 177 /** 178 * Indicates erroneous data when checking the installation status of the resources used by 179 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 180 */ 181 public static final int CHECK_VOICE_DATA_BAD_DATA = -1; 182 /** 183 * Indicates missing resources when checking the installation status of the resources used 184 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 185 */ 186 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; 187 /** 188 * Indicates missing storage volume when checking the installation status of the resources 189 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 190 */ 191 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; 192 193 // intents to ask engine to install data or check its data 194 /** 195 * Activity Action: Triggers the platform TextToSpeech engine to 196 * start the activity that installs the resource files on the device 197 * that are required for TTS to be operational. Since the installation 198 * of the data can be interrupted or declined by the user, the application 199 * shouldn't expect successful installation upon return from that intent, 200 * and if need be, should check installation status with 201 * {@link #ACTION_CHECK_TTS_DATA}. 202 */ 203 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 204 public static final String ACTION_INSTALL_TTS_DATA = 205 "android.speech.tts.engine.INSTALL_TTS_DATA"; 206 207 /** 208 * Broadcast Action: broadcast to signal the completion of the installation of 209 * the data files used by the synthesis engine. Success or failure is indicated in the 210 * {@link #EXTRA_TTS_DATA_INSTALLED} extra. 211 */ 212 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 213 public static final String ACTION_TTS_DATA_INSTALLED = 214 "android.speech.tts.engine.TTS_DATA_INSTALLED"; 215 /** 216 * Activity Action: Starts the activity from the platform TextToSpeech 217 * engine to verify the proper installation and availability of the 218 * resource files on the system. Upon completion, the activity will 219 * return one of the following codes: 220 * {@link #CHECK_VOICE_DATA_PASS}, 221 * {@link #CHECK_VOICE_DATA_FAIL}, 222 * {@link #CHECK_VOICE_DATA_BAD_DATA}, 223 * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or 224 * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}. 225 * <p> Moreover, the data received in the activity result will contain the following 226 * fields: 227 * <ul> 228 * <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which 229 * indicates the path to the location of the resource files,</li> 230 * <li>{@link #EXTRA_VOICE_DATA_FILES} which contains 231 * the list of all the resource files,</li> 232 * <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which 233 * contains, for each resource file, the description of the language covered by 234 * the file in the xxx-YYY format, where xxx is the 3-letter ISO language code, 235 * and YYY is the 3-letter ISO country code.</li> 236 * </ul> 237 */ 238 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 239 public static final String ACTION_CHECK_TTS_DATA = 240 "android.speech.tts.engine.CHECK_TTS_DATA"; 241 242 // extras for a TTS engine's check data activity 243 /** 244 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 245 * the TextToSpeech engine specifies the path to its resources. 246 */ 247 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; 248 /** 249 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 250 * the TextToSpeech engine specifies the file names of its resources under the 251 * resource path. 252 */ 253 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles"; 254 /** 255 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 256 * the TextToSpeech engine specifies the locale associated with each resource file. 257 */ 258 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo"; 259 /** 260 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 261 * the TextToSpeech engine returns an ArrayList<String> of all the available voices. 262 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 263 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 264 */ 265 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices"; 266 /** 267 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 268 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices. 269 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 270 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 271 */ 272 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices"; 273 /** 274 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the 275 * caller indicates to the TextToSpeech engine which specific sets of voice data to 276 * check for by sending an ArrayList<String> of the voices that are of interest. 277 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 278 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 279 */ 280 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor"; 281 282 // extras for a TTS engine's data installation 283 /** 284 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent. 285 * It indicates whether the data files for the synthesis engine were successfully 286 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA} 287 * intent. The possible values for this extra are 288 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}. 289 */ 290 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled"; 291 292 // keys for the parameters passed with speak commands. Hidden keys are used internally 293 // to maintain engine state for each TextToSpeech instance. 294 /** 295 * {@hide} 296 */ 297 public static final String KEY_PARAM_RATE = "rate"; 298 /** 299 * {@hide} 300 */ 301 public static final String KEY_PARAM_LANGUAGE = "language"; 302 /** 303 * {@hide} 304 */ 305 public static final String KEY_PARAM_COUNTRY = "country"; 306 /** 307 * {@hide} 308 */ 309 public static final String KEY_PARAM_VARIANT = "variant"; 310 /** 311 * {@hide} 312 */ 313 public static final String KEY_PARAM_ENGINE = "engine"; 314 /** 315 * Parameter key to specify the audio stream type to be used when speaking text 316 * or playing back a file. 317 * @see TextToSpeech#speak(String, int, HashMap) 318 * @see TextToSpeech#playEarcon(String, int, HashMap) 319 */ 320 public static final String KEY_PARAM_STREAM = "streamType"; 321 /** 322 * Parameter key to identify an utterance in the 323 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been 324 * spoken, a file has been played back or a silence duration has elapsed. 325 * @see TextToSpeech#speak(String, int, HashMap) 326 * @see TextToSpeech#playEarcon(String, int, HashMap) 327 * @see TextToSpeech#synthesizeToFile(String, HashMap, String) 328 */ 329 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId"; 330 331 // key positions in the array of cached parameters 332 /** 333 * {@hide} 334 */ 335 protected static final int PARAM_POSITION_RATE = 0; 336 /** 337 * {@hide} 338 */ 339 protected static final int PARAM_POSITION_LANGUAGE = 2; 340 /** 341 * {@hide} 342 */ 343 protected static final int PARAM_POSITION_COUNTRY = 4; 344 /** 345 * {@hide} 346 */ 347 protected static final int PARAM_POSITION_VARIANT = 6; 348 /** 349 * {@hide} 350 */ 351 protected static final int PARAM_POSITION_STREAM = 8; 352 /** 353 * {@hide} 354 */ 355 protected static final int PARAM_POSITION_UTTERANCE_ID = 10; 356 357 /** 358 * {@hide} 359 */ 360 protected static final int PARAM_POSITION_ENGINE = 12; 361 362 /** 363 * {@hide} 364 */ 365 protected static final int NB_CACHED_PARAMS = 7; 366 } 367 368 /** 369 * Connection needed for the TTS. 370 */ 371 private ServiceConnection mServiceConnection; 372 373 private ITts mITts = null; 374 private ITtsCallback mITtscallback = null; 375 private Context mContext = null; 376 private String mPackageName = ""; 377 private OnInitListener mInitListener = null; 378 private boolean mStarted = false; 379 private final Object mStartLock = new Object(); 380 /** 381 * Used to store the cached parameters sent along with each synthesis request to the 382 * TTS service. 383 */ 384 private String[] mCachedParams; 385 386 /** 387 * The constructor for the TextToSpeech class. 388 * This will also initialize the associated TextToSpeech engine if it isn't already running. 389 * 390 * @param context 391 * The context this instance is running in. 392 * @param listener 393 * The {@link TextToSpeech.OnInitListener} that will be called when the 394 * TextToSpeech engine has initialized. 395 */ 396 public TextToSpeech(Context context, OnInitListener listener) { 397 mContext = context; 398 mPackageName = mContext.getPackageName(); 399 mInitListener = listener; 400 401 mCachedParams = new String[2*Engine.NB_CACHED_PARAMS]; // store key and value 402 mCachedParams[Engine.PARAM_POSITION_RATE] = Engine.KEY_PARAM_RATE; 403 mCachedParams[Engine.PARAM_POSITION_LANGUAGE] = Engine.KEY_PARAM_LANGUAGE; 404 mCachedParams[Engine.PARAM_POSITION_COUNTRY] = Engine.KEY_PARAM_COUNTRY; 405 mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT; 406 mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM; 407 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID; 408 mCachedParams[Engine.PARAM_POSITION_ENGINE] = Engine.KEY_PARAM_ENGINE; 409 410 mCachedParams[Engine.PARAM_POSITION_RATE + 1] = 411 String.valueOf(Engine.DEFAULT_RATE); 412 // initialize the language cached parameters with the current Locale 413 Locale defaultLoc = Locale.getDefault(); 414 mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language(); 415 mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country(); 416 mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant(); 417 mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = 418 String.valueOf(Engine.DEFAULT_STREAM); 419 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = ""; 420 mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = Engine.DEFAULT_SYNTH; 421 422 initTts(); 423 } 424 425 426 private void initTts() { 427 mStarted = false; 428 429 // Initialize the TTS, run the callback after the binding is successful 430 mServiceConnection = new ServiceConnection() { 431 public void onServiceConnected(ComponentName name, IBinder service) { 432 synchronized(mStartLock) { 433 mITts = ITts.Stub.asInterface(service); 434 mStarted = true; 435 if (mInitListener != null) { 436 // TODO manage failures and missing resources 437 mInitListener.onInit(SUCCESS); 438 } 439 } 440 } 441 442 public void onServiceDisconnected(ComponentName name) { 443 synchronized(mStartLock) { 444 mITts = null; 445 mInitListener = null; 446 mStarted = false; 447 } 448 } 449 }; 450 451 Intent intent = new Intent("android.intent.action.START_TTS_SERVICE"); 452 intent.addCategory("android.intent.category.TTS"); 453 mContext.bindService(intent, mServiceConnection, 454 Context.BIND_AUTO_CREATE); 455 // TODO handle case where the binding works (should always work) but 456 // the plugin fails 457 } 458 459 460 /** 461 * Releases the resources used by the TextToSpeech engine. 462 * It is good practice for instance to call this method in the onDestroy() method of an Activity 463 * so the TextToSpeech engine can be cleanly stopped. 464 */ 465 public void shutdown() { 466 try { 467 mContext.unbindService(mServiceConnection); 468 } catch (IllegalArgumentException e) { 469 // Do nothing and fail silently since an error here indicates that 470 // binding never succeeded in the first place. 471 } 472 } 473 474 475 /** 476 * Adds a mapping between a string of text and a sound resource in a 477 * package. After a call to this method, subsequent calls to 478 * {@link #speak(String, int, HashMap)} will play the specified sound resource 479 * if it is available, or synthesize the text it is missing. 480 * 481 * @param text 482 * The string of text. Example: <code>"south_south_east"</code> 483 * 484 * @param packagename 485 * Pass the packagename of the application that contains the 486 * resource. If the resource is in your own application (this is 487 * the most common case), then put the packagename of your 488 * application here.<br/> 489 * Example: <b>"com.google.marvin.compass"</b><br/> 490 * The packagename can be found in the AndroidManifest.xml of 491 * your application. 492 * <p> 493 * <code><manifest xmlns:android="..." 494 * package="<b>com.google.marvin.compass</b>"></code> 495 * </p> 496 * 497 * @param resourceId 498 * Example: <code>R.raw.south_south_east</code> 499 * 500 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 501 */ 502 public int addSpeech(String text, String packagename, int resourceId) { 503 synchronized(mStartLock) { 504 if (!mStarted) { 505 return ERROR; 506 } 507 try { 508 mITts.addSpeech(mPackageName, text, packagename, resourceId); 509 return SUCCESS; 510 } catch (RemoteException e) { 511 // TTS died; restart it. 512 Log.e("TextToSpeech.java - addSpeech", "RemoteException"); 513 e.printStackTrace(); 514 mStarted = false; 515 initTts(); 516 } catch (NullPointerException e) { 517 // TTS died; restart it. 518 Log.e("TextToSpeech.java - addSpeech", "NullPointerException"); 519 e.printStackTrace(); 520 mStarted = false; 521 initTts(); 522 } catch (IllegalStateException e) { 523 // TTS died; restart it. 524 Log.e("TextToSpeech.java - addSpeech", "IllegalStateException"); 525 e.printStackTrace(); 526 mStarted = false; 527 initTts(); 528 } 529 return ERROR; 530 } 531 } 532 533 534 /** 535 * Adds a mapping between a string of text and a sound file. Using this, it 536 * is possible to add custom pronounciations for a string of text. 537 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} 538 * will play the specified sound resource if it is available, or synthesize the text it is 539 * missing. 540 * 541 * @param text 542 * The string of text. Example: <code>"south_south_east"</code> 543 * @param filename 544 * The full path to the sound file (for example: 545 * "/sdcard/mysounds/hello.wav") 546 * 547 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 548 */ 549 public int addSpeech(String text, String filename) { 550 synchronized (mStartLock) { 551 if (!mStarted) { 552 return ERROR; 553 } 554 try { 555 mITts.addSpeechFile(mPackageName, text, filename); 556 return SUCCESS; 557 } catch (RemoteException e) { 558 // TTS died; restart it. 559 Log.e("TextToSpeech.java - addSpeech", "RemoteException"); 560 e.printStackTrace(); 561 mStarted = false; 562 initTts(); 563 } catch (NullPointerException e) { 564 // TTS died; restart it. 565 Log.e("TextToSpeech.java - addSpeech", "NullPointerException"); 566 e.printStackTrace(); 567 mStarted = false; 568 initTts(); 569 } catch (IllegalStateException e) { 570 // TTS died; restart it. 571 Log.e("TextToSpeech.java - addSpeech", "IllegalStateException"); 572 e.printStackTrace(); 573 mStarted = false; 574 initTts(); 575 } 576 return ERROR; 577 } 578 } 579 580 581 /** 582 * Adds a mapping between a string of text and a sound resource in a 583 * package. Use this to add custom earcons. 584 * 585 * @see #playEarcon(String, int, HashMap) 586 * 587 * @param earcon The name of the earcon. 588 * Example: <code>"[tick]"</code><br/> 589 * 590 * @param packagename 591 * the package name of the application that contains the 592 * resource. This can for instance be the package name of your own application. 593 * Example: <b>"com.google.marvin.compass"</b><br/> 594 * The package name can be found in the AndroidManifest.xml of 595 * the application containing the resource. 596 * <p> 597 * <code><manifest xmlns:android="..." 598 * package="<b>com.google.marvin.compass</b>"></code> 599 * </p> 600 * 601 * @param resourceId 602 * Example: <code>R.raw.tick_snd</code> 603 * 604 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 605 */ 606 public int addEarcon(String earcon, String packagename, int resourceId) { 607 synchronized(mStartLock) { 608 if (!mStarted) { 609 return ERROR; 610 } 611 try { 612 mITts.addEarcon(mPackageName, earcon, packagename, resourceId); 613 return SUCCESS; 614 } catch (RemoteException e) { 615 // TTS died; restart it. 616 Log.e("TextToSpeech.java - addEarcon", "RemoteException"); 617 e.printStackTrace(); 618 mStarted = false; 619 initTts(); 620 } catch (NullPointerException e) { 621 // TTS died; restart it. 622 Log.e("TextToSpeech.java - addEarcon", "NullPointerException"); 623 e.printStackTrace(); 624 mStarted = false; 625 initTts(); 626 } catch (IllegalStateException e) { 627 // TTS died; restart it. 628 Log.e("TextToSpeech.java - addEarcon", "IllegalStateException"); 629 e.printStackTrace(); 630 mStarted = false; 631 initTts(); 632 } 633 return ERROR; 634 } 635 } 636 637 638 /** 639 * Adds a mapping between a string of text and a sound file. 640 * Use this to add custom earcons. 641 * 642 * @see #playEarcon(String, int, HashMap) 643 * 644 * @param earcon 645 * The name of the earcon. 646 * Example: <code>"[tick]"</code> 647 * @param filename 648 * The full path to the sound file (for example: 649 * "/sdcard/mysounds/tick.wav") 650 * 651 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 652 */ 653 public int addEarcon(String earcon, String filename) { 654 synchronized (mStartLock) { 655 if (!mStarted) { 656 return ERROR; 657 } 658 try { 659 mITts.addEarconFile(mPackageName, earcon, filename); 660 return SUCCESS; 661 } catch (RemoteException e) { 662 // TTS died; restart it. 663 Log.e("TextToSpeech.java - addEarcon", "RemoteException"); 664 e.printStackTrace(); 665 mStarted = false; 666 initTts(); 667 } catch (NullPointerException e) { 668 // TTS died; restart it. 669 Log.e("TextToSpeech.java - addEarcon", "NullPointerException"); 670 e.printStackTrace(); 671 mStarted = false; 672 initTts(); 673 } catch (IllegalStateException e) { 674 // TTS died; restart it. 675 Log.e("TextToSpeech.java - addEarcon", "IllegalStateException"); 676 e.printStackTrace(); 677 mStarted = false; 678 initTts(); 679 } 680 return ERROR; 681 } 682 } 683 684 685 /** 686 * Speaks the string using the specified queuing strategy and speech 687 * parameters. 688 * 689 * @param text 690 * The string of text to be spoken. 691 * @param queueMode 692 * The queuing strategy to use. 693 * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 694 * @param params 695 * The list of parameters to be used. Can be null if no parameters are given. 696 * They are specified using a (key, value) pair, where the key can be 697 * {@link Engine#KEY_PARAM_STREAM} or 698 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 699 * 700 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 701 */ 702 public int speak(String text, int queueMode, HashMap<String,String> params) 703 { 704 synchronized (mStartLock) { 705 int result = ERROR; 706 Log.i("TTS received: ", text); 707 if (!mStarted) { 708 return result; 709 } 710 try { 711 if ((params != null) && (!params.isEmpty())) { 712 String extra = params.get(Engine.KEY_PARAM_STREAM); 713 if (extra != null) { 714 mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra; 715 } 716 extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); 717 if (extra != null) { 718 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; 719 } 720 extra = params.get(Engine.KEY_PARAM_ENGINE); 721 if (extra != null) { 722 mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra; 723 } 724 } 725 result = mITts.speak(mPackageName, text, queueMode, mCachedParams); 726 } catch (RemoteException e) { 727 // TTS died; restart it. 728 Log.e("TextToSpeech.java - speak", "RemoteException"); 729 e.printStackTrace(); 730 mStarted = false; 731 initTts(); 732 } catch (NullPointerException e) { 733 // TTS died; restart it. 734 Log.e("TextToSpeech.java - speak", "NullPointerException"); 735 e.printStackTrace(); 736 mStarted = false; 737 initTts(); 738 } catch (IllegalStateException e) { 739 // TTS died; restart it. 740 Log.e("TextToSpeech.java - speak", "IllegalStateException"); 741 e.printStackTrace(); 742 mStarted = false; 743 initTts(); 744 } finally { 745 resetCachedParams(); 746 return result; 747 } 748 } 749 } 750 751 752 /** 753 * Plays the earcon using the specified queueing mode and parameters. 754 * 755 * @param earcon 756 * The earcon that should be played 757 * @param queueMode 758 * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 759 * @param params 760 * The list of parameters to be used. Can be null if no parameters are given. 761 * They are specified using a (key, value) pair, where the key can be 762 * {@link Engine#KEY_PARAM_STREAM} or 763 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 764 * 765 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 766 */ 767 public int playEarcon(String earcon, int queueMode, 768 HashMap<String,String> params) { 769 synchronized (mStartLock) { 770 int result = ERROR; 771 if (!mStarted) { 772 return result; 773 } 774 try { 775 if ((params != null) && (!params.isEmpty())) { 776 String extra = params.get(Engine.KEY_PARAM_STREAM); 777 if (extra != null) { 778 mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra; 779 } 780 extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); 781 if (extra != null) { 782 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; 783 } 784 } 785 result = mITts.playEarcon(mPackageName, earcon, queueMode, null); 786 } catch (RemoteException e) { 787 // TTS died; restart it. 788 Log.e("TextToSpeech.java - playEarcon", "RemoteException"); 789 e.printStackTrace(); 790 mStarted = false; 791 initTts(); 792 } catch (NullPointerException e) { 793 // TTS died; restart it. 794 Log.e("TextToSpeech.java - playEarcon", "NullPointerException"); 795 e.printStackTrace(); 796 mStarted = false; 797 initTts(); 798 } catch (IllegalStateException e) { 799 // TTS died; restart it. 800 Log.e("TextToSpeech.java - playEarcon", "IllegalStateException"); 801 e.printStackTrace(); 802 mStarted = false; 803 initTts(); 804 } finally { 805 resetCachedParams(); 806 return result; 807 } 808 } 809 } 810 811 /** 812 * Plays silence for the specified amount of time using the specified 813 * queue mode. 814 * 815 * @param durationInMs 816 * A long that indicates how long the silence should last. 817 * @param queueMode 818 * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 819 * @param params 820 * The list of parameters to be used. Can be null if no parameters are given. 821 * They are specified using a (key, value) pair, where the key can be 822 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 823 * 824 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 825 */ 826 public int playSilence(long durationInMs, int queueMode, HashMap<String,String> params) { 827 synchronized (mStartLock) { 828 int result = ERROR; 829 if (!mStarted) { 830 return result; 831 } 832 try { 833 if ((params != null) && (!params.isEmpty())) { 834 String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); 835 if (extra != null) { 836 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; 837 } 838 } 839 result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams); 840 } catch (RemoteException e) { 841 // TTS died; restart it. 842 Log.e("TextToSpeech.java - playSilence", "RemoteException"); 843 e.printStackTrace(); 844 mStarted = false; 845 initTts(); 846 } catch (NullPointerException e) { 847 // TTS died; restart it. 848 Log.e("TextToSpeech.java - playSilence", "NullPointerException"); 849 e.printStackTrace(); 850 mStarted = false; 851 initTts(); 852 } catch (IllegalStateException e) { 853 // TTS died; restart it. 854 Log.e("TextToSpeech.java - playSilence", "IllegalStateException"); 855 e.printStackTrace(); 856 mStarted = false; 857 initTts(); 858 } finally { 859 return result; 860 } 861 } 862 } 863 864 865 /** 866 * Returns whether or not the TextToSpeech engine is busy speaking. 867 * 868 * @return Whether or not the TextToSpeech engine is busy speaking. 869 */ 870 public boolean isSpeaking() { 871 synchronized (mStartLock) { 872 if (!mStarted) { 873 return false; 874 } 875 try { 876 return mITts.isSpeaking(); 877 } catch (RemoteException e) { 878 // TTS died; restart it. 879 Log.e("TextToSpeech.java - isSpeaking", "RemoteException"); 880 e.printStackTrace(); 881 mStarted = false; 882 initTts(); 883 } catch (NullPointerException e) { 884 // TTS died; restart it. 885 Log.e("TextToSpeech.java - isSpeaking", "NullPointerException"); 886 e.printStackTrace(); 887 mStarted = false; 888 initTts(); 889 } catch (IllegalStateException e) { 890 // TTS died; restart it. 891 Log.e("TextToSpeech.java - isSpeaking", "IllegalStateException"); 892 e.printStackTrace(); 893 mStarted = false; 894 initTts(); 895 } 896 return false; 897 } 898 } 899 900 901 /** 902 * Interrupts the current utterance (whether played or rendered to file) and discards other 903 * utterances in the queue. 904 * 905 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 906 */ 907 public int stop() { 908 synchronized (mStartLock) { 909 int result = ERROR; 910 if (!mStarted) { 911 return result; 912 } 913 try { 914 result = mITts.stop(mPackageName); 915 } catch (RemoteException e) { 916 // TTS died; restart it. 917 Log.e("TextToSpeech.java - stop", "RemoteException"); 918 e.printStackTrace(); 919 mStarted = false; 920 initTts(); 921 } catch (NullPointerException e) { 922 // TTS died; restart it. 923 Log.e("TextToSpeech.java - stop", "NullPointerException"); 924 e.printStackTrace(); 925 mStarted = false; 926 initTts(); 927 } catch (IllegalStateException e) { 928 // TTS died; restart it. 929 Log.e("TextToSpeech.java - stop", "IllegalStateException"); 930 e.printStackTrace(); 931 mStarted = false; 932 initTts(); 933 } finally { 934 return result; 935 } 936 } 937 } 938 939 940 /** 941 * Sets the speech rate for the TextToSpeech engine. 942 * 943 * This has no effect on any pre-recorded speech. 944 * 945 * @param speechRate 946 * The speech rate for the TextToSpeech engine. 1 is the normal speed, 947 * lower values slow down the speech (0.5 is half the normal speech rate), 948 * greater values accelerate it (2 is twice the normal speech rate). 949 * 950 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 951 */ 952 public int setSpeechRate(float speechRate) { 953 synchronized (mStartLock) { 954 int result = ERROR; 955 if (!mStarted) { 956 return result; 957 } 958 try { 959 if (speechRate > 0) { 960 int rate = (int)(speechRate*100); 961 mCachedParams[Engine.PARAM_POSITION_RATE + 1] = String.valueOf(rate); 962 // the rate is not set here, instead it is cached so it will be associated 963 // with all upcoming utterances. 964 if (speechRate > 0.0f) { 965 result = SUCCESS; 966 } else { 967 result = ERROR; 968 } 969 } 970 } catch (NullPointerException e) { 971 // TTS died; restart it. 972 Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException"); 973 e.printStackTrace(); 974 mStarted = false; 975 initTts(); 976 } catch (IllegalStateException e) { 977 // TTS died; restart it. 978 Log.e("TextToSpeech.java - setSpeechRate", "IllegalStateException"); 979 e.printStackTrace(); 980 mStarted = false; 981 initTts(); 982 } finally { 983 return result; 984 } 985 } 986 } 987 988 989 /** 990 * Sets the speech pitch for the TextToSpeech engine. 991 * 992 * This has no effect on any pre-recorded speech. 993 * 994 * @param pitch 995 * The pitch for the TextToSpeech engine. 1 is the normal pitch, 996 * lower values lower the tone of the synthesized voice, 997 * greater values increase it. 998 * 999 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 1000 */ 1001 public int setPitch(float pitch) { 1002 synchronized (mStartLock) { 1003 int result = ERROR; 1004 if (!mStarted) { 1005 return result; 1006 } 1007 try { 1008 if (pitch > 0) { 1009 result = mITts.setPitch(mPackageName, (int)(pitch*100)); 1010 } 1011 } catch (RemoteException e) { 1012 // TTS died; restart it. 1013 Log.e("TextToSpeech.java - setPitch", "RemoteException"); 1014 e.printStackTrace(); 1015 mStarted = false; 1016 initTts(); 1017 } catch (NullPointerException e) { 1018 // TTS died; restart it. 1019 Log.e("TextToSpeech.java - setPitch", "NullPointerException"); 1020 e.printStackTrace(); 1021 mStarted = false; 1022 initTts(); 1023 } catch (IllegalStateException e) { 1024 // TTS died; restart it. 1025 Log.e("TextToSpeech.java - setPitch", "IllegalStateException"); 1026 e.printStackTrace(); 1027 mStarted = false; 1028 initTts(); 1029 } finally { 1030 return result; 1031 } 1032 } 1033 } 1034 1035 1036 /** 1037 * Sets the language for the TextToSpeech engine. 1038 * The TextToSpeech engine will try to use the closest match to the specified 1039 * language as represented by the Locale, but there is no guarantee that the exact same Locale 1040 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support 1041 * before choosing the language to use for the next utterances. 1042 * 1043 * @param loc 1044 * The locale describing the language to be used. 1045 * 1046 * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1047 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1048 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1049 */ 1050 public int setLanguage(Locale loc) { 1051 synchronized (mStartLock) { 1052 int result = LANG_NOT_SUPPORTED; 1053 if (!mStarted) { 1054 return result; 1055 } 1056 try { 1057 mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language(); 1058 mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country(); 1059 mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = loc.getVariant(); 1060 // the language is not set here, instead it is cached so it will be associated 1061 // with all upcoming utterances. But we still need to report the language support, 1062 // which is achieved by calling isLanguageAvailable() 1063 result = mITts.isLanguageAvailable( 1064 mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1], 1065 mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1], 1066 mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] ); 1067 } catch (RemoteException e) { 1068 // TTS died; restart it. 1069 Log.e("TextToSpeech.java - setLanguage", "RemoteException"); 1070 e.printStackTrace(); 1071 mStarted = false; 1072 initTts(); 1073 } catch (NullPointerException e) { 1074 // TTS died; restart it. 1075 Log.e("TextToSpeech.java - setLanguage", "NullPointerException"); 1076 e.printStackTrace(); 1077 mStarted = false; 1078 initTts(); 1079 } catch (IllegalStateException e) { 1080 // TTS died; restart it. 1081 Log.e("TextToSpeech.java - setLanguage", "IllegalStateException"); 1082 e.printStackTrace(); 1083 mStarted = false; 1084 initTts(); 1085 } finally { 1086 return result; 1087 } 1088 } 1089 } 1090 1091 1092 /** 1093 * Returns a Locale instance describing the language currently being used by the TextToSpeech 1094 * engine. 1095 * @return language, country (if any) and variant (if any) used by the engine stored in a Locale 1096 * instance, or null is the TextToSpeech engine has failed. 1097 */ 1098 public Locale getLanguage() { 1099 synchronized (mStartLock) { 1100 if (!mStarted) { 1101 return null; 1102 } 1103 try { 1104 String[] locStrings = mITts.getLanguage(); 1105 if ((locStrings != null) && (locStrings.length == 3)) { 1106 return new Locale(locStrings[0], locStrings[1], locStrings[2]); 1107 } else { 1108 return null; 1109 } 1110 } catch (RemoteException e) { 1111 // TTS died; restart it. 1112 Log.e("TextToSpeech.java - getLanguage", "RemoteException"); 1113 e.printStackTrace(); 1114 mStarted = false; 1115 initTts(); 1116 } catch (NullPointerException e) { 1117 // TTS died; restart it. 1118 Log.e("TextToSpeech.java - getLanguage", "NullPointerException"); 1119 e.printStackTrace(); 1120 mStarted = false; 1121 initTts(); 1122 } catch (IllegalStateException e) { 1123 // TTS died; restart it. 1124 Log.e("TextToSpeech.java - getLanguage", "IllegalStateException"); 1125 e.printStackTrace(); 1126 mStarted = false; 1127 initTts(); 1128 } 1129 return null; 1130 } 1131 } 1132 1133 /** 1134 * Checks if the specified language as represented by the Locale is available and supported. 1135 * 1136 * @param loc 1137 * The Locale describing the language to be used. 1138 * 1139 * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1140 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1141 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1142 */ 1143 public int isLanguageAvailable(Locale loc) { 1144 synchronized (mStartLock) { 1145 int result = LANG_NOT_SUPPORTED; 1146 if (!mStarted) { 1147 return result; 1148 } 1149 try { 1150 result = mITts.isLanguageAvailable(loc.getISO3Language(), 1151 loc.getISO3Country(), loc.getVariant()); 1152 } catch (RemoteException e) { 1153 // TTS died; restart it. 1154 Log.e("TextToSpeech.java - isLanguageAvailable", "RemoteException"); 1155 e.printStackTrace(); 1156 mStarted = false; 1157 initTts(); 1158 } catch (NullPointerException e) { 1159 // TTS died; restart it. 1160 Log.e("TextToSpeech.java - isLanguageAvailable", "NullPointerException"); 1161 e.printStackTrace(); 1162 mStarted = false; 1163 initTts(); 1164 } catch (IllegalStateException e) { 1165 // TTS died; restart it. 1166 Log.e("TextToSpeech.java - isLanguageAvailable", "IllegalStateException"); 1167 e.printStackTrace(); 1168 mStarted = false; 1169 initTts(); 1170 } finally { 1171 return result; 1172 } 1173 } 1174 } 1175 1176 1177 /** 1178 * Synthesizes the given text to a file using the specified parameters. 1179 * 1180 * @param text 1181 * The String of text that should be synthesized 1182 * @param params 1183 * The list of parameters to be used. Can be null if no parameters are given. 1184 * They are specified using a (key, value) pair, where the key can be 1185 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 1186 * @param filename 1187 * The string that gives the full output filename; it should be 1188 * something like "/sdcard/myappsounds/mysound.wav". 1189 * 1190 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 1191 */ 1192 public int synthesizeToFile(String text, HashMap<String,String> params, 1193 String filename) { 1194 synchronized (mStartLock) { 1195 int result = ERROR; 1196 if (!mStarted) { 1197 return result; 1198 } 1199 try { 1200 if ((params != null) && (!params.isEmpty())) { 1201 // no need to read the stream type here 1202 String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); 1203 if (extra != null) { 1204 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; 1205 } 1206 extra = params.get(Engine.KEY_PARAM_ENGINE); 1207 if (extra != null) { 1208 mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra; 1209 } 1210 } 1211 if (mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename)){ 1212 result = SUCCESS; 1213 } 1214 } catch (RemoteException e) { 1215 // TTS died; restart it. 1216 Log.e("TextToSpeech.java - synthesizeToFile", "RemoteException"); 1217 e.printStackTrace(); 1218 mStarted = false; 1219 initTts(); 1220 } catch (NullPointerException e) { 1221 // TTS died; restart it. 1222 Log.e("TextToSpeech.java - synthesizeToFile", "NullPointerException"); 1223 e.printStackTrace(); 1224 mStarted = false; 1225 initTts(); 1226 } catch (IllegalStateException e) { 1227 // TTS died; restart it. 1228 Log.e("TextToSpeech.java - synthesizeToFile", "IllegalStateException"); 1229 e.printStackTrace(); 1230 mStarted = false; 1231 initTts(); 1232 } finally { 1233 resetCachedParams(); 1234 return result; 1235 } 1236 } 1237 } 1238 1239 1240 /** 1241 * Convenience method to reset the cached parameters to the current default values 1242 * if they are not persistent between calls to the service. 1243 */ 1244 private void resetCachedParams() { 1245 mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = 1246 String.valueOf(Engine.DEFAULT_STREAM); 1247 mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID+ 1] = ""; 1248 } 1249 1250 /** 1251 * Sets the OnUtteranceCompletedListener that will fire when an utterance completes. 1252 * 1253 * @param listener 1254 * The OnUtteranceCompletedListener 1255 * 1256 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 1257 */ 1258 public int setOnUtteranceCompletedListener( 1259 final OnUtteranceCompletedListener listener) { 1260 synchronized (mStartLock) { 1261 int result = ERROR; 1262 if (!mStarted) { 1263 return result; 1264 } 1265 mITtscallback = new ITtsCallback.Stub() { 1266 public void utteranceCompleted(String utteranceId) throws RemoteException { 1267 if (listener != null) { 1268 listener.onUtteranceCompleted(utteranceId); 1269 } 1270 } 1271 }; 1272 try { 1273 result = mITts.registerCallback(mPackageName, mITtscallback); 1274 } catch (RemoteException e) { 1275 // TTS died; restart it. 1276 Log.e("TextToSpeech.java - registerCallback", "RemoteException"); 1277 e.printStackTrace(); 1278 mStarted = false; 1279 initTts(); 1280 } catch (NullPointerException e) { 1281 // TTS died; restart it. 1282 Log.e("TextToSpeech.java - registerCallback", "NullPointerException"); 1283 e.printStackTrace(); 1284 mStarted = false; 1285 initTts(); 1286 } catch (IllegalStateException e) { 1287 // TTS died; restart it. 1288 Log.e("TextToSpeech.java - registerCallback", "IllegalStateException"); 1289 e.printStackTrace(); 1290 mStarted = false; 1291 initTts(); 1292 } finally { 1293 return result; 1294 } 1295 } 1296 } 1297 1298 /** 1299 * Sets the speech synthesis engine to be used by its packagename. 1300 * 1301 * @param enginePackageName 1302 * The packagename for the synthesis engine (ie, "com.svox.pico") 1303 * 1304 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 1305 */ 1306 public int setEngineByPackageName(String enginePackageName) { 1307 synchronized (mStartLock) { 1308 int result = TextToSpeech.ERROR; 1309 if (!mStarted) { 1310 return result; 1311 } 1312 try { 1313 result = mITts.setEngineByPackageName(enginePackageName); 1314 if (result == TextToSpeech.SUCCESS){ 1315 mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName; 1316 } 1317 } catch (RemoteException e) { 1318 // TTS died; restart it. 1319 Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException"); 1320 e.printStackTrace(); 1321 mStarted = false; 1322 initTts(); 1323 } catch (NullPointerException e) { 1324 // TTS died; restart it. 1325 Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException"); 1326 e.printStackTrace(); 1327 mStarted = false; 1328 initTts(); 1329 } catch (IllegalStateException e) { 1330 // TTS died; restart it. 1331 Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException"); 1332 e.printStackTrace(); 1333 mStarted = false; 1334 initTts(); 1335 } finally { 1336 return result; 1337 } 1338 } 1339 } 1340 1341} 1342