blob: 73d400eb20ac33da1ac5df142d8dfc0288ece7f1 [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;
Jean-Michel Trivia9810132009-07-10 12:08:59 -070025import android.media.AudioManager;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000026import android.net.Uri;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +000027import android.os.AsyncTask;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000028import android.os.Bundle;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070029import android.os.IBinder;
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +000030import android.os.ParcelFileDescriptor;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070031import android.os.RemoteException;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000032import android.provider.Settings;
33import android.text.TextUtils;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070034import android.util.Log;
35
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +000036import java.io.File;
37import java.io.FileNotFoundException;
38import java.io.IOException;
Narayan Kamath748af662011-10-31 14:20:01 +000039import java.util.Collections;
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070040import java.util.HashMap;
Narayan Kamath748af662011-10-31 14:20:01 +000041import java.util.HashSet;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000042import java.util.List;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070043import java.util.Locale;
Bjorn Bringert50e657b2011-03-08 16:00:40 +000044import java.util.Map;
Narayan Kamath748af662011-10-31 14:20:01 +000045import java.util.Set;
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070046
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070047/**
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070048 *
Jean-Michel Trivi62788e92009-07-02 16:29:30 -070049 * Synthesizes speech from text for immediate playback or to create a sound file.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -070050 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its
51 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be
52 * notified of the completion of the initialization.<br>
53 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method
54 * to release the native resources used by the TextToSpeech engine.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070055 *
56 */
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070057public class TextToSpeech {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070058
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +000059 private static final String TAG = "TextToSpeech";
60
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070061 /**
62 * Denotes a successful operation.
63 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000064 public static final int SUCCESS = 0;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070065 /**
66 * Denotes a generic operation failure.
67 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000068 public static final int ERROR = -1;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070069
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070070 /**
71 * Queue mode where all entries in the playback queue (media to be played
72 * and text to be synthesized) are dropped and replaced by the new entry.
Narayan Kamathabc63fb2011-06-10 11:36:57 +010073 * Queues are flushed with respect to a given calling app. Entries in the queue
74 * from other callees are not discarded.
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070075 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070076 public static final int QUEUE_FLUSH = 0;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070077 /**
78 * Queue mode where the new entry is added at the end of the playback queue.
79 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070080 public static final int QUEUE_ADD = 1;
Narayan Kamathabc63fb2011-06-10 11:36:57 +010081 /**
82 * Queue mode where the entire playback queue is purged. This is different
83 * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries
84 * from a given caller.
85 *
86 * @hide
87 */
88 static final int QUEUE_DESTROY = 2;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070089
Charles Chenaaf842e2009-06-25 11:59:29 -070090 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -070091 * Denotes the language is available exactly as specified by the locale.
Charles Chenaaf842e2009-06-25 11:59:29 -070092 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070093 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
Charles Chenaaf842e2009-06-25 11:59:29 -070094
Charles Chenaaf842e2009-06-25 11:59:29 -070095 /**
Narayan Kamathb956f372011-05-16 16:51:44 +010096 * Denotes the language is available for the language and country specified
Charles Chenaaf842e2009-06-25 11:59:29 -070097 * by the locale, but not the variant.
98 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070099 public static final int LANG_COUNTRY_AVAILABLE = 1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700100
Charles Chenaaf842e2009-06-25 11:59:29 -0700101 /**
Narayan Kamathb956f372011-05-16 16:51:44 +0100102 * Denotes the language is available for the language by the locale,
Charles Chenaaf842e2009-06-25 11:59:29 -0700103 * but not the country and variant.
104 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700105 public static final int LANG_AVAILABLE = 0;
Charles Chenaaf842e2009-06-25 11:59:29 -0700106
107 /**
108 * Denotes the language data is missing.
109 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700110 public static final int LANG_MISSING_DATA = -1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700111
112 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700113 * Denotes the language is not supported.
Charles Chenaaf842e2009-06-25 11:59:29 -0700114 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700115 public static final int LANG_NOT_SUPPORTED = -2;
116
Jean-Michel Trivied065782009-07-28 14:31:48 -0700117 /**
118 * Broadcast Action: The TextToSpeech synthesizer has completed processing
119 * of all the text in the speech queue.
Narayan Kamathc34f76f2011-07-15 11:13:10 +0100120 *
121 * Note that this notifies callers when the <b>engine</b> has finished has
122 * processing text data. Audio playback might not have completed (or even started)
123 * at this point. If you wish to be notified when this happens, see
124 * {@link OnUtteranceCompletedListener}.
Jean-Michel Trivied065782009-07-28 14:31:48 -0700125 */
126 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
127 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
128 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
Charles Chenaaf842e2009-06-25 11:59:29 -0700129
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700130 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700131 * Interface definition of a callback to be invoked indicating the completion of the
132 * TextToSpeech engine initialization.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700133 */
134 public interface OnInitListener {
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700135 /**
136 * Called to signal the completion of the TextToSpeech engine initialization.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000137 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700138 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
139 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700140 public void onInit(int status);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700141 }
142
143 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000144 * Listener that will be called when the TTS service has
145 * completed synthesizing an utterance. This is only called if the utterance
146 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000147 *
148 * @deprecated Use {@link UtteranceProgressListener} instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700149 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000150 @Deprecated
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700151 public interface OnUtteranceCompletedListener {
152 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000153 * Called when an utterance has been synthesized.
154 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700155 * @param utteranceId the identifier of the utterance.
Charles Chen60dd3602010-01-07 18:56:24 -0800156 */
157 public void onUtteranceCompleted(String utteranceId);
Charles Chen78c9d0d2009-07-13 16:22:41 -0700158 }
159
Charles Chen78c9d0d2009-07-13 16:22:41 -0700160 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000161 * Constants and parameter names for controlling text-to-speech. These include:
162 *
163 * <ul>
164 * <li>
165 * Intents to ask engine to install data or check its data and
166 * extras for a TTS engine's check data activity.
167 * </li>
168 * <li>
169 * Keys for the parameters passed with speak commands, e.g.
170 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, {@link Engine#KEY_PARAM_STREAM}.
171 * </li>
172 * <li>
173 * A list of feature strings that engines might support, e.g
174 * {@link Engine#KEY_FEATURE_NETWORK_SYNTHESIS}). These values may be passed in to
175 * {@link TextToSpeech#speak} and {@link TextToSpeech#synthesizeToFile} to modify
176 * engine behaviour. The engine can be queried for the set of features it supports
177 * through {@link TextToSpeech#getFeatures(java.util.Locale)}.
178 * </li>
179 * </ul>
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700180 */
181 public class Engine {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000182
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700183 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000184 * Default speech rate.
185 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700186 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000187 public static final int DEFAULT_RATE = 100;
188
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700189 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000190 * Default pitch.
191 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700192 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000193 public static final int DEFAULT_PITCH = 100;
194
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700195 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000196 * Default volume.
197 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700198 */
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800199 public static final float DEFAULT_VOLUME = 1.0f;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000200
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800201 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000202 * Default pan (centered).
203 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800204 */
205 public static final float DEFAULT_PAN = 0.0f;
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800206
207 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000208 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}.
209 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800210 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700211 public static final int USE_DEFAULTS = 0; // false
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700212
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000213 /**
214 * Package name of the default TTS engine.
215 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000216 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +0100217 * @deprecated No longer in use, the default engine is determined by
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100218 * the sort order defined in {@link TtsEngines}. Note that
Narayan Kamath22302fb2011-06-10 14:22:07 +0100219 * this doesn't "break" anything because there is no guarantee that
220 * the engine specified below is installed on a given build, let
221 * alone be the default.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000222 */
Narayan Kamath22302fb2011-06-10 14:22:07 +0100223 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000224 public static final String DEFAULT_ENGINE = "com.svox.pico";
225
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700226 /**
227 * Default audio stream used when playing synthesized speech.
228 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700229 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700230
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700231 /**
232 * Indicates success when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700233 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700234 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700235 public static final int CHECK_VOICE_DATA_PASS = 1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000236
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700237 /**
238 * Indicates failure when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700239 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700240 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700241 public static final int CHECK_VOICE_DATA_FAIL = 0;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000242
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700243 /**
244 * Indicates erroneous data when checking the installation status of the resources used by
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700245 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000246 *
247 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700248 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000249 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700250 public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000251
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700252 /**
253 * Indicates missing resources when checking the installation status of the resources used
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700254 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000255 *
256 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700257 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000258 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700259 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000260
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700261 /**
262 * Indicates missing storage volume when checking the installation status of the resources
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700263 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000264 *
265 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700266 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000267 @Deprecated
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700268 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
Charles Chen99a0fee2009-07-02 10:41:51 -0700269
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000270 /**
271 * Intent for starting a TTS service. Services that handle this intent must
272 * extend {@link TextToSpeechService}. Normal applications should not use this intent
273 * directly, instead they should talk to the TTS service using the the methods in this
274 * class.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000275 */
276 @SdkConstant(SdkConstantType.SERVICE_ACTION)
277 public static final String INTENT_ACTION_TTS_SERVICE =
278 "android.intent.action.TTS_SERVICE";
279
Narayan Kamath4d034622011-06-16 12:43:46 +0100280 /**
281 * Name under which a text to speech engine publishes information about itself.
282 * This meta-data should reference an XML resource containing a
283 * <code>&lt;{@link android.R.styleable#TextToSpeechEngine tts-engine}&gt;</code>
284 * tag.
285 */
286 public static final String SERVICE_META_DATA = "android.speech.tts";
287
Jean-Michel Trivied065782009-07-28 14:31:48 -0700288 // intents to ask engine to install data or check its data
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700289 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700290 * Activity Action: Triggers the platform TextToSpeech engine to
Jean-Michel Trivied065782009-07-28 14:31:48 -0700291 * start the activity that installs the resource files on the device
292 * that are required for TTS to be operational. Since the installation
293 * of the data can be interrupted or declined by the user, the application
294 * shouldn't expect successful installation upon return from that intent,
295 * and if need be, should check installation status with
296 * {@link #ACTION_CHECK_TTS_DATA}.
297 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700298 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700299 public static final String ACTION_INSTALL_TTS_DATA =
300 "android.speech.tts.engine.INSTALL_TTS_DATA";
301
302 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000303 * Broadcast Action: broadcast to signal the change in the list of available
304 * languages or/and their features.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700305 */
306 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
307 public static final String ACTION_TTS_DATA_INSTALLED =
308 "android.speech.tts.engine.TTS_DATA_INSTALLED";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000309
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700310 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700311 * Activity Action: Starts the activity from the platform TextToSpeech
Jean-Michel Trivied065782009-07-28 14:31:48 -0700312 * engine to verify the proper installation and availability of the
313 * resource files on the system. Upon completion, the activity will
314 * return one of the following codes:
315 * {@link #CHECK_VOICE_DATA_PASS},
316 * {@link #CHECK_VOICE_DATA_FAIL},
Jean-Michel Trivied065782009-07-28 14:31:48 -0700317 * <p> Moreover, the data received in the activity result will contain the following
318 * fields:
319 * <ul>
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000320 * <li>{@link #EXTRA_AVAILABLE_VOICES} which contains an ArrayList<String> of all the
321 * available voices. The format of each voice is: lang-COUNTRY-variant where COUNTRY and
322 * variant are optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").</li>
323 * <li>{@link #EXTRA_UNAVAILABLE_VOICES} which contains an ArrayList<String> of all the
324 * unavailable voices (ones that user can install). The format of each voice is:
325 * lang-COUNTRY-variant where COUNTRY and variant are optional (ie, "eng" or
326 * "eng-USA" or "eng-USA-FEMALE").</li>
Jean-Michel Trivied065782009-07-28 14:31:48 -0700327 * </ul>
328 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700329 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700330 public static final String ACTION_CHECK_TTS_DATA =
331 "android.speech.tts.engine.CHECK_TTS_DATA";
332
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000333 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000334 * Activity intent for getting some sample text to use for demonstrating TTS. Specific
335 * locale have to be requested by passing following extra parameters:
336 * <ul>
337 * <li>language</li>
338 * <li>country</li>
339 * <li>variant</li>
340 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000341 *
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000342 * Upon completion, the activity result may contain the following fields:
343 * <ul>
344 * <li>{@link #EXTRA_SAMPLE_TEXT} which contains an String with sample text.</li>
345 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000346 */
347 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
348 public static final String ACTION_GET_SAMPLE_TEXT =
349 "android.speech.tts.engine.GET_SAMPLE_TEXT";
350
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000351 /**
352 * Extra information received with the {@link #ACTION_GET_SAMPLE_TEXT} intent result where
353 * the TextToSpeech engine returns an String with sample text for requested voice
354 */
355 public static final String EXTRA_SAMPLE_TEXT = "sampleText";
356
357
Jean-Michel Trivied065782009-07-28 14:31:48 -0700358 // extras for a TTS engine's check data activity
359 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000360 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800361 * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
362 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
363 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
364 */
365 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000366
Charles Chen76d9c3c2010-02-11 16:44:45 -0800367 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000368 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800369 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
370 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
371 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
372 */
373 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000374
Charles Chen76d9c3c2010-02-11 16:44:45 -0800375 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000376 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
377 * the TextToSpeech engine specifies the path to its resources.
378 *
379 * It may be used by language packages to find out where to put their data.
380 *
381 * @deprecated TTS engine implementation detail, this information has no use for
382 * text-to-speech API client.
383 */
384 @Deprecated
385 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
386
387 /**
388 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
389 * the TextToSpeech engine specifies the file names of its resources under the
390 * resource path.
391 *
392 * @deprecated TTS engine implementation detail, this information has no use for
393 * text-to-speech API client.
394 */
395 @Deprecated
396 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
397
398 /**
399 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
400 * the TextToSpeech engine specifies the locale associated with each resource file.
401 *
402 * @deprecated TTS engine implementation detail, this information has no use for
403 * text-to-speech API client.
404 */
405 @Deprecated
406 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
407
408 /**
Charles Chen76d9c3c2010-02-11 16:44:45 -0800409 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
410 * caller indicates to the TextToSpeech engine which specific sets of voice data to
411 * check for by sending an ArrayList<String> of the voices that are of interest.
412 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
413 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000414 *
415 * @deprecated Redundant functionality, checking for existence of specific sets of voice
416 * data can be done on client side.
Charles Chen76d9c3c2010-02-11 16:44:45 -0800417 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000418 @Deprecated
Charles Chen76d9c3c2010-02-11 16:44:45 -0800419 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
Charles Chen99a0fee2009-07-02 10:41:51 -0700420
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700421 // extras for a TTS engine's data installation
422 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000423 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent result.
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700424 * It indicates whether the data files for the synthesis engine were successfully
425 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA}
426 * intent. The possible values for this extra are
427 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000428 *
429 * @deprecated No longer in use. If client ise interested in information about what
430 * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700431 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000432 @Deprecated
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700433 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
434
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700435 // keys for the parameters passed with speak commands. Hidden keys are used internally
436 // to maintain engine state for each TextToSpeech instance.
437 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000438 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700439 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700440 public static final String KEY_PARAM_RATE = "rate";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000441
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700442 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000443 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700444 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700445 public static final String KEY_PARAM_LANGUAGE = "language";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000446
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700447 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000448 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700449 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700450 public static final String KEY_PARAM_COUNTRY = "country";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000451
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700452 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000453 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700454 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700455 public static final String KEY_PARAM_VARIANT = "variant";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000456
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700457 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000458 * @hide
Charles Chen60dd3602010-01-07 18:56:24 -0800459 */
460 public static final String KEY_PARAM_ENGINE = "engine";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000461
Charles Chen60dd3602010-01-07 18:56:24 -0800462 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000463 * @hide
Charles Chen1a2712c2010-04-01 17:16:28 -0700464 */
465 public static final String KEY_PARAM_PITCH = "pitch";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000466
Charles Chen1a2712c2010-04-01 17:16:28 -0700467 /**
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700468 * Parameter key to specify the audio stream type to be used when speaking text
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000469 * or playing back a file. The value should be one of the STREAM_ constants
470 * defined in {@link AudioManager}.
471 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700472 * @see TextToSpeech#speak(String, int, HashMap)
473 * @see TextToSpeech#playEarcon(String, int, HashMap)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700474 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700475 public static final String KEY_PARAM_STREAM = "streamType";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000476
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700477 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700478 * Parameter key to identify an utterance in the
479 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700480 * spoken, a file has been played back or a silence duration has elapsed.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000481 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700482 * @see TextToSpeech#speak(String, int, HashMap)
483 * @see TextToSpeech#playEarcon(String, int, HashMap)
484 * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700485 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700486 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000487
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800488 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800489 * Parameter key to specify the speech volume relative to the current stream type
490 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
Jean-Michel Trivi9011ec82011-01-11 11:55:00 -0800491 * where 0 is silence, and 1 is the maximum volume (the default behavior).
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000492 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800493 * @see TextToSpeech#speak(String, int, HashMap)
494 * @see TextToSpeech#playEarcon(String, int, HashMap)
495 */
496 public static final String KEY_PARAM_VOLUME = "volume";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000497
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800498 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800499 * Parameter key to specify how the speech is panned from left to right when speaking text.
500 * 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 -0800501 * 0 to center (the default behavior), and +1 to hard-right.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000502 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800503 * @see TextToSpeech#speak(String, int, HashMap)
504 * @see TextToSpeech#playEarcon(String, int, HashMap)
505 */
506 public static final String KEY_PARAM_PAN = "pan";
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700507
Narayan Kamath748af662011-10-31 14:20:01 +0000508 /**
509 * Feature key for network synthesis. See {@link TextToSpeech#getFeatures(Locale)}
510 * for a description of how feature keys work. If set (and supported by the engine
511 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
512 * use network based synthesis.
513 *
514 * @see TextToSpeech#speak(String, int, java.util.HashMap)
515 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
516 * @see TextToSpeech#getFeatures(java.util.Locale)
517 */
518 public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
519
520 /**
521 * Feature key for embedded synthesis. See {@link TextToSpeech#getFeatures(Locale)}
522 * for a description of how feature keys work. If set and supported by the engine
523 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
524 * text on-device (without making network requests).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000525 *
526 * @see TextToSpeech#speak(String, int, java.util.HashMap)
527 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
528 * @see TextToSpeech#getFeatures(java.util.Locale)
Narayan Kamath748af662011-10-31 14:20:01 +0000529 */
530 public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700531 }
532
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000533 private final Context mContext;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000534 private Connection mConnectingServiceConnection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000535 private Connection mServiceConnection;
536 private OnInitListener mInitListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +0100537 // Written from an unspecified application thread, read from
538 // a binder thread.
Narayan Kamath754c72e2011-11-09 14:22:32 +0000539 private volatile UtteranceProgressListener mUtteranceProgressListener;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700540 private final Object mStartLock = new Object();
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000541
542 private String mRequestedEngine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000543 // Whether to initialize this TTS object with the default engine,
544 // if the requested engine is not available. Valid only if mRequestedEngine
545 // is not null. Used only for testing, though potentially useful API wise
546 // too.
547 private final boolean mUseFallback;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000548 private final Map<String, Uri> mEarcons;
549 private final Map<String, Uri> mUtterances;
550 private final Bundle mParams = new Bundle();
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100551 private final TtsEngines mEnginesHelper;
Narayan Kamath68e2af52011-11-28 17:10:04 +0000552 private final String mPackageName;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100553 private volatile String mCurrentEngine = null;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700554
555 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100556 * The constructor for the TextToSpeech class, using the default TTS engine.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700557 * This will also initialize the associated TextToSpeech engine if it isn't already running.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700558 *
559 * @param context
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700560 * The context this instance is running in.
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700561 * @param listener
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700562 * The {@link TextToSpeech.OnInitListener} that will be called when the
563 * TextToSpeech engine has initialized.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700564 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700565 public TextToSpeech(Context context, OnInitListener listener) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000566 this(context, listener, null);
567 }
568
569 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100570 * The constructor for the TextToSpeech class, using the given TTS engine.
571 * This will also initialize the associated TextToSpeech engine if it isn't already running.
572 *
573 * @param context
574 * The context this instance is running in.
575 * @param listener
576 * The {@link TextToSpeech.OnInitListener} that will be called when the
577 * TextToSpeech engine has initialized.
578 * @param engine Package name of the TTS engine to use.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000579 */
580 public TextToSpeech(Context context, OnInitListener listener, String engine) {
Narayan Kamathc60aad22011-12-06 16:40:03 +0000581 this(context, listener, engine, null, true);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000582 }
583
584 /**
585 * Used by the framework to instantiate TextToSpeech objects with a supplied
586 * package name, instead of using {@link android.content.Context#getPackageName()}
587 *
588 * @hide
589 */
590 public TextToSpeech(Context context, OnInitListener listener, String engine,
Narayan Kamathc60aad22011-12-06 16:40:03 +0000591 String packageName, boolean useFallback) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700592 mContext = context;
593 mInitListener = listener;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000594 mRequestedEngine = engine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000595 mUseFallback = useFallback;
Jean-Michel Trivi87c96842009-06-25 14:29:15 -0700596
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000597 mEarcons = new HashMap<String, Uri>();
598 mUtterances = new HashMap<String, Uri>();
Narayan Kamath68e2af52011-11-28 17:10:04 +0000599 mUtteranceProgressListener = null;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700600
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100601 mEnginesHelper = new TtsEngines(mContext);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000602 if (packageName != null) {
603 mPackageName = packageName;
604 } else {
605 mPackageName = mContext.getPackageName();
606 }
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700607 initTts();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700608 }
609
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000610 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method,
611 boolean onlyEstablishedConnection) {
612 return runAction(action, errorResult, method, false, onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000613 }
614
615 private <R> R runAction(Action<R> action, R errorResult, String method) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000616 return runAction(action, errorResult, method, true, true);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000617 }
618
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000619 private <R> R runAction(Action<R> action, R errorResult, String method,
620 boolean reconnect, boolean onlyEstablishedConnection) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000621 synchronized (mStartLock) {
622 if (mServiceConnection == null) {
623 Log.w(TAG, method + " failed: not bound to TTS engine");
624 return errorResult;
625 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000626 return mServiceConnection.runAction(action, errorResult, method, reconnect,
627 onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000628 }
629 }
630
631 private int initTts() {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100632 // Step 1: Try connecting to the engine that was requested.
Narayan Kamathc60aad22011-12-06 16:40:03 +0000633 if (mRequestedEngine != null) {
634 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
635 if (connectToEngine(mRequestedEngine)) {
636 mCurrentEngine = mRequestedEngine;
637 return SUCCESS;
638 } else if (!mUseFallback) {
639 mCurrentEngine = null;
640 dispatchOnInit(ERROR);
641 return ERROR;
642 }
643 } else if (!mUseFallback) {
644 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine);
645 mCurrentEngine = null;
646 dispatchOnInit(ERROR);
647 return ERROR;
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100648 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000649 }
650
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100651 // Step 2: Try connecting to the user's default engine.
652 final String defaultEngine = getDefaultEngine();
653 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000654 if (connectToEngine(defaultEngine)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100655 mCurrentEngine = defaultEngine;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000656 return SUCCESS;
657 }
658 }
659
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100660 // Step 3: Try connecting to the highest ranked engine in the
661 // system.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100662 final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100663 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
664 !highestRanked.equals(defaultEngine)) {
Narayan Kamath22302fb2011-06-10 14:22:07 +0100665 if (connectToEngine(highestRanked)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100666 mCurrentEngine = highestRanked;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000667 return SUCCESS;
668 }
669 }
670
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100671 // NOTE: The API currently does not allow the caller to query whether
672 // they are actually connected to any engine. This might fail for various
673 // reasons like if the user disables all her TTS engines.
674
675 mCurrentEngine = null;
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100676 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000677 return ERROR;
678 }
679
680 private boolean connectToEngine(String engine) {
681 Connection connection = new Connection();
682 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
683 intent.setPackage(engine);
684 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
685 if (!bound) {
686 Log.e(TAG, "Failed to bind to " + engine);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000687 return false;
688 } else {
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100689 Log.i(TAG, "Sucessfully bound to " + engine);
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000690 mConnectingServiceConnection = connection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000691 return true;
692 }
693 }
694
695 private void dispatchOnInit(int result) {
696 synchronized (mStartLock) {
697 if (mInitListener != null) {
698 mInitListener.onInit(result);
699 mInitListener = null;
700 }
701 }
702 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700703
Narayan Kamath492b7f02011-11-29 17:02:06 +0000704 private IBinder getCallerIdentity() {
705 return mServiceConnection.getCallerIdentity();
706 }
707
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700708 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700709 * Releases the resources used by the TextToSpeech engine.
710 * It is good practice for instance to call this method in the onDestroy() method of an Activity
711 * so the TextToSpeech engine can be cleanly stopped.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700712 */
713 public void shutdown() {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000714 // Special case, we are asked to shutdown connection that did finalize its connection.
715 synchronized (mStartLock) {
716 if (mConnectingServiceConnection != null) {
717 mContext.unbindService(mConnectingServiceConnection);
718 mConnectingServiceConnection = null;
719 return;
720 }
721 }
722
723 // Post connection case
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000724 runActionNoReconnect(new Action<Void>() {
725 @Override
726 public Void run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000727 service.setCallback(getCallerIdentity(), null);
728 service.stop(getCallerIdentity());
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000729 mServiceConnection.disconnect();
Narayan Kamath90e56502011-07-18 14:43:07 +0100730 // Context#unbindService does not result in a call to
731 // ServiceConnection#onServiceDisconnected. As a result, the
732 // service ends up being destroyed (if there are no other open
733 // connections to it) but the process lives on and the
734 // ServiceConnection continues to refer to the destroyed service.
735 //
736 // This leads to tons of log spam about SynthThread being dead.
737 mServiceConnection = null;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100738 mCurrentEngine = null;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000739 return null;
740 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000741 }, null, "shutdown", false);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700742 }
743
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700744 /**
745 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700746 * package. After a call to this method, subsequent calls to
747 * {@link #speak(String, int, HashMap)} will play the specified sound resource
748 * if it is available, or synthesize the text it is missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700749 *
750 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700751 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700752 *
753 * @param packagename
754 * Pass the packagename of the application that contains the
755 * resource. If the resource is in your own application (this is
756 * the most common case), then put the packagename of your
757 * application here.<br/>
758 * Example: <b>"com.google.marvin.compass"</b><br/>
759 * The packagename can be found in the AndroidManifest.xml of
760 * your application.
761 * <p>
762 * <code>&lt;manifest xmlns:android=&quot;...&quot;
763 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
764 * </p>
765 *
766 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700767 * Example: <code>R.raw.south_south_east</code>
Charles Chen5c22f512009-06-29 15:52:47 -0700768 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700769 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700770 */
Charles Chen5c22f512009-06-29 15:52:47 -0700771 public int addSpeech(String text, String packagename, int resourceId) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000772 synchronized (mStartLock) {
773 mUtterances.put(text, makeResourceUri(packagename, resourceId));
774 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700775 }
776 }
777
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700778 /**
779 * Adds a mapping between a string of text and a sound file. Using this, it
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700780 * is possible to add custom pronounciations for a string of text.
781 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
782 * will play the specified sound resource if it is available, or synthesize the text it is
783 * missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700784 *
785 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700786 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700787 * @param filename
788 * The full path to the sound file (for example:
789 * "/sdcard/mysounds/hello.wav")
Charles Chen5c22f512009-06-29 15:52:47 -0700790 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700791 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700792 */
Charles Chen5c22f512009-06-29 15:52:47 -0700793 public int addSpeech(String text, String filename) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700794 synchronized (mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000795 mUtterances.put(text, Uri.parse(filename));
796 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700797 }
798 }
799
800
801 /**
Charles Chen904dfa52009-07-15 10:44:41 -0700802 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700803 * package. Use this to add custom earcons.
Charles Chen904dfa52009-07-15 10:44:41 -0700804 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700805 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700806 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700807 * @param earcon The name of the earcon.
808 * Example: <code>"[tick]"</code><br/>
Charles Chen904dfa52009-07-15 10:44:41 -0700809 *
810 * @param packagename
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700811 * the package name of the application that contains the
812 * resource. This can for instance be the package name of your own application.
Charles Chen904dfa52009-07-15 10:44:41 -0700813 * Example: <b>"com.google.marvin.compass"</b><br/>
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700814 * The package name can be found in the AndroidManifest.xml of
815 * the application containing the resource.
Charles Chen904dfa52009-07-15 10:44:41 -0700816 * <p>
817 * <code>&lt;manifest xmlns:android=&quot;...&quot;
818 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
819 * </p>
820 *
821 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700822 * Example: <code>R.raw.tick_snd</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700823 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700824 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700825 */
826 public int addEarcon(String earcon, String packagename, int resourceId) {
827 synchronized(mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000828 mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
829 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700830 }
831 }
832
Charles Chen904dfa52009-07-15 10:44:41 -0700833 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700834 * Adds a mapping between a string of text and a sound file.
835 * Use this to add custom earcons.
836 *
837 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700838 *
839 * @param earcon
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700840 * The name of the earcon.
841 * Example: <code>"[tick]"</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700842 * @param filename
843 * The full path to the sound file (for example:
844 * "/sdcard/mysounds/tick.wav")
845 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700846 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700847 */
848 public int addEarcon(String earcon, String filename) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000849 synchronized(mStartLock) {
850 mEarcons.put(earcon, Uri.parse(filename));
851 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700852 }
853 }
854
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000855 private Uri makeResourceUri(String packageName, int resourceId) {
856 return new Uri.Builder()
857 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
858 .encodedAuthority(packageName)
859 .appendEncodedPath(String.valueOf(resourceId))
860 .build();
861 }
Charles Chen904dfa52009-07-15 10:44:41 -0700862
863 /**
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100864 * Speaks the string using the specified queuing strategy and speech parameters.
865 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
866 * requests and then returns. The synthesis might not have finished (or even started!) at the
867 * time when this method returns. In order to reliably detect errors during synthesis,
868 * we recommend setting an utterance progress listener (see
869 * {@link #setOnUtteranceProgressListener}) and using the
870 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700871 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +0000872 * @param text The string of text to be spoken. No longer than
873 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000874 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
875 * @param params Parameters for the request. Can be null.
876 * Supported parameter names:
877 * {@link Engine#KEY_PARAM_STREAM},
878 * {@link Engine#KEY_PARAM_UTTERANCE_ID},
879 * {@link Engine#KEY_PARAM_VOLUME},
880 * {@link Engine#KEY_PARAM_PAN}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100881 * Engine specific parameters may be passed in but the parameter keys
882 * must be prefixed by the name of the engine they are intended for. For example
883 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
884 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700885 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100886 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700887 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000888 public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
889 return runAction(new Action<Integer>() {
890 @Override
891 public Integer run(ITextToSpeechService service) throws RemoteException {
892 Uri utteranceUri = mUtterances.get(text);
893 if (utteranceUri != null) {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000894 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000895 getParams(params));
896 } else {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000897 return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700898 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700899 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000900 }, ERROR, "speak");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700901 }
902
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700903 /**
904 * Plays the earcon using the specified queueing mode and parameters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000905 * The earcon must already have been added with {@link #addEarcon(String, String)} or
906 * {@link #addEarcon(String, String, int)}.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100907 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
908 * requests and then returns. The synthesis might not have finished (or even started!) at the
909 * time when this method returns. In order to reliably detect errors during synthesis,
910 * we recommend setting an utterance progress listener (see
911 * {@link #setOnUtteranceProgressListener}) and using the
912 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700913 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000914 * @param earcon The earcon that should be played
915 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
916 * @param params Parameters for the request. Can be null.
917 * Supported parameter names:
918 * {@link Engine#KEY_PARAM_STREAM},
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700919 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100920 * Engine specific parameters may be passed in but the parameter keys
921 * must be prefixed by the name of the engine they are intended for. For example
922 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
923 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700924 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100925 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700926 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000927 public int playEarcon(final String earcon, final int queueMode,
928 final HashMap<String, String> params) {
929 return runAction(new Action<Integer>() {
930 @Override
931 public Integer run(ITextToSpeechService service) throws RemoteException {
932 Uri earconUri = mEarcons.get(earcon);
933 if (earconUri == null) {
934 return ERROR;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700935 }
Narayan Kamath492b7f02011-11-29 17:02:06 +0000936 return service.playAudio(getCallerIdentity(), earconUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000937 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700938 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000939 }, ERROR, "playEarcon");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700940 }
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700941
Charles Chen5c22f512009-06-29 15:52:47 -0700942 /**
943 * Plays silence for the specified amount of time using the specified
944 * queue mode.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100945 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
946 * requests and then returns. The synthesis might not have finished (or even started!) at the
947 * time when this method returns. In order to reliably detect errors during synthesis,
948 * we recommend setting an utterance progress listener (see
949 * {@link #setOnUtteranceProgressListener}) and using the
950 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Charles Chen5c22f512009-06-29 15:52:47 -0700951 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000952 * @param durationInMs The duration of the silence.
953 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
954 * @param params Parameters for the request. Can be null.
955 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700956 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100957 * Engine specific parameters may be passed in but the parameter keys
958 * must be prefixed by the name of the engine they are intended for. For example
959 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
960 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700961 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100962 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
Charles Chen5c22f512009-06-29 15:52:47 -0700963 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000964 public int playSilence(final long durationInMs, final int queueMode,
965 final HashMap<String, String> params) {
966 return runAction(new Action<Integer>() {
967 @Override
968 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000969 return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000970 getParams(params));
Charles Chenf032bc72009-06-26 14:41:55 -0700971 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000972 }, ERROR, "playSilence");
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700973 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700974
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700975 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000976 * Queries the engine for the set of features it supports for a given locale.
977 * Features can either be framework defined, e.g.
978 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific.
979 * Engine specific keys must be prefixed by the name of the engine they
980 * are intended for. These keys can be used as parameters to
981 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and
982 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}.
983 *
984 * Features are boolean flags, and their values in the synthesis parameters
985 * must be behave as per {@link Boolean#parseBoolean(String)}.
986 *
987 * @param locale The locale to query features for.
988 */
989 public Set<String> getFeatures(final Locale locale) {
990 return runAction(new Action<Set<String>>() {
991 @Override
992 public Set<String> run(ITextToSpeechService service) throws RemoteException {
993 String[] features = service.getFeaturesForLanguage(
994 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant());
995 if (features != null) {
996 final Set<String> featureSet = new HashSet<String>();
997 Collections.addAll(featureSet, features);
998 return featureSet;
999 }
1000 return null;
1001 }
1002 }, null, "getFeatures");
1003 }
1004
1005 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +01001006 * Checks whether the TTS engine is busy speaking. Note that a speech item is
1007 * considered complete once it's audio data has been sent to the audio mixer, or
1008 * written to a file. There might be a finite lag between this point, and when
1009 * the audio hardware completes playback.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001010 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001011 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001012 */
1013 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001014 return runAction(new Action<Boolean>() {
1015 @Override
1016 public Boolean run(ITextToSpeechService service) throws RemoteException {
1017 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001018 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001019 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001020 }
1021
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001022 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001023 * Interrupts the current utterance (whether played or rendered to file) and discards other
1024 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -07001025 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001026 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001027 */
Charles Chen5c22f512009-06-29 15:52:47 -07001028 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001029 return runAction(new Action<Integer>() {
1030 @Override
1031 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +00001032 return service.stop(getCallerIdentity());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001033 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001034 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001035 }
1036
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001037 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001038 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001039 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001040 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001041 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001042 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
1043 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
1044 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -07001045 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001046 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001047 */
Charles Chen5c22f512009-06-29 15:52:47 -07001048 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001049 if (speechRate > 0.0f) {
1050 int intRate = (int)(speechRate * 100);
1051 if (intRate > 0) {
1052 synchronized (mStartLock) {
1053 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001054 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001055 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001056 }
1057 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001058 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001059 }
1060
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001061 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001062 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001063 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001064 * This has no effect on any pre-recorded speech.
1065 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001066 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001067 * lower values lower the tone of the synthesized voice,
1068 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -07001069 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001070 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001071 */
Charles Chen5c22f512009-06-29 15:52:47 -07001072 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001073 if (pitch > 0.0f) {
1074 int intPitch = (int)(pitch * 100);
1075 if (intPitch > 0) {
1076 synchronized (mStartLock) {
1077 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001078 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001079 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001080 }
1081 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001082 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001083 }
1084
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001085 /**
Narayan Kamathbd2492e2011-06-27 18:35:47 +01001086 * @return the engine currently in use by this TextToSpeech instance.
1087 * @hide
1088 */
1089 public String getCurrentEngine() {
1090 return mCurrentEngine;
1091 }
1092
1093 /**
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001094 * Returns a Locale instance describing the language currently being used as the default
1095 * Text-to-speech language.
1096 *
1097 * @return language, country (if any) and variant (if any) used by the client stored in a
1098 * Locale instance, or {@code null} on error.
1099 */
1100 public Locale getDefaultLanguage() {
1101 return runAction(new Action<Locale>() {
1102 @Override
1103 public Locale run(ITextToSpeechService service) throws RemoteException {
1104 String[] defaultLanguage = service.getClientDefaultLanguage();
1105
1106 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]);
1107 }
1108 }, null, "getDefaultLanguage");
1109 }
1110
1111 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001112 * Sets the text-to-speech language.
1113 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001114 * language as represented by the Locale, but there is no guarantee that the exact same Locale
1115 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1116 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001117 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001118 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001119 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001120 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001121 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1122 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001123 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001124 public int setLanguage(final Locale loc) {
1125 return runAction(new Action<Integer>() {
1126 @Override
1127 public Integer run(ITextToSpeechService service) throws RemoteException {
1128 if (loc == null) {
1129 return LANG_NOT_SUPPORTED;
1130 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001131 String language = loc.getISO3Language();
1132 String country = loc.getISO3Country();
1133 String variant = loc.getVariant();
1134 // Check if the language, country, variant are available, and cache
1135 // the available parts.
1136 // Note that the language is not actually set here, instead it is cached so it
1137 // will be associated with all upcoming utterances.
Przemyslaw Szczepaniak13896b72012-11-09 15:18:16 +00001138
1139 int result = service.loadLanguage(getCallerIdentity(), language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001140 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001141 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
1142 variant = "";
1143 if (result < LANG_COUNTRY_AVAILABLE) {
1144 country = "";
1145 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001146 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001147 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
1148 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
1149 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001150 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001151 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001152 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001153 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001154 }
1155
Charles Chenaaf842e2009-06-25 11:59:29 -07001156 /**
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001157 * Returns a Locale instance describing the language currently being used for synthesis
1158 * requests sent to the TextToSpeech engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001159 *
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001160 * In Android 4.2 and before (API <= 17) this function returns the language that is currently
1161 * being used by the TTS engine. That is the last language set by this or any other
1162 * client by a {@link TextToSpeech#setLanguage} call to the same engine.
1163 *
1164 * In Android versions after 4.2 this function returns the language that is currently being
1165 * used for the synthesis requests sent from this client. That is the last language set
1166 * by a {@link TextToSpeech#setLanguage} call on this instance.
1167 *
1168 * @return language, country (if any) and variant (if any) used by the client stored in a
1169 * Locale instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001170 */
1171 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001172 return runAction(new Action<Locale>() {
1173 @Override
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001174 public Locale run(ITextToSpeechService service) {
1175 /* No service call, but we're accessing mParams, hence need for
1176 wrapping it as an Action instance */
1177 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, "");
1178 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, "");
1179 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, "");
1180 return new Locale(lang, country, variant);
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001181 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001182 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001183 }
1184
1185 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001186 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -07001187 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001188 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001189 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001190 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001191 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1192 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -07001193 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001194 public int isLanguageAvailable(final Locale loc) {
1195 return runAction(new Action<Integer>() {
1196 @Override
1197 public Integer run(ITextToSpeechService service) throws RemoteException {
1198 return service.isLanguageAvailable(loc.getISO3Language(),
1199 loc.getISO3Country(), loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001200 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001201 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -07001202 }
1203
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001204 /**
Charles Chend4989092009-06-26 15:32:46 -07001205 * Synthesizes the given text to a file using the specified parameters.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001206 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
1207 * requests and then returns. The synthesis might not have finished (or even started!) at the
1208 * time when this method returns. In order to reliably detect errors during synthesis,
1209 * we recommend setting an utterance progress listener (see
1210 * {@link #setOnUtteranceProgressListener}) and using the
1211 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001212 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001213 * @param text The text that should be synthesized. No longer than
1214 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001215 * @param params Parameters for the request. Can be null.
1216 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001217 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +01001218 * Engine specific parameters may be passed in but the parameter keys
1219 * must be prefixed by the name of the engine they are intended for. For example
1220 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
1221 * engine named "com.svox.pico" if it is being used.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001222 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001223 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -07001224 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001225 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001226 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001227 public int synthesizeToFile(final String text, final HashMap<String, String> params,
1228 final String filename) {
1229 return runAction(new Action<Integer>() {
1230 @Override
1231 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +00001232 ParcelFileDescriptor fileDescriptor;
1233 int returnValue;
1234 try {
1235 File file = new File(filename);
1236 if(file.exists() && !file.canWrite()) {
1237 Log.e(TAG, "Can't write to " + filename);
1238 return ERROR;
1239 }
1240 fileDescriptor = ParcelFileDescriptor.open(file,
1241 ParcelFileDescriptor.MODE_WRITE_ONLY |
1242 ParcelFileDescriptor.MODE_CREATE |
1243 ParcelFileDescriptor.MODE_TRUNCATE);
1244 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
1245 fileDescriptor, getParams(params));
1246 fileDescriptor.close();
1247 return returnValue;
1248 } catch (FileNotFoundException e) {
1249 Log.e(TAG, "Opening file " + filename + " failed", e);
1250 return ERROR;
1251 } catch (IOException e) {
1252 Log.e(TAG, "Closing file " + filename + " failed", e);
1253 return ERROR;
1254 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001255 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001256 }, ERROR, "synthesizeToFile");
1257 }
1258
1259 private Bundle getParams(HashMap<String, String> params) {
1260 if (params != null && !params.isEmpty()) {
1261 Bundle bundle = new Bundle(mParams);
1262 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
1263 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
1264 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
1265 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
Narayan Kamathb956f372011-05-16 16:51:44 +01001266
Narayan Kamath748af662011-10-31 14:20:01 +00001267 // Copy feature strings defined by the framework.
1268 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
Narayan Kamath6c07a202011-11-07 14:21:39 +00001269 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
Narayan Kamath748af662011-10-31 14:20:01 +00001270
Narayan Kamathb956f372011-05-16 16:51:44 +01001271 // Copy over all parameters that start with the name of the
1272 // engine that we are currently connected to. The engine is
1273 // free to interpret them as it chooses.
1274 if (!TextUtils.isEmpty(mCurrentEngine)) {
1275 for (Map.Entry<String, String> entry : params.entrySet()) {
1276 final String key = entry.getKey();
1277 if (key != null && key.startsWith(mCurrentEngine)) {
1278 bundle.putString(key, entry.getValue());
1279 }
1280 }
1281 }
1282
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001283 return bundle;
1284 } else {
1285 return mParams;
1286 }
1287 }
1288
1289 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
1290 String value = params.get(key);
1291 if (value != null) {
1292 bundle.putString(key, value);
1293 }
1294 }
1295
1296 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
1297 String valueString = params.get(key);
1298 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001299 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001300 int value = Integer.parseInt(valueString);
1301 bundle.putInt(key, value);
1302 } catch (NumberFormatException ex) {
1303 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001304 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001305 }
1306 }
1307
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001308 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
1309 String valueString = params.get(key);
1310 if (!TextUtils.isEmpty(valueString)) {
1311 try {
1312 float value = Float.parseFloat(valueString);
1313 bundle.putFloat(key, value);
1314 } catch (NumberFormatException ex) {
1315 // don't set the value in the bundle
1316 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -08001317 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -07001318 }
1319
Charles Chen78c9d0d2009-07-13 16:22:41 -07001320 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001321 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001322 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001323 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001324 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001325 * @return {@link #ERROR} or {@link #SUCCESS}.
Narayan Kamath754c72e2011-11-09 14:22:32 +00001326 *
1327 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1328 * instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001329 */
Narayan Kamath754c72e2011-11-09 14:22:32 +00001330 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001331 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001332 mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1333 return TextToSpeech.SUCCESS;
1334 }
1335
1336 /**
1337 * Sets the listener that will be notified of various events related to the
1338 * synthesis of a given utterance.
1339 *
1340 * See {@link UtteranceProgressListener} and
1341 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1342 *
1343 * @param listener the listener to use.
1344 * @return {@link #ERROR} or {@link #SUCCESS}
1345 */
1346 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1347 mUtteranceProgressListener = listener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001348 return TextToSpeech.SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001349 }
1350
Charles Chenb4fbe762009-11-18 16:34:32 -08001351 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001352 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001353 *
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001354 * @deprecated This doesn't inform callers when the TTS engine has been
1355 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
Narayan Kamathb9db1fb2011-07-14 15:30:36 +01001356 * can be used with the appropriate engine name. Also, there is no
1357 * guarantee that the engine specified will be loaded. If it isn't
1358 * installed or disabled, the user / system wide defaults will apply.
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001359 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001360 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001361 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001362 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001363 */
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001364 @Deprecated
Charles Chen60dd3602010-01-07 18:56:24 -08001365 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001366 mRequestedEngine = enginePackageName;
1367 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001368 }
1369
Charles Chendef71852010-03-25 19:59:50 -07001370 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001371 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001372 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001373 * @return Package name of the TTS engine that the user has chosen
1374 * as their default.
Charles Chendef71852010-03-25 19:59:50 -07001375 */
1376 public String getDefaultEngine() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001377 return mEnginesHelper.getDefaultEngine();
Charles Chendef71852010-03-25 19:59:50 -07001378 }
Charles Chen42229252010-03-29 18:30:30 -07001379
Charles Chen42229252010-03-29 18:30:30 -07001380 /**
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001381 * Checks whether the user's settings should override settings requested
1382 * by the calling application. As of the Ice cream sandwich release,
1383 * user settings never forcibly override the app's settings.
Charles Chen42229252010-03-29 18:30:30 -07001384 */
1385 public boolean areDefaultsEnforced() {
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001386 return false;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001387 }
1388
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001389 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001390 * Gets a list of all installed TTS engines.
1391 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001392 * @return A list of engine info objects. The list can be empty, but never {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001393 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001394 public List<EngineInfo> getEngines() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001395 return mEnginesHelper.getEngines();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001396 }
1397
1398 private class Connection implements ServiceConnection {
1399 private ITextToSpeechService mService;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001400
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001401 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask;
1402
1403 private boolean mEstablished;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001404
Narayan Kamatha57f2382011-10-04 17:20:09 +01001405 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
1406 @Override
Narayan Kamath754c72e2011-11-09 14:22:32 +00001407 public void onDone(String utteranceId) {
1408 UtteranceProgressListener listener = mUtteranceProgressListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001409 if (listener != null) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001410 listener.onDone(utteranceId);
1411 }
1412 }
1413
1414 @Override
1415 public void onError(String utteranceId) {
1416 UtteranceProgressListener listener = mUtteranceProgressListener;
1417 if (listener != null) {
1418 listener.onError(utteranceId);
1419 }
1420 }
1421
1422 @Override
1423 public void onStart(String utteranceId) {
1424 UtteranceProgressListener listener = mUtteranceProgressListener;
1425 if (listener != null) {
1426 listener.onStart(utteranceId);
Narayan Kamatha57f2382011-10-04 17:20:09 +01001427 }
1428 }
1429 };
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001430
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001431 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001432 private final ComponentName mName;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001433
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001434 public SetupConnectionAsyncTask(ComponentName name) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001435 mName = name;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001436 }
1437
1438 @Override
1439 protected Integer doInBackground(Void... params) {
1440 synchronized(mStartLock) {
1441 if (isCancelled()) {
1442 return null;
1443 }
1444
1445 try {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001446 mService.setCallback(getCallerIdentity(), mCallback);
1447 String[] defaultLanguage = mService.getClientDefaultLanguage();
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001448
1449 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]);
1450 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]);
1451 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]);
1452
1453 Log.i(TAG, "Set up connection to " + mName);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001454 return SUCCESS;
1455 } catch (RemoteException re) {
1456 Log.e(TAG, "Error connecting to service, setCallback() failed");
1457 return ERROR;
1458 }
1459 }
1460 }
1461
1462 @Override
1463 protected void onPostExecute(Integer result) {
1464 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001465 if (mOnSetupConnectionAsyncTask == this) {
1466 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001467 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001468 mEstablished = true;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001469 dispatchOnInit(result);
1470 }
1471 }
1472 }
1473
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001474 @Override
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001475 public void onServiceConnected(ComponentName name, IBinder service) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001476 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001477 mConnectingServiceConnection = null;
1478
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001479 Log.i(TAG, "Connected to " + name);
1480
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001481 if (mOnSetupConnectionAsyncTask != null) {
1482 mOnSetupConnectionAsyncTask.cancel(false);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001483 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001484
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001485 mService = ITextToSpeechService.Stub.asInterface(service);
1486 mServiceConnection = Connection.this;
1487
1488 mEstablished = false;
1489 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name);
1490 mOnSetupConnectionAsyncTask.execute();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001491 }
1492 }
1493
Narayan Kamath492b7f02011-11-29 17:02:06 +00001494 public IBinder getCallerIdentity() {
1495 return mCallback;
1496 }
1497
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001498 /**
1499 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
1500 *
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001501 * @return true if we cancel mOnSetupConnectionAsyncTask in progress.
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001502 */
1503 private boolean clearServiceConnection() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001504 synchronized(mStartLock) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001505 boolean result = false;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001506 if (mOnSetupConnectionAsyncTask != null) {
1507 result = mOnSetupConnectionAsyncTask.cancel(false);
1508 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001509 }
1510
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001511 mService = null;
1512 // If this is the active connection, clear it
1513 if (mServiceConnection == this) {
1514 mServiceConnection = null;
1515 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001516 return result;
1517 }
1518 }
1519
1520 @Override
1521 public void onServiceDisconnected(ComponentName name) {
1522 Log.i(TAG, "Asked to disconnect from " + name);
1523 if (clearServiceConnection()) {
1524 /* We need to protect against a rare case where engine
1525 * dies just after successful connection - and we process onServiceDisconnected
1526 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
1527 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
1528 * with ERROR as argument.
1529 */
1530 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001531 }
1532 }
1533
1534 public void disconnect() {
1535 mContext.unbindService(this);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001536 clearServiceConnection();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001537 }
1538
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001539 public boolean isEstablished() {
1540 return mService != null && mEstablished;
1541 }
1542
1543 public <R> R runAction(Action<R> action, R errorResult, String method,
1544 boolean reconnect, boolean onlyEstablishedConnection) {
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001545 synchronized (mStartLock) {
1546 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001547 if (mService == null) {
1548 Log.w(TAG, method + " failed: not connected to TTS engine");
1549 return errorResult;
1550 }
Fergus Henderson1c2df382013-01-25 14:59:59 +00001551 if (onlyEstablishedConnection && !isEstablished()) {
1552 Log.w(TAG, method + " failed: TTS engine connection not fully set up");
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001553 return errorResult;
1554 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001555 return action.run(mService);
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001556 } catch (RemoteException ex) {
1557 Log.e(TAG, method + " failed", ex);
1558 if (reconnect) {
1559 disconnect();
1560 initTts();
1561 }
1562 return errorResult;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001563 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001564 }
1565 }
1566 }
1567
1568 private interface Action<R> {
1569 R run(ITextToSpeechService service) throws RemoteException;
1570 }
1571
1572 /**
1573 * Information about an installed text-to-speech engine.
1574 *
1575 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001576 */
1577 public static class EngineInfo {
1578 /**
1579 * Engine package name..
1580 */
1581 public String name;
1582 /**
1583 * Localized label for the engine.
1584 */
1585 public String label;
1586 /**
1587 * Icon for the engine.
1588 */
1589 public int icon;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001590 /**
1591 * Whether this engine is a part of the system
1592 * image.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001593 *
1594 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001595 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001596 public boolean system;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001597 /**
1598 * The priority the engine declares for the the intent filter
1599 * {@code android.intent.action.TTS_SERVICE}
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001600 *
1601 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001602 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001603 public int priority;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001604
1605 @Override
1606 public String toString() {
1607 return "EngineInfo{name=" + name + "}";
1608 }
1609
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001610 }
Narayan Kamath22302fb2011-06-10 14:22:07 +01001611
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001612 /**
1613 * Limit of length of input string passed to speak and synthesizeToFile.
1614 *
1615 * @see #speak
1616 * @see #synthesizeToFile
1617 */
1618 public static int getMaxSpeechInputLength() {
1619 return 4000;
1620 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001621}