OSDN Git Service

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