blob: 1d26c22c7169a4afa2e9371ff81393d6448caa85 [file] [log] [blame]
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001/*
Bjorn Bringert50e657b2011-03-08 16:00:40 +00002 * Copyright (C) 2009 The Android Open Source Project
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07003 *
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 */
Jean-Michel Trivi21a6a6d2009-06-08 15:21:46 -070016package android.speech.tts;
17
Jean-Michel Trivied065782009-07-28 14:31:48 -070018import android.annotation.SdkConstant;
19import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070020import android.content.ComponentName;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000021import android.content.ContentResolver;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070022import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000025import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.content.pm.ServiceInfo;
Jean-Michel Trivia9810132009-07-10 12:08:59 -070028import android.media.AudioManager;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000029import android.net.Uri;
30import android.os.Bundle;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070031import android.os.IBinder;
32import android.os.RemoteException;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000033import android.provider.Settings;
34import android.text.TextUtils;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070035import android.util.Log;
36
Bjorn Bringert50e657b2011-03-08 16:00:40 +000037import java.util.ArrayList;
38import java.util.Collections;
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070039import java.util.HashMap;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000040import java.util.List;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070041import java.util.Locale;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000042import java.util.Map;
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070043
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070044/**
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070045 *
Jean-Michel Trivi62788e92009-07-02 16:29:30 -070046 * Synthesizes speech from text for immediate playback or to create a sound file.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -070047 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its
48 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be
49 * notified of the completion of the initialization.<br>
50 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method
51 * to release the native resources used by the TextToSpeech engine.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070052 *
53 */
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070054public class TextToSpeech {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070055
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +000056 private static final String TAG = "TextToSpeech";
57
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070058 /**
59 * Denotes a successful operation.
60 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000061 public static final int SUCCESS = 0;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070062 /**
63 * Denotes a generic operation failure.
64 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000065 public static final int ERROR = -1;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070066
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070067 /**
68 * Queue mode where all entries in the playback queue (media to be played
69 * and text to be synthesized) are dropped and replaced by the new entry.
70 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070071 public static final int QUEUE_FLUSH = 0;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070072 /**
73 * Queue mode where the new entry is added at the end of the playback queue.
74 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070075 public static final int QUEUE_ADD = 1;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070076
Charles Chenaaf842e2009-06-25 11:59:29 -070077 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -070078 * Denotes the language is available exactly as specified by the locale.
Charles Chenaaf842e2009-06-25 11:59:29 -070079 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070080 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
Charles Chenaaf842e2009-06-25 11:59:29 -070081
Charles Chenaaf842e2009-06-25 11:59:29 -070082 /**
83 * Denotes the language is available for the language and country specified
84 * by the locale, but not the variant.
85 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070086 public static final int LANG_COUNTRY_AVAILABLE = 1;
Charles Chenaaf842e2009-06-25 11:59:29 -070087
Charles Chenaaf842e2009-06-25 11:59:29 -070088 /**
89 * Denotes the language is available for the language by the locale,
90 * but not the country and variant.
91 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070092 public static final int LANG_AVAILABLE = 0;
Charles Chenaaf842e2009-06-25 11:59:29 -070093
94 /**
95 * Denotes the language data is missing.
96 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070097 public static final int LANG_MISSING_DATA = -1;
Charles Chenaaf842e2009-06-25 11:59:29 -070098
99 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700100 * Denotes the language is not supported.
Charles Chenaaf842e2009-06-25 11:59:29 -0700101 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700102 public static final int LANG_NOT_SUPPORTED = -2;
103
Jean-Michel Trivied065782009-07-28 14:31:48 -0700104 /**
105 * Broadcast Action: The TextToSpeech synthesizer has completed processing
106 * of all the text in the speech queue.
107 */
108 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
109 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
110 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
Charles Chenaaf842e2009-06-25 11:59:29 -0700111
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700112 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700113 * Interface definition of a callback to be invoked indicating the completion of the
114 * TextToSpeech engine initialization.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700115 */
116 public interface OnInitListener {
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700117 /**
118 * Called to signal the completion of the TextToSpeech engine initialization.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000119 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700120 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
121 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700122 public void onInit(int status);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700123 }
124
125 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000126 * Listener that will be called when the TTS service has
127 * completed synthesizing an utterance. This is only called if the utterance
128 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
Charles Chen78c9d0d2009-07-13 16:22:41 -0700129 */
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700130 public interface OnUtteranceCompletedListener {
131 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000132 * Called when an utterance has been synthesized.
133 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700134 * @param utteranceId the identifier of the utterance.
Charles Chen60dd3602010-01-07 18:56:24 -0800135 */
136 public void onUtteranceCompleted(String utteranceId);
Charles Chen78c9d0d2009-07-13 16:22:41 -0700137 }
138
Charles Chen78c9d0d2009-07-13 16:22:41 -0700139 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000140 * Constants and parameter names for controlling text-to-speech.
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700141 */
142 public class Engine {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000143
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700144 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000145 * Default speech rate.
146 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700147 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000148 public static final int DEFAULT_RATE = 100;
149
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700150 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000151 * Default pitch.
152 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700153 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000154 public static final int DEFAULT_PITCH = 100;
155
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700156 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000157 * Default volume.
158 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700159 */
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800160 public static final float DEFAULT_VOLUME = 1.0f;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000161
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800162 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000163 * Default pan (centered).
164 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800165 */
166 public static final float DEFAULT_PAN = 0.0f;
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800167
168 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000169 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}.
170 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800171 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700172 public static final int USE_DEFAULTS = 0; // false
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700173
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000174 /**
175 * Package name of the default TTS engine.
176 *
177 * TODO: This should come from a system property
178 *
179 * @hide
180 */
181 public static final String DEFAULT_ENGINE = "com.svox.pico";
182
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700183 /**
184 * Default audio stream used when playing synthesized speech.
185 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700186 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700187
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700188 /**
189 * Indicates success when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700190 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700191 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700192 public static final int CHECK_VOICE_DATA_PASS = 1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000193
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700194 /**
195 * Indicates failure when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700196 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700197 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700198 public static final int CHECK_VOICE_DATA_FAIL = 0;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000199
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700200 /**
201 * Indicates erroneous data when checking the installation status of the resources used by
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700202 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700203 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700204 public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000205
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700206 /**
207 * Indicates missing resources when checking the installation status of the resources used
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700208 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700209 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700210 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000211
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700212 /**
213 * Indicates missing storage volume when checking the installation status of the resources
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700214 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700215 */
216 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
Charles Chen99a0fee2009-07-02 10:41:51 -0700217
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000218 /**
219 * Intent for starting a TTS service. Services that handle this intent must
220 * extend {@link TextToSpeechService}. Normal applications should not use this intent
221 * directly, instead they should talk to the TTS service using the the methods in this
222 * class.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000223 */
224 @SdkConstant(SdkConstantType.SERVICE_ACTION)
225 public static final String INTENT_ACTION_TTS_SERVICE =
226 "android.intent.action.TTS_SERVICE";
227
Jean-Michel Trivied065782009-07-28 14:31:48 -0700228 // intents to ask engine to install data or check its data
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700229 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700230 * Activity Action: Triggers the platform TextToSpeech engine to
Jean-Michel Trivied065782009-07-28 14:31:48 -0700231 * start the activity that installs the resource files on the device
232 * that are required for TTS to be operational. Since the installation
233 * of the data can be interrupted or declined by the user, the application
234 * shouldn't expect successful installation upon return from that intent,
235 * and if need be, should check installation status with
236 * {@link #ACTION_CHECK_TTS_DATA}.
237 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700238 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700239 public static final String ACTION_INSTALL_TTS_DATA =
240 "android.speech.tts.engine.INSTALL_TTS_DATA";
241
242 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700243 * Broadcast Action: broadcast to signal the completion of the installation of
244 * the data files used by the synthesis engine. Success or failure is indicated in the
245 * {@link #EXTRA_TTS_DATA_INSTALLED} extra.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700246 */
247 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
248 public static final String ACTION_TTS_DATA_INSTALLED =
249 "android.speech.tts.engine.TTS_DATA_INSTALLED";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000250
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700251 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700252 * Activity Action: Starts the activity from the platform TextToSpeech
Jean-Michel Trivied065782009-07-28 14:31:48 -0700253 * engine to verify the proper installation and availability of the
254 * resource files on the system. Upon completion, the activity will
255 * return one of the following codes:
256 * {@link #CHECK_VOICE_DATA_PASS},
257 * {@link #CHECK_VOICE_DATA_FAIL},
258 * {@link #CHECK_VOICE_DATA_BAD_DATA},
259 * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or
260 * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}.
261 * <p> Moreover, the data received in the activity result will contain the following
262 * fields:
263 * <ul>
264 * <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700265 * indicates the path to the location of the resource files,</li>
Jean-Michel Trivied065782009-07-28 14:31:48 -0700266 * <li>{@link #EXTRA_VOICE_DATA_FILES} which contains
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700267 * the list of all the resource files,</li>
Jean-Michel Trivied065782009-07-28 14:31:48 -0700268 * <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which
269 * contains, for each resource file, the description of the language covered by
270 * the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
271 * and YYY is the 3-letter ISO country code.</li>
272 * </ul>
273 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700274 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700275 public static final String ACTION_CHECK_TTS_DATA =
276 "android.speech.tts.engine.CHECK_TTS_DATA";
277
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000278 /**
279 * Activity intent for getting some sample text to use for demonstrating TTS.
280 *
281 * @hide This intent was used by engines written against the old API.
282 * Not sure if it should be exposed.
283 */
284 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
285 public static final String ACTION_GET_SAMPLE_TEXT =
286 "android.speech.tts.engine.GET_SAMPLE_TEXT";
287
Jean-Michel Trivied065782009-07-28 14:31:48 -0700288 // extras for a TTS engine's check data activity
289 /**
290 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700291 * the TextToSpeech engine specifies the path to its resources.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700292 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700293 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000294
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700295 /**
Jean-Michel Trivied065782009-07-28 14:31:48 -0700296 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700297 * the TextToSpeech engine specifies the file names of its resources under the
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700298 * resource path.
299 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700300 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000301
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700302 /**
Jean-Michel Trivied065782009-07-28 14:31:48 -0700303 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700304 * the TextToSpeech engine specifies the locale associated with each resource file.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700305 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700306 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000307
Charles Chen76d9c3c2010-02-11 16:44:45 -0800308 /**
309 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
310 * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
311 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
312 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
313 */
314 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000315
Charles Chen76d9c3c2010-02-11 16:44:45 -0800316 /**
317 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
318 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
319 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
320 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
321 */
322 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000323
Charles Chen76d9c3c2010-02-11 16:44:45 -0800324 /**
325 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
326 * caller indicates to the TextToSpeech engine which specific sets of voice data to
327 * check for by sending an ArrayList<String> of the voices that are of interest.
328 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
329 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
330 */
331 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
Charles Chen99a0fee2009-07-02 10:41:51 -0700332
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700333 // extras for a TTS engine's data installation
334 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700335 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent.
336 * It indicates whether the data files for the synthesis engine were successfully
337 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA}
338 * intent. The possible values for this extra are
339 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700340 */
341 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
342
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700343 // keys for the parameters passed with speak commands. Hidden keys are used internally
344 // to maintain engine state for each TextToSpeech instance.
345 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000346 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700347 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700348 public static final String KEY_PARAM_RATE = "rate";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000349
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700350 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000351 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700352 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700353 public static final String KEY_PARAM_LANGUAGE = "language";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000354
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700355 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000356 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700357 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700358 public static final String KEY_PARAM_COUNTRY = "country";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000359
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700360 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000361 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700362 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700363 public static final String KEY_PARAM_VARIANT = "variant";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000364
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700365 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000366 * @hide
Charles Chen60dd3602010-01-07 18:56:24 -0800367 */
368 public static final String KEY_PARAM_ENGINE = "engine";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000369
Charles Chen60dd3602010-01-07 18:56:24 -0800370 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000371 * @hide
Charles Chen1a2712c2010-04-01 17:16:28 -0700372 */
373 public static final String KEY_PARAM_PITCH = "pitch";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000374
Charles Chen1a2712c2010-04-01 17:16:28 -0700375 /**
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700376 * Parameter key to specify the audio stream type to be used when speaking text
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000377 * or playing back a file. The value should be one of the STREAM_ constants
378 * defined in {@link AudioManager}.
379 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700380 * @see TextToSpeech#speak(String, int, HashMap)
381 * @see TextToSpeech#playEarcon(String, int, HashMap)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700382 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700383 public static final String KEY_PARAM_STREAM = "streamType";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000384
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700385 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700386 * Parameter key to identify an utterance in the
387 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700388 * spoken, a file has been played back or a silence duration has elapsed.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000389 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700390 * @see TextToSpeech#speak(String, int, HashMap)
391 * @see TextToSpeech#playEarcon(String, int, HashMap)
392 * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700393 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700394 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000395
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800396 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800397 * Parameter key to specify the speech volume relative to the current stream type
398 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
Jean-Michel Trivi9011ec82011-01-11 11:55:00 -0800399 * where 0 is silence, and 1 is the maximum volume (the default behavior).
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000400 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800401 * @see TextToSpeech#speak(String, int, HashMap)
402 * @see TextToSpeech#playEarcon(String, int, HashMap)
403 */
404 public static final String KEY_PARAM_VOLUME = "volume";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000405
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800406 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800407 * Parameter key to specify how the speech is panned from left to right when speaking text.
408 * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
Jean-Michel Trivi9011ec82011-01-11 11:55:00 -0800409 * 0 to center (the default behavior), and +1 to hard-right.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000410 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800411 * @see TextToSpeech#speak(String, int, HashMap)
412 * @see TextToSpeech#playEarcon(String, int, HashMap)
413 */
414 public static final String KEY_PARAM_PAN = "pan";
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700415
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700416 }
417
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000418 private final Context mContext;
419 private Connection mServiceConnection;
420 private OnInitListener mInitListener;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700421 private final Object mStartLock = new Object();
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000422
423 private String mRequestedEngine;
424 private final Map<String, Uri> mEarcons;
425 private final Map<String, Uri> mUtterances;
426 private final Bundle mParams = new Bundle();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700427
428 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100429 * The constructor for the TextToSpeech class, using the default TTS engine.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700430 * This will also initialize the associated TextToSpeech engine if it isn't already running.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700431 *
432 * @param context
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700433 * The context this instance is running in.
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700434 * @param listener
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700435 * The {@link TextToSpeech.OnInitListener} that will be called when the
436 * TextToSpeech engine has initialized.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700437 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700438 public TextToSpeech(Context context, OnInitListener listener) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000439 this(context, listener, null);
440 }
441
442 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100443 * The constructor for the TextToSpeech class, using the given TTS engine.
444 * This will also initialize the associated TextToSpeech engine if it isn't already running.
445 *
446 * @param context
447 * The context this instance is running in.
448 * @param listener
449 * The {@link TextToSpeech.OnInitListener} that will be called when the
450 * TextToSpeech engine has initialized.
451 * @param engine Package name of the TTS engine to use.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000452 */
453 public TextToSpeech(Context context, OnInitListener listener, String engine) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700454 mContext = context;
455 mInitListener = listener;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000456 mRequestedEngine = engine;
Jean-Michel Trivi87c96842009-06-25 14:29:15 -0700457
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000458 mEarcons = new HashMap<String, Uri>();
459 mUtterances = new HashMap<String, Uri>();
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700460
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700461 initTts();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700462 }
463
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000464 private String getPackageName() {
465 return mContext.getPackageName();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700466 }
467
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000468 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) {
469 return runAction(action, errorResult, method, false);
470 }
471
472 private <R> R runAction(Action<R> action, R errorResult, String method) {
473 return runAction(action, errorResult, method, true);
474 }
475
476 private <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
477 synchronized (mStartLock) {
478 if (mServiceConnection == null) {
479 Log.w(TAG, method + " failed: not bound to TTS engine");
480 return errorResult;
481 }
482 return mServiceConnection.runAction(action, errorResult, method, reconnect);
483 }
484 }
485
486 private int initTts() {
487 String defaultEngine = getDefaultEngine();
488 String engine = defaultEngine;
489 if (!areDefaultsEnforced() && !TextUtils.isEmpty(mRequestedEngine)
490 && isEngineEnabled(engine)) {
491 engine = mRequestedEngine;
492 }
493
494 // Try requested engine
495 if (connectToEngine(engine)) {
496 return SUCCESS;
497 }
498
499 // Fall back to user's default engine if different from the already tested one
500 if (!engine.equals(defaultEngine)) {
501 if (connectToEngine(defaultEngine)) {
502 return SUCCESS;
503 }
504 }
505
506 // Fall back to the hardcoded default if different from the two above
507 if (!defaultEngine.equals(Engine.DEFAULT_ENGINE)
508 && !engine.equals(Engine.DEFAULT_ENGINE)) {
509 if (connectToEngine(Engine.DEFAULT_ENGINE)) {
510 return SUCCESS;
511 }
512 }
513
514 return ERROR;
515 }
516
517 private boolean connectToEngine(String engine) {
518 Connection connection = new Connection();
519 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
520 intent.setPackage(engine);
521 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
522 if (!bound) {
523 Log.e(TAG, "Failed to bind to " + engine);
524 dispatchOnInit(ERROR);
525 return false;
526 } else {
527 return true;
528 }
529 }
530
531 private void dispatchOnInit(int result) {
532 synchronized (mStartLock) {
533 if (mInitListener != null) {
534 mInitListener.onInit(result);
535 mInitListener = null;
536 }
537 }
538 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700539
540 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700541 * Releases the resources used by the TextToSpeech engine.
542 * It is good practice for instance to call this method in the onDestroy() method of an Activity
543 * so the TextToSpeech engine can be cleanly stopped.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700544 */
545 public void shutdown() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000546 runActionNoReconnect(new Action<Void>() {
547 @Override
548 public Void run(ITextToSpeechService service) throws RemoteException {
549 service.setCallback(getPackageName(), null);
550 service.stop(getPackageName());
551 mServiceConnection.disconnect();
552 return null;
553 }
554 }, null, "shutdown");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700555 }
556
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700557 /**
558 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700559 * package. After a call to this method, subsequent calls to
560 * {@link #speak(String, int, HashMap)} will play the specified sound resource
561 * if it is available, or synthesize the text it is missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700562 *
563 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700564 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700565 *
566 * @param packagename
567 * Pass the packagename of the application that contains the
568 * resource. If the resource is in your own application (this is
569 * the most common case), then put the packagename of your
570 * application here.<br/>
571 * Example: <b>"com.google.marvin.compass"</b><br/>
572 * The packagename can be found in the AndroidManifest.xml of
573 * your application.
574 * <p>
575 * <code>&lt;manifest xmlns:android=&quot;...&quot;
576 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
577 * </p>
578 *
579 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700580 * Example: <code>R.raw.south_south_east</code>
Charles Chen5c22f512009-06-29 15:52:47 -0700581 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700582 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700583 */
Charles Chen5c22f512009-06-29 15:52:47 -0700584 public int addSpeech(String text, String packagename, int resourceId) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000585 synchronized (mStartLock) {
586 mUtterances.put(text, makeResourceUri(packagename, resourceId));
587 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700588 }
589 }
590
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700591 /**
592 * Adds a mapping between a string of text and a sound file. Using this, it
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700593 * is possible to add custom pronounciations for a string of text.
594 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
595 * will play the specified sound resource if it is available, or synthesize the text it is
596 * missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700597 *
598 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700599 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700600 * @param filename
601 * The full path to the sound file (for example:
602 * "/sdcard/mysounds/hello.wav")
Charles Chen5c22f512009-06-29 15:52:47 -0700603 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700604 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700605 */
Charles Chen5c22f512009-06-29 15:52:47 -0700606 public int addSpeech(String text, String filename) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700607 synchronized (mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000608 mUtterances.put(text, Uri.parse(filename));
609 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700610 }
611 }
612
613
614 /**
Charles Chen904dfa52009-07-15 10:44:41 -0700615 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700616 * package. Use this to add custom earcons.
Charles Chen904dfa52009-07-15 10:44:41 -0700617 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700618 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700619 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700620 * @param earcon The name of the earcon.
621 * Example: <code>"[tick]"</code><br/>
Charles Chen904dfa52009-07-15 10:44:41 -0700622 *
623 * @param packagename
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700624 * the package name of the application that contains the
625 * resource. This can for instance be the package name of your own application.
Charles Chen904dfa52009-07-15 10:44:41 -0700626 * Example: <b>"com.google.marvin.compass"</b><br/>
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700627 * The package name can be found in the AndroidManifest.xml of
628 * the application containing the resource.
Charles Chen904dfa52009-07-15 10:44:41 -0700629 * <p>
630 * <code>&lt;manifest xmlns:android=&quot;...&quot;
631 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
632 * </p>
633 *
634 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700635 * Example: <code>R.raw.tick_snd</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700636 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700637 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700638 */
639 public int addEarcon(String earcon, String packagename, int resourceId) {
640 synchronized(mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000641 mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
642 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700643 }
644 }
645
Charles Chen904dfa52009-07-15 10:44:41 -0700646 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700647 * Adds a mapping between a string of text and a sound file.
648 * Use this to add custom earcons.
649 *
650 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700651 *
652 * @param earcon
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700653 * The name of the earcon.
654 * Example: <code>"[tick]"</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700655 * @param filename
656 * The full path to the sound file (for example:
657 * "/sdcard/mysounds/tick.wav")
658 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700659 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700660 */
661 public int addEarcon(String earcon, String filename) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000662 synchronized(mStartLock) {
663 mEarcons.put(earcon, Uri.parse(filename));
664 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700665 }
666 }
667
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000668 private Uri makeResourceUri(String packageName, int resourceId) {
669 return new Uri.Builder()
670 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
671 .encodedAuthority(packageName)
672 .appendEncodedPath(String.valueOf(resourceId))
673 .build();
674 }
Charles Chen904dfa52009-07-15 10:44:41 -0700675
676 /**
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700677 * Speaks the string using the specified queuing strategy and speech
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700678 * parameters.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700679 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000680 * @param text The string of text to be spoken.
681 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
682 * @param params Parameters for the request. Can be null.
683 * Supported parameter names:
684 * {@link Engine#KEY_PARAM_STREAM},
685 * {@link Engine#KEY_PARAM_UTTERANCE_ID},
686 * {@link Engine#KEY_PARAM_VOLUME},
687 * {@link Engine#KEY_PARAM_PAN}.
Charles Chen5c22f512009-06-29 15:52:47 -0700688 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000689 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700690 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000691 public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
692 return runAction(new Action<Integer>() {
693 @Override
694 public Integer run(ITextToSpeechService service) throws RemoteException {
695 Uri utteranceUri = mUtterances.get(text);
696 if (utteranceUri != null) {
697 return service.playAudio(getPackageName(), utteranceUri, queueMode,
698 getParams(params));
699 } else {
700 return service.speak(getPackageName(), text, queueMode, getParams(params));
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700701 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700702 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000703 }, ERROR, "speak");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700704 }
705
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700706 /**
707 * Plays the earcon using the specified queueing mode and parameters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000708 * The earcon must already have been added with {@link #addEarcon(String, String)} or
709 * {@link #addEarcon(String, String, int)}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700710 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000711 * @param earcon The earcon that should be played
712 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
713 * @param params Parameters for the request. Can be null.
714 * Supported parameter names:
715 * {@link Engine#KEY_PARAM_STREAM},
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700716 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Charles Chen5c22f512009-06-29 15:52:47 -0700717 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000718 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700719 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000720 public int playEarcon(final String earcon, final int queueMode,
721 final HashMap<String, String> params) {
722 return runAction(new Action<Integer>() {
723 @Override
724 public Integer run(ITextToSpeechService service) throws RemoteException {
725 Uri earconUri = mEarcons.get(earcon);
726 if (earconUri == null) {
727 return ERROR;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700728 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000729 return service.playAudio(getPackageName(), earconUri, queueMode,
730 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700731 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000732 }, ERROR, "playEarcon");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700733 }
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700734
Charles Chen5c22f512009-06-29 15:52:47 -0700735 /**
736 * Plays silence for the specified amount of time using the specified
737 * queue mode.
738 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000739 * @param durationInMs The duration of the silence.
740 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
741 * @param params Parameters for the request. Can be null.
742 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700743 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Charles Chen5c22f512009-06-29 15:52:47 -0700744 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000745 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chen5c22f512009-06-29 15:52:47 -0700746 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000747 public int playSilence(final long durationInMs, final int queueMode,
748 final HashMap<String, String> params) {
749 return runAction(new Action<Integer>() {
750 @Override
751 public Integer run(ITextToSpeechService service) throws RemoteException {
752 return service.playSilence(getPackageName(), durationInMs, queueMode,
753 getParams(params));
Charles Chenf032bc72009-06-26 14:41:55 -0700754 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000755 }, ERROR, "playSilence");
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700756 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700757
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700758 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000759 * Checks whether the TTS engine is busy speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700760 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000761 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700762 */
763 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000764 return runAction(new Action<Boolean>() {
765 @Override
766 public Boolean run(ITextToSpeechService service) throws RemoteException {
767 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700768 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000769 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700770 }
771
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700772 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700773 * Interrupts the current utterance (whether played or rendered to file) and discards other
774 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -0700775 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000776 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700777 */
Charles Chen5c22f512009-06-29 15:52:47 -0700778 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000779 return runAction(new Action<Integer>() {
780 @Override
781 public Integer run(ITextToSpeechService service) throws RemoteException {
782 return service.stop(getPackageName());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700783 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000784 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700785 }
786
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700787 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000788 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700789 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700790 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700791 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000792 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
793 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
794 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -0700795 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000796 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700797 */
Charles Chen5c22f512009-06-29 15:52:47 -0700798 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000799 if (speechRate > 0.0f) {
800 int intRate = (int)(speechRate * 100);
801 if (intRate > 0) {
802 synchronized (mStartLock) {
803 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700804 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000805 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700806 }
807 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000808 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700809 }
810
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700811 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700812 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700813 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700814 * This has no effect on any pre-recorded speech.
815 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000816 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700817 * lower values lower the tone of the synthesized voice,
818 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -0700819 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000820 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700821 */
Charles Chen5c22f512009-06-29 15:52:47 -0700822 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000823 if (pitch > 0.0f) {
824 int intPitch = (int)(pitch * 100);
825 if (intPitch > 0) {
826 synchronized (mStartLock) {
827 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700828 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000829 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700830 }
831 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000832 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700833 }
834
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -0700835 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000836 * Sets the text-to-speech language.
837 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700838 * language as represented by the Locale, but there is no guarantee that the exact same Locale
839 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
840 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700841 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000842 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -0700843 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000844 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -0700845 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
846 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700847 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000848 public int setLanguage(final Locale loc) {
849 return runAction(new Action<Integer>() {
850 @Override
851 public Integer run(ITextToSpeechService service) throws RemoteException {
852 if (loc == null) {
853 return LANG_NOT_SUPPORTED;
854 }
Charles Chen1a2712c2010-04-01 17:16:28 -0700855 String language = loc.getISO3Language();
856 String country = loc.getISO3Country();
857 String variant = loc.getVariant();
858 // Check if the language, country, variant are available, and cache
859 // the available parts.
860 // Note that the language is not actually set here, instead it is cached so it
861 // will be associated with all upcoming utterances.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000862 int result = service.loadLanguage(language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -0700863 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000864 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
865 variant = "";
866 if (result < LANG_COUNTRY_AVAILABLE) {
867 country = "";
868 }
Charles Chen1a2712c2010-04-01 17:16:28 -0700869 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000870 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
871 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
872 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -0700873 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000874 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700875 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000876 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700877 }
878
Charles Chenaaf842e2009-06-25 11:59:29 -0700879 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700880 * Returns a Locale instance describing the language currently being used by the TextToSpeech
881 * engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000882 *
Jean-Michel Trividdb0a802009-06-29 16:38:47 -0700883 * @return language, country (if any) and variant (if any) used by the engine stored in a Locale
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000884 * instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -0700885 */
886 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000887 return runAction(new Action<Locale>() {
888 @Override
889 public Locale run(ITextToSpeechService service) throws RemoteException {
890 String[] locStrings = service.getLanguage();
891 if (locStrings != null && locStrings.length == 3) {
892 return new Locale(locStrings[0], locStrings[1], locStrings[2]);
893 }
Jean-Michel Trividdb0a802009-06-29 16:38:47 -0700894 return null;
895 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000896 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -0700897 }
898
899 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700900 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -0700901 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000902 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -0700903 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000904 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -0700905 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
906 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -0700907 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000908 public int isLanguageAvailable(final Locale loc) {
909 return runAction(new Action<Integer>() {
910 @Override
911 public Integer run(ITextToSpeechService service) throws RemoteException {
912 return service.isLanguageAvailable(loc.getISO3Language(),
913 loc.getISO3Country(), loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -0700914 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000915 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -0700916 }
917
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700918 /**
Charles Chend4989092009-06-26 15:32:46 -0700919 * Synthesizes the given text to a file using the specified parameters.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700920 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000921 * @param text Thetext that should be synthesized
922 * @param params Parameters for the request. Can be null.
923 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700924 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000925 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700926 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -0700927 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000928 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700929 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000930 public int synthesizeToFile(final String text, final HashMap<String, String> params,
931 final String filename) {
932 return runAction(new Action<Integer>() {
933 @Override
934 public Integer run(ITextToSpeechService service) throws RemoteException {
935 return service.synthesizeToFile(getPackageName(), text, filename,
936 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700937 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000938 }, ERROR, "synthesizeToFile");
939 }
940
941 private Bundle getParams(HashMap<String, String> params) {
942 if (params != null && !params.isEmpty()) {
943 Bundle bundle = new Bundle(mParams);
944 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
945 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
946 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
947 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
948 return bundle;
949 } else {
950 return mParams;
951 }
952 }
953
954 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
955 String value = params.get(key);
956 if (value != null) {
957 bundle.putString(key, value);
958 }
959 }
960
961 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
962 String valueString = params.get(key);
963 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700964 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000965 int value = Integer.parseInt(valueString);
966 bundle.putInt(key, value);
967 } catch (NumberFormatException ex) {
968 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700969 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700970 }
971 }
972
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000973 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
974 String valueString = params.get(key);
975 if (!TextUtils.isEmpty(valueString)) {
976 try {
977 float value = Float.parseFloat(valueString);
978 bundle.putFloat(key, value);
979 } catch (NumberFormatException ex) {
980 // don't set the value in the bundle
981 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800982 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700983 }
984
Charles Chen78c9d0d2009-07-13 16:22:41 -0700985 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000986 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700987 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000988 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700989 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000990 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700991 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000992 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
993 return runAction(new Action<Integer>() {
994 @Override
995 public Integer run(ITextToSpeechService service) throws RemoteException {
996 ITextToSpeechCallback.Stub callback = new ITextToSpeechCallback.Stub() {
997 public void utteranceCompleted(String utteranceId) {
998 if (listener != null) {
999 listener.onUtteranceCompleted(utteranceId);
1000 }
Charles Chen60dd3602010-01-07 18:56:24 -08001001 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001002 };
1003 service.setCallback(getPackageName(), callback);
1004 return SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001005 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001006 }, ERROR, "setOnUtteranceCompletedListener");
Charles Chen78c9d0d2009-07-13 16:22:41 -07001007 }
1008
Charles Chenb4fbe762009-11-18 16:34:32 -08001009 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001010 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001011 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001012 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001013 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001014 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001015 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001016 // TODO: add @Deprecated{This method does not tell the caller when the new engine
1017 // has been initialized. You should create a new TextToSpeech object with the new
1018 // engine instead.}
Charles Chen60dd3602010-01-07 18:56:24 -08001019 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001020 mRequestedEngine = enginePackageName;
1021 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001022 }
1023
Charles Chendef71852010-03-25 19:59:50 -07001024 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001025 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001026 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001027 * @return Package name of the TTS engine that the user has chosen as their default.
Charles Chendef71852010-03-25 19:59:50 -07001028 */
1029 public String getDefaultEngine() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001030 String engine = Settings.Secure.getString(mContext.getContentResolver(),
1031 Settings.Secure.TTS_DEFAULT_SYNTH);
1032 return engine != null ? engine : Engine.DEFAULT_ENGINE;
Charles Chendef71852010-03-25 19:59:50 -07001033 }
Charles Chen42229252010-03-29 18:30:30 -07001034
Charles Chen42229252010-03-29 18:30:30 -07001035 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001036 * Checks whether the user's settings should override settings requested by the calling
1037 * application.
Charles Chen42229252010-03-29 18:30:30 -07001038 */
1039 public boolean areDefaultsEnforced() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001040 return Settings.Secure.getInt(mContext.getContentResolver(),
1041 Settings.Secure.TTS_USE_DEFAULTS, Engine.USE_DEFAULTS) == 1;
1042 }
1043
1044 private boolean isEngineEnabled(String engine) {
1045 if (Engine.DEFAULT_ENGINE.equals(engine)) {
1046 return true;
Charles Chen42229252010-03-29 18:30:30 -07001047 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001048 for (String enabled : getEnabledEngines()) {
1049 if (engine.equals(enabled)) {
1050 return true;
1051 }
1052 }
1053 return false;
1054 }
1055
1056 private String[] getEnabledEngines() {
1057 String str = Settings.Secure.getString(mContext.getContentResolver(),
1058 Settings.Secure.TTS_ENABLED_PLUGINS);
1059 if (TextUtils.isEmpty(str)) {
1060 return new String[0];
1061 }
1062 return str.split(" ");
Charles Chen42229252010-03-29 18:30:30 -07001063 }
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001064
1065 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001066 * Gets a list of all installed TTS engines.
1067 *
1068 * @return A list of engine info objects. The list can be empty, but will never by {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001069 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001070 public List<EngineInfo> getEngines() {
1071 PackageManager pm = mContext.getPackageManager();
1072 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
Bjorn Bringertfe6ea012011-04-18 19:19:31 +01001073 List<ResolveInfo> resolveInfos =
1074 pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001075 if (resolveInfos == null) return Collections.emptyList();
1076 List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size());
1077 for (ResolveInfo resolveInfo : resolveInfos) {
1078 ServiceInfo service = resolveInfo.serviceInfo;
1079 if (service != null) {
1080 EngineInfo engine = new EngineInfo();
1081 // Using just the package name isn't great, since it disallows having
1082 // multiple engines in the same package, but that's what the existing API does.
1083 engine.name = service.packageName;
1084 CharSequence label = service.loadLabel(pm);
1085 engine.label = TextUtils.isEmpty(label) ? engine.name : label.toString();
1086 engine.icon = service.getIconResource();
1087 engines.add(engine);
1088 }
1089 }
1090 return engines;
1091 }
1092
1093 private class Connection implements ServiceConnection {
1094 private ITextToSpeechService mService;
1095
1096 public void onServiceConnected(ComponentName name, IBinder service) {
1097 Log.i(TAG, "Connected to " + name);
1098 synchronized(mStartLock) {
1099 if (mServiceConnection != null) {
1100 // Disconnect any previous service connection
1101 mServiceConnection.disconnect();
1102 }
1103 mServiceConnection = this;
1104 mService = ITextToSpeechService.Stub.asInterface(service);
1105 dispatchOnInit(SUCCESS);
1106 }
1107 }
1108
1109 public void onServiceDisconnected(ComponentName name) {
1110 synchronized(mStartLock) {
1111 mService = null;
1112 // If this is the active connection, clear it
1113 if (mServiceConnection == this) {
1114 mServiceConnection = null;
1115 }
1116 }
1117 }
1118
1119 public void disconnect() {
1120 mContext.unbindService(this);
1121 }
1122
1123 public <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
1124 try {
1125 synchronized (mStartLock) {
1126 if (mService == null) {
1127 Log.w(TAG, method + " failed: not connected to TTS engine");
1128 return errorResult;
1129 }
1130 return action.run(mService);
1131 }
1132 } catch (RemoteException ex) {
1133 Log.e(TAG, method + " failed", ex);
1134 if (reconnect) {
1135 disconnect();
1136 initTts();
1137 }
1138 return errorResult;
1139 }
1140 }
1141 }
1142
1143 private interface Action<R> {
1144 R run(ITextToSpeechService service) throws RemoteException;
1145 }
1146
1147 /**
1148 * Information about an installed text-to-speech engine.
1149 *
1150 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001151 */
1152 public static class EngineInfo {
1153 /**
1154 * Engine package name..
1155 */
1156 public String name;
1157 /**
1158 * Localized label for the engine.
1159 */
1160 public String label;
1161 /**
1162 * Icon for the engine.
1163 */
1164 public int icon;
1165
1166 @Override
1167 public String toString() {
1168 return "EngineInfo{name=" + name + "}";
1169 }
1170
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001171 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001172}