TextToSpeech.java revision f288a64f5bed290d162c1a6fd54bea7c0ba14042
1/* 2 * Copyright (C) 2009 The Android Open Source Project 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.annotation.SdkConstant; 19import android.annotation.SdkConstant.SdkConstantType; 20import android.content.ComponentName; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.media.AudioManager; 26import android.net.Uri; 27import android.os.Bundle; 28import android.os.IBinder; 29import android.os.RemoteException; 30import android.provider.Settings; 31import android.text.TextUtils; 32import android.util.Log; 33 34import java.util.Collections; 35import java.util.HashMap; 36import java.util.HashSet; 37import java.util.List; 38import java.util.Locale; 39import java.util.Map; 40import java.util.Set; 41 42/** 43 * 44 * Synthesizes speech from text for immediate playback or to create a sound file. 45 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its 46 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be 47 * notified of the completion of the initialization.<br> 48 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method 49 * to release the native resources used by the TextToSpeech engine. 50 * 51 */ 52public class TextToSpeech { 53 54 private static final String TAG = "TextToSpeech"; 55 56 /** 57 * Denotes a successful operation. 58 */ 59 public static final int SUCCESS = 0; 60 /** 61 * Denotes a generic operation failure. 62 */ 63 public static final int ERROR = -1; 64 65 /** 66 * Queue mode where all entries in the playback queue (media to be played 67 * and text to be synthesized) are dropped and replaced by the new entry. 68 * Queues are flushed with respect to a given calling app. Entries in the queue 69 * from other callees are not discarded. 70 */ 71 public static final int QUEUE_FLUSH = 0; 72 /** 73 * Queue mode where the new entry is added at the end of the playback queue. 74 */ 75 public static final int QUEUE_ADD = 1; 76 /** 77 * Queue mode where the entire playback queue is purged. This is different 78 * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries 79 * from a given caller. 80 * 81 * @hide 82 */ 83 static final int QUEUE_DESTROY = 2; 84 85 /** 86 * Denotes the language is available exactly as specified by the locale. 87 */ 88 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2; 89 90 /** 91 * Denotes the language is available for the language and country specified 92 * by the locale, but not the variant. 93 */ 94 public static final int LANG_COUNTRY_AVAILABLE = 1; 95 96 /** 97 * Denotes the language is available for the language by the locale, 98 * but not the country and variant. 99 */ 100 public static final int LANG_AVAILABLE = 0; 101 102 /** 103 * Denotes the language data is missing. 104 */ 105 public static final int LANG_MISSING_DATA = -1; 106 107 /** 108 * Denotes the language is not supported. 109 */ 110 public static final int LANG_NOT_SUPPORTED = -2; 111 112 /** 113 * Broadcast Action: The TextToSpeech synthesizer has completed processing 114 * of all the text in the speech queue. 115 * 116 * Note that this notifies callers when the <b>engine</b> has finished has 117 * processing text data. Audio playback might not have completed (or even started) 118 * at this point. If you wish to be notified when this happens, see 119 * {@link OnUtteranceCompletedListener}. 120 */ 121 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 122 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = 123 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED"; 124 125 /** 126 * Interface definition of a callback to be invoked indicating the completion of the 127 * TextToSpeech engine initialization. 128 */ 129 public interface OnInitListener { 130 /** 131 * Called to signal the completion of the TextToSpeech engine initialization. 132 * 133 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. 134 */ 135 public void onInit(int status); 136 } 137 138 /** 139 * Listener that will be called when the TTS service has 140 * completed synthesizing an utterance. This is only called if the utterance 141 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}). 142 */ 143 public interface OnUtteranceCompletedListener { 144 /** 145 * Called when an utterance has been synthesized. 146 * 147 * @param utteranceId the identifier of the utterance. 148 */ 149 public void onUtteranceCompleted(String utteranceId); 150 } 151 152 /** 153 * Constants and parameter names for controlling text-to-speech. These include: 154 * 155 * <ul> 156 * <li> 157 * Intents to ask engine to install data or check its data and 158 * extras for a TTS engine's check data activity. 159 * </li> 160 * <li> 161 * Keys for the parameters passed with speak commands, e.g. 162 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, {@link Engine#KEY_PARAM_STREAM}. 163 * </li> 164 * <li> 165 * A list of feature strings that engines might support, e.g 166 * {@link Engine#KEY_FEATURE_NETWORK_SYNTHESIS}). These values may be passed in to 167 * {@link TextToSpeech#speak} and {@link TextToSpeech#synthesizeToFile} to modify 168 * engine behaviour. The engine can be queried for the set of features it supports 169 * through {@link TextToSpeech#getFeatures(java.util.Locale)}. 170 * </li> 171 * </ul> 172 */ 173 public class Engine { 174 175 /** 176 * Default speech rate. 177 * @hide 178 */ 179 public static final int DEFAULT_RATE = 100; 180 181 /** 182 * Default pitch. 183 * @hide 184 */ 185 public static final int DEFAULT_PITCH = 100; 186 187 /** 188 * Default volume. 189 * @hide 190 */ 191 public static final float DEFAULT_VOLUME = 1.0f; 192 193 /** 194 * Default pan (centered). 195 * @hide 196 */ 197 public static final float DEFAULT_PAN = 0.0f; 198 199 /** 200 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}. 201 * @hide 202 */ 203 public static final int USE_DEFAULTS = 0; // false 204 205 /** 206 * Limit of length of input string passed to speak/synthesizeToFile. 207 * Larger strings will be rejected. 208 */ 209 public static final int MAX_SPEECH_STRING_LENGTH = 4000; 210 211 /** 212 * Package name of the default TTS engine. 213 * 214 * @hide 215 * @deprecated No longer in use, the default engine is determined by 216 * the sort order defined in {@link TtsEngines}. Note that 217 * this doesn't "break" anything because there is no guarantee that 218 * the engine specified below is installed on a given build, let 219 * alone be the default. 220 */ 221 @Deprecated 222 public static final String DEFAULT_ENGINE = "com.svox.pico"; 223 224 /** 225 * Default audio stream used when playing synthesized speech. 226 */ 227 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC; 228 229 /** 230 * Indicates success when checking the installation status of the resources used by the 231 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 232 */ 233 public static final int CHECK_VOICE_DATA_PASS = 1; 234 235 /** 236 * Indicates failure when checking the installation status of the resources used by the 237 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 238 */ 239 public static final int CHECK_VOICE_DATA_FAIL = 0; 240 241 /** 242 * Indicates erroneous data when checking the installation status of the resources used by 243 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 244 */ 245 public static final int CHECK_VOICE_DATA_BAD_DATA = -1; 246 247 /** 248 * Indicates missing resources when checking the installation status of the resources used 249 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 250 */ 251 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; 252 253 /** 254 * Indicates missing storage volume when checking the installation status of the resources 255 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 256 */ 257 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; 258 259 /** 260 * Intent for starting a TTS service. Services that handle this intent must 261 * extend {@link TextToSpeechService}. Normal applications should not use this intent 262 * directly, instead they should talk to the TTS service using the the methods in this 263 * class. 264 */ 265 @SdkConstant(SdkConstantType.SERVICE_ACTION) 266 public static final String INTENT_ACTION_TTS_SERVICE = 267 "android.intent.action.TTS_SERVICE"; 268 269 /** 270 * Name under which a text to speech engine publishes information about itself. 271 * This meta-data should reference an XML resource containing a 272 * <code><{@link android.R.styleable#TextToSpeechEngine tts-engine}></code> 273 * tag. 274 */ 275 public static final String SERVICE_META_DATA = "android.speech.tts"; 276 277 // intents to ask engine to install data or check its data 278 /** 279 * Activity Action: Triggers the platform TextToSpeech engine to 280 * start the activity that installs the resource files on the device 281 * that are required for TTS to be operational. Since the installation 282 * of the data can be interrupted or declined by the user, the application 283 * shouldn't expect successful installation upon return from that intent, 284 * and if need be, should check installation status with 285 * {@link #ACTION_CHECK_TTS_DATA}. 286 */ 287 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 288 public static final String ACTION_INSTALL_TTS_DATA = 289 "android.speech.tts.engine.INSTALL_TTS_DATA"; 290 291 /** 292 * Broadcast Action: broadcast to signal the completion of the installation of 293 * the data files used by the synthesis engine. Success or failure is indicated in the 294 * {@link #EXTRA_TTS_DATA_INSTALLED} extra. 295 */ 296 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 297 public static final String ACTION_TTS_DATA_INSTALLED = 298 "android.speech.tts.engine.TTS_DATA_INSTALLED"; 299 300 /** 301 * Activity Action: Starts the activity from the platform TextToSpeech 302 * engine to verify the proper installation and availability of the 303 * resource files on the system. Upon completion, the activity will 304 * return one of the following codes: 305 * {@link #CHECK_VOICE_DATA_PASS}, 306 * {@link #CHECK_VOICE_DATA_FAIL}, 307 * {@link #CHECK_VOICE_DATA_BAD_DATA}, 308 * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or 309 * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}. 310 * <p> Moreover, the data received in the activity result will contain the following 311 * fields: 312 * <ul> 313 * <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which 314 * indicates the path to the location of the resource files,</li> 315 * <li>{@link #EXTRA_VOICE_DATA_FILES} which contains 316 * the list of all the resource files,</li> 317 * <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which 318 * contains, for each resource file, the description of the language covered by 319 * the file in the xxx-YYY format, where xxx is the 3-letter ISO language code, 320 * and YYY is the 3-letter ISO country code.</li> 321 * </ul> 322 */ 323 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 324 public static final String ACTION_CHECK_TTS_DATA = 325 "android.speech.tts.engine.CHECK_TTS_DATA"; 326 327 /** 328 * Activity intent for getting some sample text to use for demonstrating TTS. 329 * 330 * @hide This intent was used by engines written against the old API. 331 * Not sure if it should be exposed. 332 */ 333 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 334 public static final String ACTION_GET_SAMPLE_TEXT = 335 "android.speech.tts.engine.GET_SAMPLE_TEXT"; 336 337 // extras for a TTS engine's check data activity 338 /** 339 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 340 * the TextToSpeech engine specifies the path to its resources. 341 */ 342 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; 343 344 /** 345 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 346 * the TextToSpeech engine specifies the file names of its resources under the 347 * resource path. 348 */ 349 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles"; 350 351 /** 352 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 353 * the TextToSpeech engine specifies the locale associated with each resource file. 354 */ 355 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo"; 356 357 /** 358 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 359 * the TextToSpeech engine returns an ArrayList<String> of all the available voices. 360 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 361 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 362 */ 363 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices"; 364 365 /** 366 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where 367 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices. 368 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 369 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 370 */ 371 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices"; 372 373 /** 374 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the 375 * caller indicates to the TextToSpeech engine which specific sets of voice data to 376 * check for by sending an ArrayList<String> of the voices that are of interest. 377 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 378 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 379 */ 380 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor"; 381 382 // extras for a TTS engine's data installation 383 /** 384 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent. 385 * It indicates whether the data files for the synthesis engine were successfully 386 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA} 387 * intent. The possible values for this extra are 388 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}. 389 */ 390 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled"; 391 392 // keys for the parameters passed with speak commands. Hidden keys are used internally 393 // to maintain engine state for each TextToSpeech instance. 394 /** 395 * @hide 396 */ 397 public static final String KEY_PARAM_RATE = "rate"; 398 399 /** 400 * @hide 401 */ 402 public static final String KEY_PARAM_LANGUAGE = "language"; 403 404 /** 405 * @hide 406 */ 407 public static final String KEY_PARAM_COUNTRY = "country"; 408 409 /** 410 * @hide 411 */ 412 public static final String KEY_PARAM_VARIANT = "variant"; 413 414 /** 415 * @hide 416 */ 417 public static final String KEY_PARAM_ENGINE = "engine"; 418 419 /** 420 * @hide 421 */ 422 public static final String KEY_PARAM_PITCH = "pitch"; 423 424 /** 425 * Parameter key to specify the audio stream type to be used when speaking text 426 * or playing back a file. The value should be one of the STREAM_ constants 427 * defined in {@link AudioManager}. 428 * 429 * @see TextToSpeech#speak(String, int, HashMap) 430 * @see TextToSpeech#playEarcon(String, int, HashMap) 431 */ 432 public static final String KEY_PARAM_STREAM = "streamType"; 433 434 /** 435 * Parameter key to identify an utterance in the 436 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been 437 * spoken, a file has been played back or a silence duration has elapsed. 438 * 439 * @see TextToSpeech#speak(String, int, HashMap) 440 * @see TextToSpeech#playEarcon(String, int, HashMap) 441 * @see TextToSpeech#synthesizeToFile(String, HashMap, String) 442 */ 443 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId"; 444 445 /** 446 * Parameter key to specify the speech volume relative to the current stream type 447 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1 448 * where 0 is silence, and 1 is the maximum volume (the default behavior). 449 * 450 * @see TextToSpeech#speak(String, int, HashMap) 451 * @see TextToSpeech#playEarcon(String, int, HashMap) 452 */ 453 public static final String KEY_PARAM_VOLUME = "volume"; 454 455 /** 456 * Parameter key to specify how the speech is panned from left to right when speaking text. 457 * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan, 458 * 0 to center (the default behavior), and +1 to hard-right. 459 * 460 * @see TextToSpeech#speak(String, int, HashMap) 461 * @see TextToSpeech#playEarcon(String, int, HashMap) 462 */ 463 public static final String KEY_PARAM_PAN = "pan"; 464 465 /** 466 * Feature key for network synthesis. See {@link TextToSpeech#getFeatures(Locale)} 467 * for a description of how feature keys work. If set (and supported by the engine 468 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must 469 * use network based synthesis. 470 * 471 * @see TextToSpeech#speak(String, int, java.util.HashMap) 472 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) 473 * @see TextToSpeech#getFeatures(java.util.Locale) 474 */ 475 public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts"; 476 477 /** 478 * Feature key for embedded synthesis. See {@link TextToSpeech#getFeatures(Locale)} 479 * for a description of how feature keys work. If set and supported by the engine 480 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize 481 * text on-device (without making network requests). 482 */ 483 public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts"; 484 } 485 486 private final Context mContext; 487 private Connection mServiceConnection; 488 private OnInitListener mInitListener; 489 // Written from an unspecified application thread, read from 490 // a binder thread. 491 private volatile UtteranceProgressListener mUtteranceProgressListener; 492 private final Object mStartLock = new Object(); 493 494 private String mRequestedEngine; 495 // Whether to initialize this TTS object with the default engine, 496 // if the requested engine is not available. Valid only if mRequestedEngine 497 // is not null. Used only for testing, though potentially useful API wise 498 // too. 499 private final boolean mUseFallback; 500 private final Map<String, Uri> mEarcons; 501 private final Map<String, Uri> mUtterances; 502 private final Bundle mParams = new Bundle(); 503 private final TtsEngines mEnginesHelper; 504 private final String mPackageName; 505 private volatile String mCurrentEngine = null; 506 507 /** 508 * The constructor for the TextToSpeech class, using the default TTS engine. 509 * This will also initialize the associated TextToSpeech engine if it isn't already running. 510 * 511 * @param context 512 * The context this instance is running in. 513 * @param listener 514 * The {@link TextToSpeech.OnInitListener} that will be called when the 515 * TextToSpeech engine has initialized. 516 */ 517 public TextToSpeech(Context context, OnInitListener listener) { 518 this(context, listener, null); 519 } 520 521 /** 522 * The constructor for the TextToSpeech class, using the given TTS engine. 523 * This will also initialize the associated TextToSpeech engine if it isn't already running. 524 * 525 * @param context 526 * The context this instance is running in. 527 * @param listener 528 * The {@link TextToSpeech.OnInitListener} that will be called when the 529 * TextToSpeech engine has initialized. 530 * @param engine Package name of the TTS engine to use. 531 */ 532 public TextToSpeech(Context context, OnInitListener listener, String engine) { 533 this(context, listener, engine, null, true); 534 } 535 536 /** 537 * Used by the framework to instantiate TextToSpeech objects with a supplied 538 * package name, instead of using {@link android.content.Context#getPackageName()} 539 * 540 * @hide 541 */ 542 public TextToSpeech(Context context, OnInitListener listener, String engine, 543 String packageName, boolean useFallback) { 544 mContext = context; 545 mInitListener = listener; 546 mRequestedEngine = engine; 547 mUseFallback = useFallback; 548 549 mEarcons = new HashMap<String, Uri>(); 550 mUtterances = new HashMap<String, Uri>(); 551 mUtteranceProgressListener = null; 552 553 mEnginesHelper = new TtsEngines(mContext); 554 if (packageName != null) { 555 mPackageName = packageName; 556 } else { 557 mPackageName = mContext.getPackageName(); 558 } 559 initTts(); 560 } 561 562 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) { 563 return runAction(action, errorResult, method, false); 564 } 565 566 private <R> R runAction(Action<R> action, R errorResult, String method) { 567 return runAction(action, errorResult, method, true); 568 } 569 570 private <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) { 571 synchronized (mStartLock) { 572 if (mServiceConnection == null) { 573 Log.w(TAG, method + " failed: not bound to TTS engine"); 574 return errorResult; 575 } 576 return mServiceConnection.runAction(action, errorResult, method, reconnect); 577 } 578 } 579 580 private int initTts() { 581 // Step 1: Try connecting to the engine that was requested. 582 if (mRequestedEngine != null) { 583 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) { 584 if (connectToEngine(mRequestedEngine)) { 585 mCurrentEngine = mRequestedEngine; 586 return SUCCESS; 587 } else if (!mUseFallback) { 588 mCurrentEngine = null; 589 dispatchOnInit(ERROR); 590 return ERROR; 591 } 592 } else if (!mUseFallback) { 593 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine); 594 mCurrentEngine = null; 595 dispatchOnInit(ERROR); 596 return ERROR; 597 } 598 } 599 600 // Step 2: Try connecting to the user's default engine. 601 final String defaultEngine = getDefaultEngine(); 602 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) { 603 if (connectToEngine(defaultEngine)) { 604 mCurrentEngine = defaultEngine; 605 return SUCCESS; 606 } 607 } 608 609 // Step 3: Try connecting to the highest ranked engine in the 610 // system. 611 final String highestRanked = mEnginesHelper.getHighestRankedEngineName(); 612 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) && 613 !highestRanked.equals(defaultEngine)) { 614 if (connectToEngine(highestRanked)) { 615 mCurrentEngine = highestRanked; 616 return SUCCESS; 617 } 618 } 619 620 // NOTE: The API currently does not allow the caller to query whether 621 // they are actually connected to any engine. This might fail for various 622 // reasons like if the user disables all her TTS engines. 623 624 mCurrentEngine = null; 625 dispatchOnInit(ERROR); 626 return ERROR; 627 } 628 629 private boolean connectToEngine(String engine) { 630 Connection connection = new Connection(); 631 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); 632 intent.setPackage(engine); 633 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE); 634 if (!bound) { 635 Log.e(TAG, "Failed to bind to " + engine); 636 return false; 637 } else { 638 Log.i(TAG, "Sucessfully bound to " + engine); 639 return true; 640 } 641 } 642 643 private void dispatchOnInit(int result) { 644 synchronized (mStartLock) { 645 if (mInitListener != null) { 646 mInitListener.onInit(result); 647 mInitListener = null; 648 } 649 } 650 } 651 652 private IBinder getCallerIdentity() { 653 return mServiceConnection.getCallerIdentity(); 654 } 655 656 /** 657 * Releases the resources used by the TextToSpeech engine. 658 * It is good practice for instance to call this method in the onDestroy() method of an Activity 659 * so the TextToSpeech engine can be cleanly stopped. 660 */ 661 public void shutdown() { 662 runActionNoReconnect(new Action<Void>() { 663 @Override 664 public Void run(ITextToSpeechService service) throws RemoteException { 665 service.setCallback(getCallerIdentity(), null); 666 service.stop(getCallerIdentity()); 667 mServiceConnection.disconnect(); 668 // Context#unbindService does not result in a call to 669 // ServiceConnection#onServiceDisconnected. As a result, the 670 // service ends up being destroyed (if there are no other open 671 // connections to it) but the process lives on and the 672 // ServiceConnection continues to refer to the destroyed service. 673 // 674 // This leads to tons of log spam about SynthThread being dead. 675 mServiceConnection = null; 676 mCurrentEngine = null; 677 return null; 678 } 679 }, null, "shutdown"); 680 } 681 682 /** 683 * Adds a mapping between a string of text and a sound resource in a 684 * package. After a call to this method, subsequent calls to 685 * {@link #speak(String, int, HashMap)} will play the specified sound resource 686 * if it is available, or synthesize the text it is missing. 687 * 688 * @param text 689 * The string of text. Example: <code>"south_south_east"</code> 690 * 691 * @param packagename 692 * Pass the packagename of the application that contains the 693 * resource. If the resource is in your own application (this is 694 * the most common case), then put the packagename of your 695 * application here.<br/> 696 * Example: <b>"com.google.marvin.compass"</b><br/> 697 * The packagename can be found in the AndroidManifest.xml of 698 * your application. 699 * <p> 700 * <code><manifest xmlns:android="..." 701 * package="<b>com.google.marvin.compass</b>"></code> 702 * </p> 703 * 704 * @param resourceId 705 * Example: <code>R.raw.south_south_east</code> 706 * 707 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 708 */ 709 public int addSpeech(String text, String packagename, int resourceId) { 710 synchronized (mStartLock) { 711 mUtterances.put(text, makeResourceUri(packagename, resourceId)); 712 return SUCCESS; 713 } 714 } 715 716 /** 717 * Adds a mapping between a string of text and a sound file. Using this, it 718 * is possible to add custom pronounciations for a string of text. 719 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} 720 * will play the specified sound resource if it is available, or synthesize the text it is 721 * missing. 722 * 723 * @param text 724 * The string of text. Example: <code>"south_south_east"</code> 725 * @param filename 726 * The full path to the sound file (for example: 727 * "/sdcard/mysounds/hello.wav") 728 * 729 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 730 */ 731 public int addSpeech(String text, String filename) { 732 synchronized (mStartLock) { 733 mUtterances.put(text, Uri.parse(filename)); 734 return SUCCESS; 735 } 736 } 737 738 739 /** 740 * Adds a mapping between a string of text and a sound resource in a 741 * package. Use this to add custom earcons. 742 * 743 * @see #playEarcon(String, int, HashMap) 744 * 745 * @param earcon The name of the earcon. 746 * Example: <code>"[tick]"</code><br/> 747 * 748 * @param packagename 749 * the package name of the application that contains the 750 * resource. This can for instance be the package name of your own application. 751 * Example: <b>"com.google.marvin.compass"</b><br/> 752 * The package name can be found in the AndroidManifest.xml of 753 * the application containing the resource. 754 * <p> 755 * <code><manifest xmlns:android="..." 756 * package="<b>com.google.marvin.compass</b>"></code> 757 * </p> 758 * 759 * @param resourceId 760 * Example: <code>R.raw.tick_snd</code> 761 * 762 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 763 */ 764 public int addEarcon(String earcon, String packagename, int resourceId) { 765 synchronized(mStartLock) { 766 mEarcons.put(earcon, makeResourceUri(packagename, resourceId)); 767 return SUCCESS; 768 } 769 } 770 771 /** 772 * Adds a mapping between a string of text and a sound file. 773 * Use this to add custom earcons. 774 * 775 * @see #playEarcon(String, int, HashMap) 776 * 777 * @param earcon 778 * The name of the earcon. 779 * Example: <code>"[tick]"</code> 780 * @param filename 781 * The full path to the sound file (for example: 782 * "/sdcard/mysounds/tick.wav") 783 * 784 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 785 */ 786 public int addEarcon(String earcon, String filename) { 787 synchronized(mStartLock) { 788 mEarcons.put(earcon, Uri.parse(filename)); 789 return SUCCESS; 790 } 791 } 792 793 private Uri makeResourceUri(String packageName, int resourceId) { 794 return new Uri.Builder() 795 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 796 .encodedAuthority(packageName) 797 .appendEncodedPath(String.valueOf(resourceId)) 798 .build(); 799 } 800 801 /** 802 * Speaks the string using the specified queuing strategy and speech parameters. 803 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 804 * requests and then returns. The synthesis might not have finished (or even started!) at the 805 * time when this method returns. In order to reliably detect errors during synthesis, 806 * we recommend setting an utterance progress listener (see 807 * {@link #setOnUtteranceProgressListener}) and using the 808 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 809 * 810 * @param text The string of text to be spoken. No longer than 811 * {@link Engine#MAX_SPEECH_STRING_LENGTH} characters. 812 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 813 * @param params Parameters for the request. Can be null. 814 * Supported parameter names: 815 * {@link Engine#KEY_PARAM_STREAM}, 816 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, 817 * {@link Engine#KEY_PARAM_VOLUME}, 818 * {@link Engine#KEY_PARAM_PAN}. 819 * Engine specific parameters may be passed in but the parameter keys 820 * must be prefixed by the name of the engine they are intended for. For example 821 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 822 * engine named "com.svox.pico" if it is being used. 823 * 824 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation. 825 */ 826 public int speak(final String text, final int queueMode, final HashMap<String, String> params) { 827 return runAction(new Action<Integer>() { 828 @Override 829 public Integer run(ITextToSpeechService service) throws RemoteException { 830 Uri utteranceUri = mUtterances.get(text); 831 if (utteranceUri != null) { 832 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode, 833 getParams(params)); 834 } else { 835 return service.speak(getCallerIdentity(), text, queueMode, getParams(params)); 836 } 837 } 838 }, ERROR, "speak"); 839 } 840 841 /** 842 * Plays the earcon using the specified queueing mode and parameters. 843 * The earcon must already have been added with {@link #addEarcon(String, String)} or 844 * {@link #addEarcon(String, String, int)}. 845 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 846 * requests and then returns. The synthesis might not have finished (or even started!) at the 847 * time when this method returns. In order to reliably detect errors during synthesis, 848 * we recommend setting an utterance progress listener (see 849 * {@link #setOnUtteranceProgressListener}) and using the 850 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 851 * 852 * @param earcon The earcon that should be played 853 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 854 * @param params Parameters for the request. Can be null. 855 * Supported parameter names: 856 * {@link Engine#KEY_PARAM_STREAM}, 857 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 858 * Engine specific parameters may be passed in but the parameter keys 859 * must be prefixed by the name of the engine they are intended for. For example 860 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 861 * engine named "com.svox.pico" if it is being used. 862 * 863 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation. 864 */ 865 public int playEarcon(final String earcon, final int queueMode, 866 final HashMap<String, String> params) { 867 return runAction(new Action<Integer>() { 868 @Override 869 public Integer run(ITextToSpeechService service) throws RemoteException { 870 Uri earconUri = mEarcons.get(earcon); 871 if (earconUri == null) { 872 return ERROR; 873 } 874 return service.playAudio(getCallerIdentity(), earconUri, queueMode, 875 getParams(params)); 876 } 877 }, ERROR, "playEarcon"); 878 } 879 880 /** 881 * Plays silence for the specified amount of time using the specified 882 * queue mode. 883 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 884 * requests and then returns. The synthesis might not have finished (or even started!) at the 885 * time when this method returns. In order to reliably detect errors during synthesis, 886 * we recommend setting an utterance progress listener (see 887 * {@link #setOnUtteranceProgressListener}) and using the 888 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 889 * 890 * @param durationInMs The duration of the silence. 891 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 892 * @param params Parameters for the request. Can be null. 893 * Supported parameter names: 894 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 895 * Engine specific parameters may be passed in but the parameter keys 896 * must be prefixed by the name of the engine they are intended for. For example 897 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 898 * engine named "com.svox.pico" if it is being used. 899 * 900 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation. 901 */ 902 public int playSilence(final long durationInMs, final int queueMode, 903 final HashMap<String, String> params) { 904 return runAction(new Action<Integer>() { 905 @Override 906 public Integer run(ITextToSpeechService service) throws RemoteException { 907 return service.playSilence(getCallerIdentity(), durationInMs, queueMode, 908 getParams(params)); 909 } 910 }, ERROR, "playSilence"); 911 } 912 913 /** 914 * Queries the engine for the set of features it supports for a given locale. 915 * Features can either be framework defined, e.g. 916 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific. 917 * Engine specific keys must be prefixed by the name of the engine they 918 * are intended for. These keys can be used as parameters to 919 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and 920 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}. 921 * 922 * Features are boolean flags, and their values in the synthesis parameters 923 * must be behave as per {@link Boolean#parseBoolean(String)}. 924 * 925 * @param locale The locale to query features for. 926 */ 927 public Set<String> getFeatures(final Locale locale) { 928 return runAction(new Action<Set<String>>() { 929 @Override 930 public Set<String> run(ITextToSpeechService service) throws RemoteException { 931 String[] features = service.getFeaturesForLanguage( 932 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant()); 933 if (features != null) { 934 final Set<String> featureSet = new HashSet<String>(); 935 Collections.addAll(featureSet, features); 936 return featureSet; 937 } 938 return null; 939 } 940 }, null, "getFeatures"); 941 } 942 943 /** 944 * Checks whether the TTS engine is busy speaking. Note that a speech item is 945 * considered complete once it's audio data has been sent to the audio mixer, or 946 * written to a file. There might be a finite lag between this point, and when 947 * the audio hardware completes playback. 948 * 949 * @return {@code true} if the TTS engine is speaking. 950 */ 951 public boolean isSpeaking() { 952 return runAction(new Action<Boolean>() { 953 @Override 954 public Boolean run(ITextToSpeechService service) throws RemoteException { 955 return service.isSpeaking(); 956 } 957 }, false, "isSpeaking"); 958 } 959 960 /** 961 * Interrupts the current utterance (whether played or rendered to file) and discards other 962 * utterances in the queue. 963 * 964 * @return {@link #ERROR} or {@link #SUCCESS}. 965 */ 966 public int stop() { 967 return runAction(new Action<Integer>() { 968 @Override 969 public Integer run(ITextToSpeechService service) throws RemoteException { 970 return service.stop(getCallerIdentity()); 971 } 972 }, ERROR, "stop"); 973 } 974 975 /** 976 * Sets the speech rate. 977 * 978 * This has no effect on any pre-recorded speech. 979 * 980 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate, 981 * lower values slow down the speech ({@code 0.5} is half the normal speech rate), 982 * greater values accelerate it ({@code 2.0} is twice the normal speech rate). 983 * 984 * @return {@link #ERROR} or {@link #SUCCESS}. 985 */ 986 public int setSpeechRate(float speechRate) { 987 if (speechRate > 0.0f) { 988 int intRate = (int)(speechRate * 100); 989 if (intRate > 0) { 990 synchronized (mStartLock) { 991 mParams.putInt(Engine.KEY_PARAM_RATE, intRate); 992 } 993 return SUCCESS; 994 } 995 } 996 return ERROR; 997 } 998 999 /** 1000 * Sets the speech pitch for the TextToSpeech engine. 1001 * 1002 * This has no effect on any pre-recorded speech. 1003 * 1004 * @param pitch Speech pitch. {@code 1.0} is the normal pitch, 1005 * lower values lower the tone of the synthesized voice, 1006 * greater values increase it. 1007 * 1008 * @return {@link #ERROR} or {@link #SUCCESS}. 1009 */ 1010 public int setPitch(float pitch) { 1011 if (pitch > 0.0f) { 1012 int intPitch = (int)(pitch * 100); 1013 if (intPitch > 0) { 1014 synchronized (mStartLock) { 1015 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch); 1016 } 1017 return SUCCESS; 1018 } 1019 } 1020 return ERROR; 1021 } 1022 1023 /** 1024 * @return the engine currently in use by this TextToSpeech instance. 1025 * @hide 1026 */ 1027 public String getCurrentEngine() { 1028 return mCurrentEngine; 1029 } 1030 1031 /** 1032 * Sets the text-to-speech language. 1033 * The TTS engine will try to use the closest match to the specified 1034 * language as represented by the Locale, but there is no guarantee that the exact same Locale 1035 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support 1036 * before choosing the language to use for the next utterances. 1037 * 1038 * @param loc The locale describing the language to be used. 1039 * 1040 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1041 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1042 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1043 */ 1044 public int setLanguage(final Locale loc) { 1045 return runAction(new Action<Integer>() { 1046 @Override 1047 public Integer run(ITextToSpeechService service) throws RemoteException { 1048 if (loc == null) { 1049 return LANG_NOT_SUPPORTED; 1050 } 1051 String language = loc.getISO3Language(); 1052 String country = loc.getISO3Country(); 1053 String variant = loc.getVariant(); 1054 // Check if the language, country, variant are available, and cache 1055 // the available parts. 1056 // Note that the language is not actually set here, instead it is cached so it 1057 // will be associated with all upcoming utterances. 1058 int result = service.loadLanguage(language, country, variant); 1059 if (result >= LANG_AVAILABLE){ 1060 if (result < LANG_COUNTRY_VAR_AVAILABLE) { 1061 variant = ""; 1062 if (result < LANG_COUNTRY_AVAILABLE) { 1063 country = ""; 1064 } 1065 } 1066 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language); 1067 mParams.putString(Engine.KEY_PARAM_COUNTRY, country); 1068 mParams.putString(Engine.KEY_PARAM_VARIANT, variant); 1069 } 1070 return result; 1071 } 1072 }, LANG_NOT_SUPPORTED, "setLanguage"); 1073 } 1074 1075 /** 1076 * Returns a Locale instance describing the language currently being used by the TextToSpeech 1077 * engine. 1078 * 1079 * @return language, country (if any) and variant (if any) used by the engine stored in a Locale 1080 * instance, or {@code null} on error. 1081 */ 1082 public Locale getLanguage() { 1083 return runAction(new Action<Locale>() { 1084 @Override 1085 public Locale run(ITextToSpeechService service) throws RemoteException { 1086 String[] locStrings = service.getLanguage(); 1087 if (locStrings != null && locStrings.length == 3) { 1088 return new Locale(locStrings[0], locStrings[1], locStrings[2]); 1089 } 1090 return null; 1091 } 1092 }, null, "getLanguage"); 1093 } 1094 1095 /** 1096 * Checks if the specified language as represented by the Locale is available and supported. 1097 * 1098 * @param loc The Locale describing the language to be used. 1099 * 1100 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1101 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1102 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1103 */ 1104 public int isLanguageAvailable(final Locale loc) { 1105 return runAction(new Action<Integer>() { 1106 @Override 1107 public Integer run(ITextToSpeechService service) throws RemoteException { 1108 return service.isLanguageAvailable(loc.getISO3Language(), 1109 loc.getISO3Country(), loc.getVariant()); 1110 } 1111 }, LANG_NOT_SUPPORTED, "isLanguageAvailable"); 1112 } 1113 1114 /** 1115 * Synthesizes the given text to a file using the specified parameters. 1116 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1117 * requests and then returns. The synthesis might not have finished (or even started!) at the 1118 * time when this method returns. In order to reliably detect errors during synthesis, 1119 * we recommend setting an utterance progress listener (see 1120 * {@link #setOnUtteranceProgressListener}) and using the 1121 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1122 * 1123 * @param text The text that should be synthesized. No longer than 1124 * {@link Engine#MAX_SPEECH_STRING_LENGTH} characters. 1125 * @param params Parameters for the request. Can be null. 1126 * Supported parameter names: 1127 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 1128 * Engine specific parameters may be passed in but the parameter keys 1129 * must be prefixed by the name of the engine they are intended for. For example 1130 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1131 * engine named "com.svox.pico" if it is being used. 1132 * @param filename Absolute file filename to write the generated audio data to.It should be 1133 * something like "/sdcard/myappsounds/mysound.wav". 1134 * 1135 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation. 1136 */ 1137 public int synthesizeToFile(final String text, final HashMap<String, String> params, 1138 final String filename) { 1139 return runAction(new Action<Integer>() { 1140 @Override 1141 public Integer run(ITextToSpeechService service) throws RemoteException { 1142 return service.synthesizeToFile(getCallerIdentity(), text, filename, 1143 getParams(params)); 1144 } 1145 }, ERROR, "synthesizeToFile"); 1146 } 1147 1148 private Bundle getParams(HashMap<String, String> params) { 1149 if (params != null && !params.isEmpty()) { 1150 Bundle bundle = new Bundle(mParams); 1151 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM); 1152 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID); 1153 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME); 1154 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN); 1155 1156 // Copy feature strings defined by the framework. 1157 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS); 1158 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS); 1159 1160 // Copy over all parameters that start with the name of the 1161 // engine that we are currently connected to. The engine is 1162 // free to interpret them as it chooses. 1163 if (!TextUtils.isEmpty(mCurrentEngine)) { 1164 for (Map.Entry<String, String> entry : params.entrySet()) { 1165 final String key = entry.getKey(); 1166 if (key != null && key.startsWith(mCurrentEngine)) { 1167 bundle.putString(key, entry.getValue()); 1168 } 1169 } 1170 } 1171 1172 return bundle; 1173 } else { 1174 return mParams; 1175 } 1176 } 1177 1178 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) { 1179 String value = params.get(key); 1180 if (value != null) { 1181 bundle.putString(key, value); 1182 } 1183 } 1184 1185 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) { 1186 String valueString = params.get(key); 1187 if (!TextUtils.isEmpty(valueString)) { 1188 try { 1189 int value = Integer.parseInt(valueString); 1190 bundle.putInt(key, value); 1191 } catch (NumberFormatException ex) { 1192 // don't set the value in the bundle 1193 } 1194 } 1195 } 1196 1197 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) { 1198 String valueString = params.get(key); 1199 if (!TextUtils.isEmpty(valueString)) { 1200 try { 1201 float value = Float.parseFloat(valueString); 1202 bundle.putFloat(key, value); 1203 } catch (NumberFormatException ex) { 1204 // don't set the value in the bundle 1205 } 1206 } 1207 } 1208 1209 /** 1210 * Sets the listener that will be notified when synthesis of an utterance completes. 1211 * 1212 * @param listener The listener to use. 1213 * 1214 * @return {@link #ERROR} or {@link #SUCCESS}. 1215 * 1216 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)} 1217 * instead. 1218 */ 1219 @Deprecated 1220 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) { 1221 mUtteranceProgressListener = UtteranceProgressListener.from(listener); 1222 return TextToSpeech.SUCCESS; 1223 } 1224 1225 /** 1226 * Sets the listener that will be notified of various events related to the 1227 * synthesis of a given utterance. 1228 * 1229 * See {@link UtteranceProgressListener} and 1230 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}. 1231 * 1232 * @param listener the listener to use. 1233 * @return {@link #ERROR} or {@link #SUCCESS} 1234 */ 1235 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) { 1236 mUtteranceProgressListener = listener; 1237 return TextToSpeech.SUCCESS; 1238 } 1239 1240 /** 1241 * Sets the TTS engine to use. 1242 * 1243 * @deprecated This doesn't inform callers when the TTS engine has been 1244 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)} 1245 * can be used with the appropriate engine name. Also, there is no 1246 * guarantee that the engine specified will be loaded. If it isn't 1247 * installed or disabled, the user / system wide defaults will apply. 1248 * 1249 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico") 1250 * 1251 * @return {@link #ERROR} or {@link #SUCCESS}. 1252 */ 1253 @Deprecated 1254 public int setEngineByPackageName(String enginePackageName) { 1255 mRequestedEngine = enginePackageName; 1256 return initTts(); 1257 } 1258 1259 /** 1260 * Gets the package name of the default speech synthesis engine. 1261 * 1262 * @return Package name of the TTS engine that the user has chosen 1263 * as their default. 1264 */ 1265 public String getDefaultEngine() { 1266 return mEnginesHelper.getDefaultEngine(); 1267 } 1268 1269 /** 1270 * Checks whether the user's settings should override settings requested 1271 * by the calling application. As of the Ice cream sandwich release, 1272 * user settings never forcibly override the app's settings. 1273 */ 1274 public boolean areDefaultsEnforced() { 1275 return false; 1276 } 1277 1278 /** 1279 * Gets a list of all installed TTS engines. 1280 * 1281 * @return A list of engine info objects. The list can be empty, but never {@code null}. 1282 */ 1283 public List<EngineInfo> getEngines() { 1284 return mEnginesHelper.getEngines(); 1285 } 1286 1287 1288 private class Connection implements ServiceConnection { 1289 private ITextToSpeechService mService; 1290 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() { 1291 @Override 1292 public void onDone(String utteranceId) { 1293 UtteranceProgressListener listener = mUtteranceProgressListener; 1294 if (listener != null) { 1295 listener.onDone(utteranceId); 1296 } 1297 } 1298 1299 @Override 1300 public void onError(String utteranceId) { 1301 UtteranceProgressListener listener = mUtteranceProgressListener; 1302 if (listener != null) { 1303 listener.onError(utteranceId); 1304 } 1305 } 1306 1307 @Override 1308 public void onStart(String utteranceId) { 1309 UtteranceProgressListener listener = mUtteranceProgressListener; 1310 if (listener != null) { 1311 listener.onStart(utteranceId); 1312 } 1313 } 1314 }; 1315 1316 @Override 1317 public void onServiceConnected(ComponentName name, IBinder service) { 1318 Log.i(TAG, "Connected to " + name); 1319 synchronized(mStartLock) { 1320 if (mServiceConnection != null) { 1321 // Disconnect any previous service connection 1322 mServiceConnection.disconnect(); 1323 } 1324 mServiceConnection = this; 1325 mService = ITextToSpeechService.Stub.asInterface(service); 1326 try { 1327 mService.setCallback(getCallerIdentity(), mCallback); 1328 dispatchOnInit(SUCCESS); 1329 } catch (RemoteException re) { 1330 Log.e(TAG, "Error connecting to service, setCallback() failed"); 1331 dispatchOnInit(ERROR); 1332 } 1333 } 1334 } 1335 1336 public IBinder getCallerIdentity() { 1337 return mCallback; 1338 } 1339 1340 @Override 1341 public void onServiceDisconnected(ComponentName name) { 1342 synchronized(mStartLock) { 1343 mService = null; 1344 // If this is the active connection, clear it 1345 if (mServiceConnection == this) { 1346 mServiceConnection = null; 1347 } 1348 } 1349 } 1350 1351 public void disconnect() { 1352 mContext.unbindService(this); 1353 1354 synchronized (mStartLock) { 1355 mService = null; 1356 // If this is the active connection, clear it 1357 if (mServiceConnection == this) { 1358 mServiceConnection = null; 1359 } 1360 1361 } 1362 } 1363 1364 public <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) { 1365 synchronized (mStartLock) { 1366 try { 1367 if (mService == null) { 1368 Log.w(TAG, method + " failed: not connected to TTS engine"); 1369 return errorResult; 1370 } 1371 return action.run(mService); 1372 } catch (RemoteException ex) { 1373 Log.e(TAG, method + " failed", ex); 1374 if (reconnect) { 1375 disconnect(); 1376 initTts(); 1377 } 1378 return errorResult; 1379 } 1380 } 1381 } 1382 } 1383 1384 private interface Action<R> { 1385 R run(ITextToSpeechService service) throws RemoteException; 1386 } 1387 1388 /** 1389 * Information about an installed text-to-speech engine. 1390 * 1391 * @see TextToSpeech#getEngines 1392 */ 1393 public static class EngineInfo { 1394 /** 1395 * Engine package name.. 1396 */ 1397 public String name; 1398 /** 1399 * Localized label for the engine. 1400 */ 1401 public String label; 1402 /** 1403 * Icon for the engine. 1404 */ 1405 public int icon; 1406 /** 1407 * Whether this engine is a part of the system 1408 * image. 1409 * 1410 * @hide 1411 */ 1412 public boolean system; 1413 /** 1414 * The priority the engine declares for the the intent filter 1415 * {@code android.intent.action.TTS_SERVICE} 1416 * 1417 * @hide 1418 */ 1419 public int priority; 1420 1421 @Override 1422 public String toString() { 1423 return "EngineInfo{name=" + name + "}"; 1424 } 1425 1426 } 1427 1428} 1429