blob: 02152fbec3f563f08779d1c6a8f3d0f1a983a112 [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;
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +010045import java.util.MissingResourceException;
Narayan Kamath748af662011-10-31 14:20:01 +000046import java.util.Set;
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070047
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070048/**
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070049 *
Jean-Michel Trivi62788e92009-07-02 16:29:30 -070050 * Synthesizes speech from text for immediate playback or to create a sound file.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -070051 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its
52 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be
53 * notified of the completion of the initialization.<br>
54 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method
55 * to release the native resources used by the TextToSpeech engine.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070056 *
Nick Kralevicheb337052013-10-24 15:56:04 -070057 * @deprecated Use {@link TextToSpeechClient} instead
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070058 */
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +010059@Deprecated
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070060public class TextToSpeech {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070061
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +000062 private static final String TAG = "TextToSpeech";
63
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070064 /**
65 * Denotes a successful operation.
66 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000067 public static final int SUCCESS = 0;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070068 /**
69 * Denotes a generic operation failure.
70 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000071 public static final int ERROR = -1;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070072
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070073 /**
74 * Queue mode where all entries in the playback queue (media to be played
75 * and text to be synthesized) are dropped and replaced by the new entry.
Narayan Kamathabc63fb2011-06-10 11:36:57 +010076 * Queues are flushed with respect to a given calling app. Entries in the queue
77 * from other callees are not discarded.
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070078 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070079 public static final int QUEUE_FLUSH = 0;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070080 /**
81 * Queue mode where the new entry is added at the end of the playback queue.
82 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070083 public static final int QUEUE_ADD = 1;
Narayan Kamathabc63fb2011-06-10 11:36:57 +010084 /**
85 * Queue mode where the entire playback queue is purged. This is different
86 * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries
87 * from a given caller.
88 *
89 * @hide
90 */
91 static final int QUEUE_DESTROY = 2;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070092
Charles Chenaaf842e2009-06-25 11:59:29 -070093 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -070094 * Denotes the language is available exactly as specified by the locale.
Charles Chenaaf842e2009-06-25 11:59:29 -070095 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070096 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
Charles Chenaaf842e2009-06-25 11:59:29 -070097
Charles Chenaaf842e2009-06-25 11:59:29 -070098 /**
Narayan Kamathb956f372011-05-16 16:51:44 +010099 * Denotes the language is available for the language and country specified
Charles Chenaaf842e2009-06-25 11:59:29 -0700100 * by the locale, but not the variant.
101 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700102 public static final int LANG_COUNTRY_AVAILABLE = 1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700103
Charles Chenaaf842e2009-06-25 11:59:29 -0700104 /**
Narayan Kamathb956f372011-05-16 16:51:44 +0100105 * Denotes the language is available for the language by the locale,
Charles Chenaaf842e2009-06-25 11:59:29 -0700106 * but not the country and variant.
107 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700108 public static final int LANG_AVAILABLE = 0;
Charles Chenaaf842e2009-06-25 11:59:29 -0700109
110 /**
111 * Denotes the language data is missing.
112 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700113 public static final int LANG_MISSING_DATA = -1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700114
115 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700116 * Denotes the language is not supported.
Charles Chenaaf842e2009-06-25 11:59:29 -0700117 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700118 public static final int LANG_NOT_SUPPORTED = -2;
119
Jean-Michel Trivied065782009-07-28 14:31:48 -0700120 /**
121 * Broadcast Action: The TextToSpeech synthesizer has completed processing
122 * of all the text in the speech queue.
Narayan Kamathc34f76f2011-07-15 11:13:10 +0100123 *
124 * Note that this notifies callers when the <b>engine</b> has finished has
125 * processing text data. Audio playback might not have completed (or even started)
126 * at this point. If you wish to be notified when this happens, see
127 * {@link OnUtteranceCompletedListener}.
Jean-Michel Trivied065782009-07-28 14:31:48 -0700128 */
129 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
130 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
131 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
Charles Chenaaf842e2009-06-25 11:59:29 -0700132
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700133 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700134 * Interface definition of a callback to be invoked indicating the completion of the
135 * TextToSpeech engine initialization.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700136 */
137 public interface OnInitListener {
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700138 /**
139 * Called to signal the completion of the TextToSpeech engine initialization.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000140 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700141 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
142 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700143 public void onInit(int status);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700144 }
145
146 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000147 * Listener that will be called when the TTS service has
148 * completed synthesizing an utterance. This is only called if the utterance
149 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000150 *
151 * @deprecated Use {@link UtteranceProgressListener} instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700152 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000153 @Deprecated
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700154 public interface OnUtteranceCompletedListener {
155 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000156 * Called when an utterance has been synthesized.
157 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700158 * @param utteranceId the identifier of the utterance.
Charles Chen60dd3602010-01-07 18:56:24 -0800159 */
160 public void onUtteranceCompleted(String utteranceId);
Charles Chen78c9d0d2009-07-13 16:22:41 -0700161 }
162
Charles Chen78c9d0d2009-07-13 16:22:41 -0700163 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000164 * Constants and parameter names for controlling text-to-speech. These include:
165 *
166 * <ul>
167 * <li>
168 * Intents to ask engine to install data or check its data and
169 * extras for a TTS engine's check data activity.
170 * </li>
171 * <li>
172 * Keys for the parameters passed with speak commands, e.g.
173 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, {@link Engine#KEY_PARAM_STREAM}.
174 * </li>
175 * <li>
176 * A list of feature strings that engines might support, e.g
177 * {@link Engine#KEY_FEATURE_NETWORK_SYNTHESIS}). These values may be passed in to
178 * {@link TextToSpeech#speak} and {@link TextToSpeech#synthesizeToFile} to modify
179 * engine behaviour. The engine can be queried for the set of features it supports
180 * through {@link TextToSpeech#getFeatures(java.util.Locale)}.
181 * </li>
182 * </ul>
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700183 */
184 public class Engine {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000185
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700186 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000187 * Default speech rate.
188 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700189 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000190 public static final int DEFAULT_RATE = 100;
191
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700192 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000193 * Default pitch.
194 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700195 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000196 public static final int DEFAULT_PITCH = 100;
197
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700198 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000199 * Default volume.
200 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700201 */
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800202 public static final float DEFAULT_VOLUME = 1.0f;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000203
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800204 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000205 * Default pan (centered).
206 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800207 */
208 public static final float DEFAULT_PAN = 0.0f;
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800209
210 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000211 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}.
212 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800213 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700214 public static final int USE_DEFAULTS = 0; // false
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700215
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000216 /**
217 * Package name of the default TTS engine.
218 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000219 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +0100220 * @deprecated No longer in use, the default engine is determined by
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100221 * the sort order defined in {@link TtsEngines}. Note that
Narayan Kamath22302fb2011-06-10 14:22:07 +0100222 * this doesn't "break" anything because there is no guarantee that
223 * the engine specified below is installed on a given build, let
224 * alone be the default.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000225 */
Narayan Kamath22302fb2011-06-10 14:22:07 +0100226 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000227 public static final String DEFAULT_ENGINE = "com.svox.pico";
228
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700229 /**
230 * Default audio stream used when playing synthesized speech.
231 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700232 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700233
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700234 /**
235 * Indicates success when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700236 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700237 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700238 public static final int CHECK_VOICE_DATA_PASS = 1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000239
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700240 /**
241 * Indicates failure when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700242 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700243 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700244 public static final int CHECK_VOICE_DATA_FAIL = 0;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000245
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700246 /**
247 * Indicates erroneous data when checking the installation status of the resources used by
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700248 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000249 *
250 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700251 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000252 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700253 public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000254
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700255 /**
256 * Indicates missing resources when checking the installation status of the resources used
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700257 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000258 *
259 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700260 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000261 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700262 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000263
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700264 /**
265 * Indicates missing storage volume when checking the installation status of the resources
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700266 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000267 *
268 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700269 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000270 @Deprecated
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700271 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
Charles Chen99a0fee2009-07-02 10:41:51 -0700272
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000273 /**
274 * Intent for starting a TTS service. Services that handle this intent must
275 * extend {@link TextToSpeechService}. Normal applications should not use this intent
276 * directly, instead they should talk to the TTS service using the the methods in this
277 * class.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000278 */
279 @SdkConstant(SdkConstantType.SERVICE_ACTION)
280 public static final String INTENT_ACTION_TTS_SERVICE =
281 "android.intent.action.TTS_SERVICE";
282
Narayan Kamath4d034622011-06-16 12:43:46 +0100283 /**
284 * Name under which a text to speech engine publishes information about itself.
285 * This meta-data should reference an XML resource containing a
286 * <code>&lt;{@link android.R.styleable#TextToSpeechEngine tts-engine}&gt;</code>
287 * tag.
288 */
289 public static final String SERVICE_META_DATA = "android.speech.tts";
290
Jean-Michel Trivied065782009-07-28 14:31:48 -0700291 // intents to ask engine to install data or check its data
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700292 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700293 * Activity Action: Triggers the platform TextToSpeech engine to
Jean-Michel Trivied065782009-07-28 14:31:48 -0700294 * start the activity that installs the resource files on the device
295 * that are required for TTS to be operational. Since the installation
296 * of the data can be interrupted or declined by the user, the application
297 * shouldn't expect successful installation upon return from that intent,
298 * and if need be, should check installation status with
299 * {@link #ACTION_CHECK_TTS_DATA}.
300 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700301 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700302 public static final String ACTION_INSTALL_TTS_DATA =
303 "android.speech.tts.engine.INSTALL_TTS_DATA";
304
305 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000306 * Broadcast Action: broadcast to signal the change in the list of available
307 * languages or/and their features.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700308 */
309 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
310 public static final String ACTION_TTS_DATA_INSTALLED =
311 "android.speech.tts.engine.TTS_DATA_INSTALLED";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000312
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700313 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700314 * Activity Action: Starts the activity from the platform TextToSpeech
Jean-Michel Trivied065782009-07-28 14:31:48 -0700315 * engine to verify the proper installation and availability of the
316 * resource files on the system. Upon completion, the activity will
317 * return one of the following codes:
318 * {@link #CHECK_VOICE_DATA_PASS},
319 * {@link #CHECK_VOICE_DATA_FAIL},
Jean-Michel Trivied065782009-07-28 14:31:48 -0700320 * <p> Moreover, the data received in the activity result will contain the following
321 * fields:
322 * <ul>
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000323 * <li>{@link #EXTRA_AVAILABLE_VOICES} which contains an ArrayList<String> of all the
324 * available voices. The format of each voice is: lang-COUNTRY-variant where COUNTRY and
325 * variant are optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").</li>
326 * <li>{@link #EXTRA_UNAVAILABLE_VOICES} which contains an ArrayList<String> of all the
327 * unavailable voices (ones that user can install). The format of each voice is:
328 * lang-COUNTRY-variant where COUNTRY and variant are optional (ie, "eng" or
329 * "eng-USA" or "eng-USA-FEMALE").</li>
Jean-Michel Trivied065782009-07-28 14:31:48 -0700330 * </ul>
331 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700332 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700333 public static final String ACTION_CHECK_TTS_DATA =
334 "android.speech.tts.engine.CHECK_TTS_DATA";
335
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000336 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000337 * Activity intent for getting some sample text to use for demonstrating TTS. Specific
338 * locale have to be requested by passing following extra parameters:
339 * <ul>
340 * <li>language</li>
341 * <li>country</li>
342 * <li>variant</li>
343 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000344 *
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000345 * Upon completion, the activity result may contain the following fields:
346 * <ul>
347 * <li>{@link #EXTRA_SAMPLE_TEXT} which contains an String with sample text.</li>
348 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000349 */
350 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
351 public static final String ACTION_GET_SAMPLE_TEXT =
352 "android.speech.tts.engine.GET_SAMPLE_TEXT";
353
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000354 /**
355 * Extra information received with the {@link #ACTION_GET_SAMPLE_TEXT} intent result where
356 * the TextToSpeech engine returns an String with sample text for requested voice
357 */
358 public static final String EXTRA_SAMPLE_TEXT = "sampleText";
359
360
Jean-Michel Trivied065782009-07-28 14:31:48 -0700361 // extras for a TTS engine's check data activity
362 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000363 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800364 * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
365 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
366 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
367 */
368 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000369
Charles Chen76d9c3c2010-02-11 16:44:45 -0800370 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000371 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800372 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
373 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
374 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
375 */
376 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000377
Charles Chen76d9c3c2010-02-11 16:44:45 -0800378 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000379 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
380 * the TextToSpeech engine specifies the path to its resources.
381 *
382 * It may be used by language packages to find out where to put their data.
383 *
384 * @deprecated TTS engine implementation detail, this information has no use for
385 * text-to-speech API client.
386 */
387 @Deprecated
388 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
389
390 /**
391 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
392 * the TextToSpeech engine specifies the file names of its resources under the
393 * resource path.
394 *
395 * @deprecated TTS engine implementation detail, this information has no use for
396 * text-to-speech API client.
397 */
398 @Deprecated
399 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
400
401 /**
402 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
403 * the TextToSpeech engine specifies the locale associated with each resource file.
404 *
405 * @deprecated TTS engine implementation detail, this information has no use for
406 * text-to-speech API client.
407 */
408 @Deprecated
409 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
410
411 /**
Charles Chen76d9c3c2010-02-11 16:44:45 -0800412 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
413 * caller indicates to the TextToSpeech engine which specific sets of voice data to
414 * check for by sending an ArrayList<String> of the voices that are of interest.
415 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
416 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000417 *
418 * @deprecated Redundant functionality, checking for existence of specific sets of voice
419 * data can be done on client side.
Charles Chen76d9c3c2010-02-11 16:44:45 -0800420 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000421 @Deprecated
Charles Chen76d9c3c2010-02-11 16:44:45 -0800422 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
Charles Chen99a0fee2009-07-02 10:41:51 -0700423
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700424 // extras for a TTS engine's data installation
425 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000426 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent result.
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700427 * It indicates whether the data files for the synthesis engine were successfully
428 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA}
429 * intent. The possible values for this extra are
430 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000431 *
432 * @deprecated No longer in use. If client ise interested in information about what
433 * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700434 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000435 @Deprecated
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700436 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
437
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700438 // keys for the parameters passed with speak commands. Hidden keys are used internally
439 // to maintain engine state for each TextToSpeech instance.
440 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000441 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700442 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700443 public static final String KEY_PARAM_RATE = "rate";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000444
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700445 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000446 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700447 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700448 public static final String KEY_PARAM_LANGUAGE = "language";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000449
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700450 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000451 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700452 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700453 public static final String KEY_PARAM_COUNTRY = "country";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000454
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700455 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000456 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700457 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700458 public static final String KEY_PARAM_VARIANT = "variant";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000459
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700460 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000461 * @hide
Charles Chen60dd3602010-01-07 18:56:24 -0800462 */
463 public static final String KEY_PARAM_ENGINE = "engine";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000464
Charles Chen60dd3602010-01-07 18:56:24 -0800465 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000466 * @hide
Charles Chen1a2712c2010-04-01 17:16:28 -0700467 */
468 public static final String KEY_PARAM_PITCH = "pitch";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000469
Charles Chen1a2712c2010-04-01 17:16:28 -0700470 /**
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700471 * Parameter key to specify the audio stream type to be used when speaking text
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000472 * or playing back a file. The value should be one of the STREAM_ constants
473 * defined in {@link AudioManager}.
474 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700475 * @see TextToSpeech#speak(String, int, HashMap)
476 * @see TextToSpeech#playEarcon(String, int, HashMap)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700477 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700478 public static final String KEY_PARAM_STREAM = "streamType";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000479
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700480 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700481 * Parameter key to identify an utterance in the
482 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700483 * spoken, a file has been played back or a silence duration has elapsed.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000484 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700485 * @see TextToSpeech#speak(String, int, HashMap)
486 * @see TextToSpeech#playEarcon(String, int, HashMap)
487 * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700488 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700489 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000490
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800491 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800492 * Parameter key to specify the speech volume relative to the current stream type
493 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
Jean-Michel Trivi9011ec82011-01-11 11:55:00 -0800494 * where 0 is silence, and 1 is the maximum volume (the default behavior).
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000495 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800496 * @see TextToSpeech#speak(String, int, HashMap)
497 * @see TextToSpeech#playEarcon(String, int, HashMap)
498 */
499 public static final String KEY_PARAM_VOLUME = "volume";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000500
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800501 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800502 * Parameter key to specify how the speech is panned from left to right when speaking text.
503 * 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 -0800504 * 0 to center (the default behavior), and +1 to hard-right.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000505 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800506 * @see TextToSpeech#speak(String, int, HashMap)
507 * @see TextToSpeech#playEarcon(String, int, HashMap)
508 */
509 public static final String KEY_PARAM_PAN = "pan";
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700510
Narayan Kamath748af662011-10-31 14:20:01 +0000511 /**
512 * Feature key for network synthesis. See {@link TextToSpeech#getFeatures(Locale)}
513 * for a description of how feature keys work. If set (and supported by the engine
514 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
515 * use network based synthesis.
516 *
517 * @see TextToSpeech#speak(String, int, java.util.HashMap)
518 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
519 * @see TextToSpeech#getFeatures(java.util.Locale)
520 */
521 public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
522
523 /**
524 * Feature key for embedded synthesis. See {@link TextToSpeech#getFeatures(Locale)}
525 * for a description of how feature keys work. If set and supported by the engine
526 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
527 * text on-device (without making network requests).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000528 *
529 * @see TextToSpeech#speak(String, int, java.util.HashMap)
530 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
531 * @see TextToSpeech#getFeatures(java.util.Locale)
Narayan Kamath748af662011-10-31 14:20:01 +0000532 */
533 public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700534 }
535
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000536 private final Context mContext;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000537 private Connection mConnectingServiceConnection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000538 private Connection mServiceConnection;
539 private OnInitListener mInitListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +0100540 // Written from an unspecified application thread, read from
541 // a binder thread.
Narayan Kamath754c72e2011-11-09 14:22:32 +0000542 private volatile UtteranceProgressListener mUtteranceProgressListener;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700543 private final Object mStartLock = new Object();
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000544
545 private String mRequestedEngine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000546 // Whether to initialize this TTS object with the default engine,
547 // if the requested engine is not available. Valid only if mRequestedEngine
548 // is not null. Used only for testing, though potentially useful API wise
549 // too.
550 private final boolean mUseFallback;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000551 private final Map<String, Uri> mEarcons;
552 private final Map<String, Uri> mUtterances;
553 private final Bundle mParams = new Bundle();
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100554 private final TtsEngines mEnginesHelper;
Narayan Kamath68e2af52011-11-28 17:10:04 +0000555 private final String mPackageName;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100556 private volatile String mCurrentEngine = null;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700557
558 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100559 * The constructor for the TextToSpeech class, using the default TTS engine.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700560 * This will also initialize the associated TextToSpeech engine if it isn't already running.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700561 *
562 * @param context
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700563 * The context this instance is running in.
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700564 * @param listener
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700565 * The {@link TextToSpeech.OnInitListener} that will be called when the
Przemyslaw Szczepaniake86a936a2013-04-30 16:41:14 +0100566 * TextToSpeech engine has initialized. In a case of a failure the listener
567 * may be called immediately, before TextToSpeech instance is fully constructed.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700568 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700569 public TextToSpeech(Context context, OnInitListener listener) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000570 this(context, listener, null);
571 }
572
573 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100574 * The constructor for the TextToSpeech class, using the given TTS engine.
575 * This will also initialize the associated TextToSpeech engine if it isn't already running.
576 *
577 * @param context
578 * The context this instance is running in.
579 * @param listener
580 * The {@link TextToSpeech.OnInitListener} that will be called when the
Przemyslaw Szczepaniake86a936a2013-04-30 16:41:14 +0100581 * TextToSpeech engine has initialized. In a case of a failure the listener
582 * may be called immediately, before TextToSpeech instance is fully constructed.
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100583 * @param engine Package name of the TTS engine to use.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000584 */
585 public TextToSpeech(Context context, OnInitListener listener, String engine) {
Narayan Kamathc60aad22011-12-06 16:40:03 +0000586 this(context, listener, engine, null, true);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000587 }
588
589 /**
590 * Used by the framework to instantiate TextToSpeech objects with a supplied
591 * package name, instead of using {@link android.content.Context#getPackageName()}
592 *
593 * @hide
594 */
595 public TextToSpeech(Context context, OnInitListener listener, String engine,
Narayan Kamathc60aad22011-12-06 16:40:03 +0000596 String packageName, boolean useFallback) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700597 mContext = context;
598 mInitListener = listener;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000599 mRequestedEngine = engine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000600 mUseFallback = useFallback;
Jean-Michel Trivi87c96842009-06-25 14:29:15 -0700601
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000602 mEarcons = new HashMap<String, Uri>();
603 mUtterances = new HashMap<String, Uri>();
Narayan Kamath68e2af52011-11-28 17:10:04 +0000604 mUtteranceProgressListener = null;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700605
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100606 mEnginesHelper = new TtsEngines(mContext);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000607 if (packageName != null) {
608 mPackageName = packageName;
609 } else {
610 mPackageName = mContext.getPackageName();
611 }
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700612 initTts();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700613 }
614
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000615 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method,
616 boolean onlyEstablishedConnection) {
617 return runAction(action, errorResult, method, false, onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000618 }
619
620 private <R> R runAction(Action<R> action, R errorResult, String method) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000621 return runAction(action, errorResult, method, true, true);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000622 }
623
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000624 private <R> R runAction(Action<R> action, R errorResult, String method,
625 boolean reconnect, boolean onlyEstablishedConnection) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000626 synchronized (mStartLock) {
627 if (mServiceConnection == null) {
628 Log.w(TAG, method + " failed: not bound to TTS engine");
629 return errorResult;
630 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000631 return mServiceConnection.runAction(action, errorResult, method, reconnect,
632 onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000633 }
634 }
635
636 private int initTts() {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100637 // Step 1: Try connecting to the engine that was requested.
Narayan Kamathc60aad22011-12-06 16:40:03 +0000638 if (mRequestedEngine != null) {
639 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
640 if (connectToEngine(mRequestedEngine)) {
641 mCurrentEngine = mRequestedEngine;
642 return SUCCESS;
643 } else if (!mUseFallback) {
644 mCurrentEngine = null;
645 dispatchOnInit(ERROR);
646 return ERROR;
647 }
648 } else if (!mUseFallback) {
649 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine);
650 mCurrentEngine = null;
651 dispatchOnInit(ERROR);
652 return ERROR;
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100653 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000654 }
655
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100656 // Step 2: Try connecting to the user's default engine.
657 final String defaultEngine = getDefaultEngine();
658 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000659 if (connectToEngine(defaultEngine)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100660 mCurrentEngine = defaultEngine;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000661 return SUCCESS;
662 }
663 }
664
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100665 // Step 3: Try connecting to the highest ranked engine in the
666 // system.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100667 final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100668 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
669 !highestRanked.equals(defaultEngine)) {
Narayan Kamath22302fb2011-06-10 14:22:07 +0100670 if (connectToEngine(highestRanked)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100671 mCurrentEngine = highestRanked;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000672 return SUCCESS;
673 }
674 }
675
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100676 // NOTE: The API currently does not allow the caller to query whether
677 // they are actually connected to any engine. This might fail for various
678 // reasons like if the user disables all her TTS engines.
679
680 mCurrentEngine = null;
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100681 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000682 return ERROR;
683 }
684
685 private boolean connectToEngine(String engine) {
686 Connection connection = new Connection();
687 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
688 intent.setPackage(engine);
689 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
690 if (!bound) {
691 Log.e(TAG, "Failed to bind to " + engine);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000692 return false;
693 } else {
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100694 Log.i(TAG, "Sucessfully bound to " + engine);
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000695 mConnectingServiceConnection = connection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000696 return true;
697 }
698 }
699
700 private void dispatchOnInit(int result) {
701 synchronized (mStartLock) {
702 if (mInitListener != null) {
703 mInitListener.onInit(result);
704 mInitListener = null;
705 }
706 }
707 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700708
Narayan Kamath492b7f02011-11-29 17:02:06 +0000709 private IBinder getCallerIdentity() {
710 return mServiceConnection.getCallerIdentity();
711 }
712
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700713 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700714 * Releases the resources used by the TextToSpeech engine.
715 * It is good practice for instance to call this method in the onDestroy() method of an Activity
716 * so the TextToSpeech engine can be cleanly stopped.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700717 */
718 public void shutdown() {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000719 // Special case, we are asked to shutdown connection that did finalize its connection.
720 synchronized (mStartLock) {
721 if (mConnectingServiceConnection != null) {
722 mContext.unbindService(mConnectingServiceConnection);
723 mConnectingServiceConnection = null;
724 return;
725 }
726 }
727
728 // Post connection case
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000729 runActionNoReconnect(new Action<Void>() {
730 @Override
731 public Void run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000732 service.setCallback(getCallerIdentity(), null);
733 service.stop(getCallerIdentity());
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000734 mServiceConnection.disconnect();
Narayan Kamath90e56502011-07-18 14:43:07 +0100735 // Context#unbindService does not result in a call to
736 // ServiceConnection#onServiceDisconnected. As a result, the
737 // service ends up being destroyed (if there are no other open
738 // connections to it) but the process lives on and the
739 // ServiceConnection continues to refer to the destroyed service.
740 //
741 // This leads to tons of log spam about SynthThread being dead.
742 mServiceConnection = null;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100743 mCurrentEngine = null;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000744 return null;
745 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000746 }, null, "shutdown", false);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700747 }
748
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700749 /**
750 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700751 * package. After a call to this method, subsequent calls to
752 * {@link #speak(String, int, HashMap)} will play the specified sound resource
753 * if it is available, or synthesize the text it is missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700754 *
755 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700756 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700757 *
758 * @param packagename
759 * Pass the packagename of the application that contains the
760 * resource. If the resource is in your own application (this is
761 * the most common case), then put the packagename of your
762 * application here.<br/>
763 * Example: <b>"com.google.marvin.compass"</b><br/>
764 * The packagename can be found in the AndroidManifest.xml of
765 * your application.
766 * <p>
767 * <code>&lt;manifest xmlns:android=&quot;...&quot;
768 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
769 * </p>
770 *
771 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700772 * Example: <code>R.raw.south_south_east</code>
Charles Chen5c22f512009-06-29 15:52:47 -0700773 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700774 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700775 */
Charles Chen5c22f512009-06-29 15:52:47 -0700776 public int addSpeech(String text, String packagename, int resourceId) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000777 synchronized (mStartLock) {
778 mUtterances.put(text, makeResourceUri(packagename, resourceId));
779 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700780 }
781 }
782
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700783 /**
784 * Adds a mapping between a string of text and a sound file. Using this, it
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700785 * is possible to add custom pronounciations for a string of text.
786 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
787 * will play the specified sound resource if it is available, or synthesize the text it is
788 * missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700789 *
790 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700791 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700792 * @param filename
793 * The full path to the sound file (for example:
794 * "/sdcard/mysounds/hello.wav")
Charles Chen5c22f512009-06-29 15:52:47 -0700795 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700796 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700797 */
Charles Chen5c22f512009-06-29 15:52:47 -0700798 public int addSpeech(String text, String filename) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700799 synchronized (mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000800 mUtterances.put(text, Uri.parse(filename));
801 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700802 }
803 }
804
805
806 /**
Charles Chen904dfa52009-07-15 10:44:41 -0700807 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700808 * package. Use this to add custom earcons.
Charles Chen904dfa52009-07-15 10:44:41 -0700809 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700810 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700811 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700812 * @param earcon The name of the earcon.
813 * Example: <code>"[tick]"</code><br/>
Charles Chen904dfa52009-07-15 10:44:41 -0700814 *
815 * @param packagename
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700816 * the package name of the application that contains the
817 * resource. This can for instance be the package name of your own application.
Charles Chen904dfa52009-07-15 10:44:41 -0700818 * Example: <b>"com.google.marvin.compass"</b><br/>
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700819 * The package name can be found in the AndroidManifest.xml of
820 * the application containing the resource.
Charles Chen904dfa52009-07-15 10:44:41 -0700821 * <p>
822 * <code>&lt;manifest xmlns:android=&quot;...&quot;
823 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
824 * </p>
825 *
826 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700827 * Example: <code>R.raw.tick_snd</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700828 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700829 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700830 */
831 public int addEarcon(String earcon, String packagename, int resourceId) {
832 synchronized(mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000833 mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
834 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700835 }
836 }
837
Charles Chen904dfa52009-07-15 10:44:41 -0700838 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700839 * Adds a mapping between a string of text and a sound file.
840 * Use this to add custom earcons.
841 *
842 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700843 *
844 * @param earcon
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700845 * The name of the earcon.
846 * Example: <code>"[tick]"</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700847 * @param filename
848 * The full path to the sound file (for example:
849 * "/sdcard/mysounds/tick.wav")
850 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700851 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700852 */
853 public int addEarcon(String earcon, String filename) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000854 synchronized(mStartLock) {
855 mEarcons.put(earcon, Uri.parse(filename));
856 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700857 }
858 }
859
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000860 private Uri makeResourceUri(String packageName, int resourceId) {
861 return new Uri.Builder()
862 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
863 .encodedAuthority(packageName)
864 .appendEncodedPath(String.valueOf(resourceId))
865 .build();
866 }
Charles Chen904dfa52009-07-15 10:44:41 -0700867
868 /**
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100869 * Speaks the string using the specified queuing strategy and speech parameters.
870 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
871 * requests and then returns. The synthesis might not have finished (or even started!) at the
872 * time when this method returns. In order to reliably detect errors during synthesis,
873 * we recommend setting an utterance progress listener (see
874 * {@link #setOnUtteranceProgressListener}) and using the
875 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700876 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +0000877 * @param text The string of text to be spoken. No longer than
878 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000879 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
880 * @param params Parameters for the request. Can be null.
881 * Supported parameter names:
882 * {@link Engine#KEY_PARAM_STREAM},
883 * {@link Engine#KEY_PARAM_UTTERANCE_ID},
884 * {@link Engine#KEY_PARAM_VOLUME},
885 * {@link Engine#KEY_PARAM_PAN}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100886 * Engine specific parameters may be passed in but the parameter keys
887 * must be prefixed by the name of the engine they are intended for. For example
888 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
889 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700890 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100891 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700892 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000893 public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
894 return runAction(new Action<Integer>() {
895 @Override
896 public Integer run(ITextToSpeechService service) throws RemoteException {
897 Uri utteranceUri = mUtterances.get(text);
898 if (utteranceUri != null) {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000899 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000900 getParams(params));
901 } else {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000902 return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700903 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700904 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000905 }, ERROR, "speak");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700906 }
907
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700908 /**
909 * Plays the earcon using the specified queueing mode and parameters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000910 * The earcon must already have been added with {@link #addEarcon(String, String)} or
911 * {@link #addEarcon(String, String, int)}.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100912 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
913 * requests and then returns. The synthesis might not have finished (or even started!) at the
914 * time when this method returns. In order to reliably detect errors during synthesis,
915 * we recommend setting an utterance progress listener (see
916 * {@link #setOnUtteranceProgressListener}) and using the
917 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700918 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000919 * @param earcon The earcon that should be played
920 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
921 * @param params Parameters for the request. Can be null.
922 * Supported parameter names:
923 * {@link Engine#KEY_PARAM_STREAM},
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700924 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100925 * Engine specific parameters may be passed in but the parameter keys
926 * must be prefixed by the name of the engine they are intended for. For example
927 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
928 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700929 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100930 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700931 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000932 public int playEarcon(final String earcon, final int queueMode,
933 final HashMap<String, String> params) {
934 return runAction(new Action<Integer>() {
935 @Override
936 public Integer run(ITextToSpeechService service) throws RemoteException {
937 Uri earconUri = mEarcons.get(earcon);
938 if (earconUri == null) {
939 return ERROR;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700940 }
Narayan Kamath492b7f02011-11-29 17:02:06 +0000941 return service.playAudio(getCallerIdentity(), earconUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000942 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700943 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000944 }, ERROR, "playEarcon");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700945 }
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700946
Charles Chen5c22f512009-06-29 15:52:47 -0700947 /**
948 * Plays silence for the specified amount of time using the specified
949 * queue mode.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100950 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
951 * requests and then returns. The synthesis might not have finished (or even started!) at the
952 * time when this method returns. In order to reliably detect errors during synthesis,
953 * we recommend setting an utterance progress listener (see
954 * {@link #setOnUtteranceProgressListener}) and using the
955 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Charles Chen5c22f512009-06-29 15:52:47 -0700956 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000957 * @param durationInMs The duration of the silence.
958 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
959 * @param params Parameters for the request. Can be null.
960 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700961 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100962 * Engine specific parameters may be passed in but the parameter keys
963 * must be prefixed by the name of the engine they are intended for. For example
964 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
965 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700966 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100967 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
Charles Chen5c22f512009-06-29 15:52:47 -0700968 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000969 public int playSilence(final long durationInMs, final int queueMode,
970 final HashMap<String, String> params) {
971 return runAction(new Action<Integer>() {
972 @Override
973 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000974 return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +0100975 params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
Charles Chenf032bc72009-06-26 14:41:55 -0700976 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000977 }, ERROR, "playSilence");
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700978 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700979
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700980 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000981 * Queries the engine for the set of features it supports for a given locale.
982 * Features can either be framework defined, e.g.
983 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific.
984 * Engine specific keys must be prefixed by the name of the engine they
985 * are intended for. These keys can be used as parameters to
986 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and
987 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}.
988 *
989 * Features are boolean flags, and their values in the synthesis parameters
990 * must be behave as per {@link Boolean#parseBoolean(String)}.
991 *
992 * @param locale The locale to query features for.
993 */
994 public Set<String> getFeatures(final Locale locale) {
995 return runAction(new Action<Set<String>>() {
996 @Override
997 public Set<String> run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak58f16652013-09-20 15:29:25 +0100998 String[] features = null;
999 try {
1000 features = service.getFeaturesForLanguage(
Narayan Kamath748af662011-10-31 14:20:01 +00001001 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant());
Przemyslaw Szczepaniak58f16652013-09-20 15:29:25 +01001002 } catch(MissingResourceException e) {
1003 Log.w(TAG, "Couldn't retrieve 3 letter ISO 639-2/T language and/or ISO 3166 " +
1004 "country code for locale: " + locale, e);
1005 return null;
1006 }
1007
Narayan Kamath748af662011-10-31 14:20:01 +00001008 if (features != null) {
1009 final Set<String> featureSet = new HashSet<String>();
1010 Collections.addAll(featureSet, features);
1011 return featureSet;
1012 }
1013 return null;
1014 }
1015 }, null, "getFeatures");
1016 }
1017
1018 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +01001019 * Checks whether the TTS engine is busy speaking. Note that a speech item is
1020 * considered complete once it's audio data has been sent to the audio mixer, or
1021 * written to a file. There might be a finite lag between this point, and when
1022 * the audio hardware completes playback.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001023 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001024 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001025 */
1026 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001027 return runAction(new Action<Boolean>() {
1028 @Override
1029 public Boolean run(ITextToSpeechService service) throws RemoteException {
1030 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001031 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001032 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001033 }
1034
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001035 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001036 * Interrupts the current utterance (whether played or rendered to file) and discards other
1037 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -07001038 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001039 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001040 */
Charles Chen5c22f512009-06-29 15:52:47 -07001041 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001042 return runAction(new Action<Integer>() {
1043 @Override
1044 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +00001045 return service.stop(getCallerIdentity());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001046 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001047 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001048 }
1049
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001050 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001051 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001052 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001053 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001054 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001055 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
1056 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
1057 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -07001058 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001059 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001060 */
Charles Chen5c22f512009-06-29 15:52:47 -07001061 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001062 if (speechRate > 0.0f) {
1063 int intRate = (int)(speechRate * 100);
1064 if (intRate > 0) {
1065 synchronized (mStartLock) {
1066 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001067 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001068 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001069 }
1070 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001071 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001072 }
1073
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001074 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001075 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001076 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001077 * This has no effect on any pre-recorded speech.
1078 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001079 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001080 * lower values lower the tone of the synthesized voice,
1081 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -07001082 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001083 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001084 */
Charles Chen5c22f512009-06-29 15:52:47 -07001085 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001086 if (pitch > 0.0f) {
1087 int intPitch = (int)(pitch * 100);
1088 if (intPitch > 0) {
1089 synchronized (mStartLock) {
1090 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001091 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001092 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001093 }
1094 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001095 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001096 }
1097
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001098 /**
Narayan Kamathbd2492e2011-06-27 18:35:47 +01001099 * @return the engine currently in use by this TextToSpeech instance.
1100 * @hide
1101 */
1102 public String getCurrentEngine() {
1103 return mCurrentEngine;
1104 }
1105
1106 /**
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001107 * Returns a Locale instance describing the language currently being used as the default
1108 * Text-to-speech language.
1109 *
1110 * @return language, country (if any) and variant (if any) used by the client stored in a
1111 * Locale instance, or {@code null} on error.
1112 */
1113 public Locale getDefaultLanguage() {
1114 return runAction(new Action<Locale>() {
1115 @Override
1116 public Locale run(ITextToSpeechService service) throws RemoteException {
1117 String[] defaultLanguage = service.getClientDefaultLanguage();
1118
1119 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]);
1120 }
1121 }, null, "getDefaultLanguage");
1122 }
1123
1124 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001125 * Sets the text-to-speech language.
1126 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001127 * language as represented by the Locale, but there is no guarantee that the exact same Locale
1128 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1129 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001130 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001131 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001132 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001133 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001134 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1135 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001136 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001137 public int setLanguage(final Locale loc) {
1138 return runAction(new Action<Integer>() {
1139 @Override
1140 public Integer run(ITextToSpeechService service) throws RemoteException {
1141 if (loc == null) {
1142 return LANG_NOT_SUPPORTED;
1143 }
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001144 String language = null, country = null;
1145 try {
1146 language = loc.getISO3Language();
1147 } catch (MissingResourceException e) {
1148 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1149 return LANG_NOT_SUPPORTED;
1150 }
1151
1152 try {
1153 country = loc.getISO3Country();
1154 } catch (MissingResourceException e) {
1155 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1156 return LANG_NOT_SUPPORTED;
1157 }
1158
Charles Chen1a2712c2010-04-01 17:16:28 -07001159 String variant = loc.getVariant();
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001160
Charles Chen1a2712c2010-04-01 17:16:28 -07001161 // Check if the language, country, variant are available, and cache
1162 // the available parts.
1163 // Note that the language is not actually set here, instead it is cached so it
1164 // will be associated with all upcoming utterances.
Przemyslaw Szczepaniak13896b72012-11-09 15:18:16 +00001165
1166 int result = service.loadLanguage(getCallerIdentity(), language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001167 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001168 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
1169 variant = "";
1170 if (result < LANG_COUNTRY_AVAILABLE) {
1171 country = "";
1172 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001173 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001174 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
1175 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
1176 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001177 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001178 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001179 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001180 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001181 }
1182
Charles Chenaaf842e2009-06-25 11:59:29 -07001183 /**
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001184 * Returns a Locale instance describing the language currently being used for synthesis
1185 * requests sent to the TextToSpeech engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001186 *
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001187 * In Android 4.2 and before (API <= 17) this function returns the language that is currently
1188 * being used by the TTS engine. That is the last language set by this or any other
1189 * client by a {@link TextToSpeech#setLanguage} call to the same engine.
1190 *
1191 * In Android versions after 4.2 this function returns the language that is currently being
1192 * used for the synthesis requests sent from this client. That is the last language set
1193 * by a {@link TextToSpeech#setLanguage} call on this instance.
1194 *
1195 * @return language, country (if any) and variant (if any) used by the client stored in a
1196 * Locale instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001197 */
1198 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001199 return runAction(new Action<Locale>() {
1200 @Override
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001201 public Locale run(ITextToSpeechService service) {
1202 /* No service call, but we're accessing mParams, hence need for
1203 wrapping it as an Action instance */
1204 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, "");
1205 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, "");
1206 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, "");
1207 return new Locale(lang, country, variant);
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001208 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001209 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001210 }
1211
1212 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001213 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -07001214 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001215 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001216 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001217 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001218 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1219 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -07001220 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001221 public int isLanguageAvailable(final Locale loc) {
1222 return runAction(new Action<Integer>() {
1223 @Override
1224 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001225 String language = null, country = null;
1226
1227 try {
1228 language = loc.getISO3Language();
1229 } catch (MissingResourceException e) {
1230 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1231 return LANG_NOT_SUPPORTED;
1232 }
1233
1234 try {
1235 country = loc.getISO3Country();
1236 } catch (MissingResourceException e) {
1237 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1238 return LANG_NOT_SUPPORTED;
1239 }
1240
1241 return service.isLanguageAvailable(language, country, loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001242 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001243 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -07001244 }
1245
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001246 /**
Charles Chend4989092009-06-26 15:32:46 -07001247 * Synthesizes the given text to a file using the specified parameters.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001248 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
1249 * requests and then returns. The synthesis might not have finished (or even started!) at the
1250 * time when this method returns. In order to reliably detect errors during synthesis,
1251 * we recommend setting an utterance progress listener (see
1252 * {@link #setOnUtteranceProgressListener}) and using the
1253 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001254 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001255 * @param text The text that should be synthesized. No longer than
1256 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001257 * @param params Parameters for the request. Can be null.
1258 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001259 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +01001260 * Engine specific parameters may be passed in but the parameter keys
1261 * must be prefixed by the name of the engine they are intended for. For example
1262 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
1263 * engine named "com.svox.pico" if it is being used.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001264 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001265 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -07001266 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001267 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001268 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001269 public int synthesizeToFile(final String text, final HashMap<String, String> params,
1270 final String filename) {
1271 return runAction(new Action<Integer>() {
1272 @Override
1273 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +00001274 ParcelFileDescriptor fileDescriptor;
1275 int returnValue;
1276 try {
1277 File file = new File(filename);
1278 if(file.exists() && !file.canWrite()) {
1279 Log.e(TAG, "Can't write to " + filename);
1280 return ERROR;
1281 }
1282 fileDescriptor = ParcelFileDescriptor.open(file,
1283 ParcelFileDescriptor.MODE_WRITE_ONLY |
1284 ParcelFileDescriptor.MODE_CREATE |
1285 ParcelFileDescriptor.MODE_TRUNCATE);
1286 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
1287 fileDescriptor, getParams(params));
1288 fileDescriptor.close();
1289 return returnValue;
1290 } catch (FileNotFoundException e) {
1291 Log.e(TAG, "Opening file " + filename + " failed", e);
1292 return ERROR;
1293 } catch (IOException e) {
1294 Log.e(TAG, "Closing file " + filename + " failed", e);
1295 return ERROR;
1296 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001297 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001298 }, ERROR, "synthesizeToFile");
1299 }
1300
1301 private Bundle getParams(HashMap<String, String> params) {
1302 if (params != null && !params.isEmpty()) {
1303 Bundle bundle = new Bundle(mParams);
1304 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
1305 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
1306 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
1307 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
Narayan Kamathb956f372011-05-16 16:51:44 +01001308
Narayan Kamath748af662011-10-31 14:20:01 +00001309 // Copy feature strings defined by the framework.
1310 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
Narayan Kamath6c07a202011-11-07 14:21:39 +00001311 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
Narayan Kamath748af662011-10-31 14:20:01 +00001312
Narayan Kamathb956f372011-05-16 16:51:44 +01001313 // Copy over all parameters that start with the name of the
1314 // engine that we are currently connected to. The engine is
1315 // free to interpret them as it chooses.
1316 if (!TextUtils.isEmpty(mCurrentEngine)) {
1317 for (Map.Entry<String, String> entry : params.entrySet()) {
1318 final String key = entry.getKey();
1319 if (key != null && key.startsWith(mCurrentEngine)) {
1320 bundle.putString(key, entry.getValue());
1321 }
1322 }
1323 }
1324
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001325 return bundle;
1326 } else {
1327 return mParams;
1328 }
1329 }
1330
1331 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
1332 String value = params.get(key);
1333 if (value != null) {
1334 bundle.putString(key, value);
1335 }
1336 }
1337
1338 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
1339 String valueString = params.get(key);
1340 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001341 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001342 int value = Integer.parseInt(valueString);
1343 bundle.putInt(key, value);
1344 } catch (NumberFormatException ex) {
1345 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001346 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001347 }
1348 }
1349
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001350 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
1351 String valueString = params.get(key);
1352 if (!TextUtils.isEmpty(valueString)) {
1353 try {
1354 float value = Float.parseFloat(valueString);
1355 bundle.putFloat(key, value);
1356 } catch (NumberFormatException ex) {
1357 // don't set the value in the bundle
1358 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -08001359 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -07001360 }
1361
Charles Chen78c9d0d2009-07-13 16:22:41 -07001362 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001363 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001364 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001365 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001366 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001367 * @return {@link #ERROR} or {@link #SUCCESS}.
Narayan Kamath754c72e2011-11-09 14:22:32 +00001368 *
1369 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1370 * instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001371 */
Narayan Kamath754c72e2011-11-09 14:22:32 +00001372 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001373 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001374 mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1375 return TextToSpeech.SUCCESS;
1376 }
1377
1378 /**
1379 * Sets the listener that will be notified of various events related to the
1380 * synthesis of a given utterance.
1381 *
1382 * See {@link UtteranceProgressListener} and
1383 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1384 *
1385 * @param listener the listener to use.
1386 * @return {@link #ERROR} or {@link #SUCCESS}
1387 */
1388 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1389 mUtteranceProgressListener = listener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001390 return TextToSpeech.SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001391 }
1392
Charles Chenb4fbe762009-11-18 16:34:32 -08001393 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001394 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001395 *
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001396 * @deprecated This doesn't inform callers when the TTS engine has been
1397 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
Narayan Kamathb9db1fb2011-07-14 15:30:36 +01001398 * can be used with the appropriate engine name. Also, there is no
1399 * guarantee that the engine specified will be loaded. If it isn't
1400 * installed or disabled, the user / system wide defaults will apply.
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001401 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001402 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001403 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001404 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001405 */
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001406 @Deprecated
Charles Chen60dd3602010-01-07 18:56:24 -08001407 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001408 mRequestedEngine = enginePackageName;
1409 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001410 }
1411
Charles Chendef71852010-03-25 19:59:50 -07001412 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001413 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001414 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001415 * @return Package name of the TTS engine that the user has chosen
1416 * as their default.
Charles Chendef71852010-03-25 19:59:50 -07001417 */
1418 public String getDefaultEngine() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001419 return mEnginesHelper.getDefaultEngine();
Charles Chendef71852010-03-25 19:59:50 -07001420 }
Charles Chen42229252010-03-29 18:30:30 -07001421
Charles Chen42229252010-03-29 18:30:30 -07001422 /**
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001423 * Checks whether the user's settings should override settings requested
1424 * by the calling application. As of the Ice cream sandwich release,
1425 * user settings never forcibly override the app's settings.
Charles Chen42229252010-03-29 18:30:30 -07001426 */
1427 public boolean areDefaultsEnforced() {
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001428 return false;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001429 }
1430
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001431 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001432 * Gets a list of all installed TTS engines.
1433 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001434 * @return A list of engine info objects. The list can be empty, but never {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001435 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001436 public List<EngineInfo> getEngines() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001437 return mEnginesHelper.getEngines();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001438 }
1439
1440 private class Connection implements ServiceConnection {
1441 private ITextToSpeechService mService;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001442
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001443 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask;
1444
1445 private boolean mEstablished;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001446
Narayan Kamatha57f2382011-10-04 17:20:09 +01001447 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +01001448 public void onStop(String utteranceId) throws RemoteException {
1449 // do nothing
1450 };
1451
Narayan Kamatha57f2382011-10-04 17:20:09 +01001452 @Override
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +01001453 public void onFallback(String utteranceId) throws RemoteException {
1454 // do nothing
1455 }
1456
1457 @Override
1458 public void onSuccess(String utteranceId) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001459 UtteranceProgressListener listener = mUtteranceProgressListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001460 if (listener != null) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001461 listener.onDone(utteranceId);
1462 }
1463 }
1464
1465 @Override
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +01001466 public void onError(String utteranceId, int errorCode) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001467 UtteranceProgressListener listener = mUtteranceProgressListener;
1468 if (listener != null) {
1469 listener.onError(utteranceId);
1470 }
1471 }
1472
1473 @Override
1474 public void onStart(String utteranceId) {
1475 UtteranceProgressListener listener = mUtteranceProgressListener;
1476 if (listener != null) {
1477 listener.onStart(utteranceId);
Narayan Kamatha57f2382011-10-04 17:20:09 +01001478 }
1479 }
Przemyslaw Szczepaniak90d15d22013-06-14 12:02:53 +01001480
1481 @Override
1482 public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) throws RemoteException {
1483 // Ignore it
1484 }
Narayan Kamatha57f2382011-10-04 17:20:09 +01001485 };
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001486
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001487 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001488 private final ComponentName mName;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001489
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001490 public SetupConnectionAsyncTask(ComponentName name) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001491 mName = name;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001492 }
1493
1494 @Override
1495 protected Integer doInBackground(Void... params) {
1496 synchronized(mStartLock) {
1497 if (isCancelled()) {
1498 return null;
1499 }
1500
1501 try {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001502 mService.setCallback(getCallerIdentity(), mCallback);
1503 String[] defaultLanguage = mService.getClientDefaultLanguage();
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001504
1505 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]);
1506 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]);
1507 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]);
1508
1509 Log.i(TAG, "Set up connection to " + mName);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001510 return SUCCESS;
1511 } catch (RemoteException re) {
1512 Log.e(TAG, "Error connecting to service, setCallback() failed");
1513 return ERROR;
1514 }
1515 }
1516 }
1517
1518 @Override
1519 protected void onPostExecute(Integer result) {
1520 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001521 if (mOnSetupConnectionAsyncTask == this) {
1522 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001523 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001524 mEstablished = true;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001525 dispatchOnInit(result);
1526 }
1527 }
1528 }
1529
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001530 @Override
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001531 public void onServiceConnected(ComponentName name, IBinder service) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001532 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001533 mConnectingServiceConnection = null;
1534
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001535 Log.i(TAG, "Connected to " + name);
1536
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001537 if (mOnSetupConnectionAsyncTask != null) {
1538 mOnSetupConnectionAsyncTask.cancel(false);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001539 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001540
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001541 mService = ITextToSpeechService.Stub.asInterface(service);
1542 mServiceConnection = Connection.this;
1543
1544 mEstablished = false;
1545 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name);
1546 mOnSetupConnectionAsyncTask.execute();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001547 }
1548 }
1549
Narayan Kamath492b7f02011-11-29 17:02:06 +00001550 public IBinder getCallerIdentity() {
1551 return mCallback;
1552 }
1553
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001554 /**
1555 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
1556 *
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001557 * @return true if we cancel mOnSetupConnectionAsyncTask in progress.
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001558 */
1559 private boolean clearServiceConnection() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001560 synchronized(mStartLock) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001561 boolean result = false;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001562 if (mOnSetupConnectionAsyncTask != null) {
1563 result = mOnSetupConnectionAsyncTask.cancel(false);
1564 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001565 }
1566
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001567 mService = null;
1568 // If this is the active connection, clear it
1569 if (mServiceConnection == this) {
1570 mServiceConnection = null;
1571 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001572 return result;
1573 }
1574 }
1575
1576 @Override
1577 public void onServiceDisconnected(ComponentName name) {
1578 Log.i(TAG, "Asked to disconnect from " + name);
1579 if (clearServiceConnection()) {
1580 /* We need to protect against a rare case where engine
1581 * dies just after successful connection - and we process onServiceDisconnected
1582 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
1583 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
1584 * with ERROR as argument.
1585 */
1586 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001587 }
1588 }
1589
1590 public void disconnect() {
1591 mContext.unbindService(this);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001592 clearServiceConnection();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001593 }
1594
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001595 public boolean isEstablished() {
1596 return mService != null && mEstablished;
1597 }
1598
1599 public <R> R runAction(Action<R> action, R errorResult, String method,
1600 boolean reconnect, boolean onlyEstablishedConnection) {
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001601 synchronized (mStartLock) {
1602 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001603 if (mService == null) {
1604 Log.w(TAG, method + " failed: not connected to TTS engine");
1605 return errorResult;
1606 }
Fergus Henderson1c2df382013-01-25 14:59:59 +00001607 if (onlyEstablishedConnection && !isEstablished()) {
1608 Log.w(TAG, method + " failed: TTS engine connection not fully set up");
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001609 return errorResult;
1610 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001611 return action.run(mService);
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001612 } catch (RemoteException ex) {
1613 Log.e(TAG, method + " failed", ex);
1614 if (reconnect) {
1615 disconnect();
1616 initTts();
1617 }
1618 return errorResult;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001619 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001620 }
1621 }
1622 }
1623
1624 private interface Action<R> {
1625 R run(ITextToSpeechService service) throws RemoteException;
1626 }
1627
1628 /**
1629 * Information about an installed text-to-speech engine.
1630 *
1631 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001632 */
1633 public static class EngineInfo {
1634 /**
1635 * Engine package name..
1636 */
1637 public String name;
1638 /**
1639 * Localized label for the engine.
1640 */
1641 public String label;
1642 /**
1643 * Icon for the engine.
1644 */
1645 public int icon;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001646 /**
1647 * Whether this engine is a part of the system
1648 * image.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001649 *
1650 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001651 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001652 public boolean system;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001653 /**
1654 * The priority the engine declares for the the intent filter
1655 * {@code android.intent.action.TTS_SERVICE}
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001656 *
1657 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001658 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001659 public int priority;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001660
1661 @Override
1662 public String toString() {
1663 return "EngineInfo{name=" + name + "}";
1664 }
1665
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001666 }
Narayan Kamath22302fb2011-06-10 14:22:07 +01001667
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001668 /**
1669 * Limit of length of input string passed to speak and synthesizeToFile.
1670 *
1671 * @see #speak
1672 * @see #synthesizeToFile
1673 */
1674 public static int getMaxSpeechInputLength() {
1675 return 4000;
1676 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001677}