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