blob: 578a86eb521d9b8a167efdadff567c6560228d9e [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 *
57 */
Jean-Michel Trivia8518c12009-06-10 17:33:34 -070058public class TextToSpeech {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070059
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +000060 private static final String TAG = "TextToSpeech";
61
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070062 /**
63 * Denotes a successful operation.
64 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000065 public static final int SUCCESS = 0;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070066 /**
67 * Denotes a generic operation failure.
68 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +000069 public static final int ERROR = -1;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -070070
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070071 /**
72 * Queue mode where all entries in the playback queue (media to be played
73 * and text to be synthesized) are dropped and replaced by the new entry.
Narayan Kamathabc63fb2011-06-10 11:36:57 +010074 * Queues are flushed with respect to a given calling app. Entries in the queue
75 * from other callees are not discarded.
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070076 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070077 public static final int QUEUE_FLUSH = 0;
Jean-Michel Trivi679d7282009-06-16 15:36:28 -070078 /**
79 * Queue mode where the new entry is added at the end of the playback queue.
80 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070081 public static final int QUEUE_ADD = 1;
Narayan Kamathabc63fb2011-06-10 11:36:57 +010082 /**
83 * Queue mode where the entire playback queue is purged. This is different
84 * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries
85 * from a given caller.
86 *
87 * @hide
88 */
89 static final int QUEUE_DESTROY = 2;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -070090
Charles Chenaaf842e2009-06-25 11:59:29 -070091 /**
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -070092 * Denotes the language is available exactly as specified by the locale.
Charles Chenaaf842e2009-06-25 11:59:29 -070093 */
Jean-Michel Trivied065782009-07-28 14:31:48 -070094 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
Charles Chenaaf842e2009-06-25 11:59:29 -070095
Charles Chenaaf842e2009-06-25 11:59:29 -070096 /**
Narayan Kamathb956f372011-05-16 16:51:44 +010097 * Denotes the language is available for the language and country specified
Charles Chenaaf842e2009-06-25 11:59:29 -070098 * by the locale, but not the variant.
99 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700100 public static final int LANG_COUNTRY_AVAILABLE = 1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700101
Charles Chenaaf842e2009-06-25 11:59:29 -0700102 /**
Narayan Kamathb956f372011-05-16 16:51:44 +0100103 * Denotes the language is available for the language by the locale,
Charles Chenaaf842e2009-06-25 11:59:29 -0700104 * but not the country and variant.
105 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700106 public static final int LANG_AVAILABLE = 0;
Charles Chenaaf842e2009-06-25 11:59:29 -0700107
108 /**
109 * Denotes the language data is missing.
110 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700111 public static final int LANG_MISSING_DATA = -1;
Charles Chenaaf842e2009-06-25 11:59:29 -0700112
113 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700114 * Denotes the language is not supported.
Charles Chenaaf842e2009-06-25 11:59:29 -0700115 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700116 public static final int LANG_NOT_SUPPORTED = -2;
117
Jean-Michel Trivied065782009-07-28 14:31:48 -0700118 /**
119 * Broadcast Action: The TextToSpeech synthesizer has completed processing
120 * of all the text in the speech queue.
Narayan Kamathc34f76f2011-07-15 11:13:10 +0100121 *
122 * Note that this notifies callers when the <b>engine</b> has finished has
123 * processing text data. Audio playback might not have completed (or even started)
124 * at this point. If you wish to be notified when this happens, see
125 * {@link OnUtteranceCompletedListener}.
Jean-Michel Trivied065782009-07-28 14:31:48 -0700126 */
127 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
128 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
129 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
Charles Chenaaf842e2009-06-25 11:59:29 -0700130
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700131 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700132 * Interface definition of a callback to be invoked indicating the completion of the
133 * TextToSpeech engine initialization.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700134 */
135 public interface OnInitListener {
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700136 /**
137 * Called to signal the completion of the TextToSpeech engine initialization.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000138 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700139 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
140 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700141 public void onInit(int status);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700142 }
143
144 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000145 * Listener that will be called when the TTS service has
146 * completed synthesizing an utterance. This is only called if the utterance
147 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000148 *
149 * @deprecated Use {@link UtteranceProgressListener} instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -0700150 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000151 @Deprecated
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700152 public interface OnUtteranceCompletedListener {
153 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000154 * Called when an utterance has been synthesized.
155 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700156 * @param utteranceId the identifier of the utterance.
Charles Chen60dd3602010-01-07 18:56:24 -0800157 */
158 public void onUtteranceCompleted(String utteranceId);
Charles Chen78c9d0d2009-07-13 16:22:41 -0700159 }
160
Charles Chen78c9d0d2009-07-13 16:22:41 -0700161 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000162 * Constants and parameter names for controlling text-to-speech. These include:
163 *
164 * <ul>
165 * <li>
166 * Intents to ask engine to install data or check its data and
167 * extras for a TTS engine's check data activity.
168 * </li>
169 * <li>
170 * Keys for the parameters passed with speak commands, e.g.
171 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, {@link Engine#KEY_PARAM_STREAM}.
172 * </li>
173 * <li>
174 * A list of feature strings that engines might support, e.g
175 * {@link Engine#KEY_FEATURE_NETWORK_SYNTHESIS}). These values may be passed in to
176 * {@link TextToSpeech#speak} and {@link TextToSpeech#synthesizeToFile} to modify
177 * engine behaviour. The engine can be queried for the set of features it supports
178 * through {@link TextToSpeech#getFeatures(java.util.Locale)}.
179 * </li>
180 * </ul>
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700181 */
182 public class Engine {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000183
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700184 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000185 * Default speech rate.
186 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700187 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000188 public static final int DEFAULT_RATE = 100;
189
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700190 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000191 * Default pitch.
192 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700193 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000194 public static final int DEFAULT_PITCH = 100;
195
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700196 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000197 * Default volume.
198 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700199 */
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800200 public static final float DEFAULT_VOLUME = 1.0f;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000201
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800202 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000203 * Default pan (centered).
204 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800205 */
206 public static final float DEFAULT_PAN = 0.0f;
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800207
208 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000209 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}.
210 * @hide
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800211 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700212 public static final int USE_DEFAULTS = 0; // false
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700213
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000214 /**
215 * Package name of the default TTS engine.
216 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000217 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +0100218 * @deprecated No longer in use, the default engine is determined by
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100219 * the sort order defined in {@link TtsEngines}. Note that
Narayan Kamath22302fb2011-06-10 14:22:07 +0100220 * this doesn't "break" anything because there is no guarantee that
221 * the engine specified below is installed on a given build, let
222 * alone be the default.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000223 */
Narayan Kamath22302fb2011-06-10 14:22:07 +0100224 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000225 public static final String DEFAULT_ENGINE = "com.svox.pico";
226
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700227 /**
228 * Default audio stream used when playing synthesized speech.
229 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700230 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700231
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700232 /**
233 * Indicates success when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700234 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700235 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700236 public static final int CHECK_VOICE_DATA_PASS = 1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000237
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700238 /**
239 * Indicates failure when checking the installation status of the resources used by the
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700240 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700241 */
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700242 public static final int CHECK_VOICE_DATA_FAIL = 0;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000243
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700244 /**
245 * Indicates erroneous data when checking the installation status of the resources used by
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700246 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000247 *
248 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700249 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000250 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700251 public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000252
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700253 /**
254 * Indicates missing resources when checking the installation status of the resources used
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700255 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000256 *
257 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700258 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000259 @Deprecated
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700260 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000261
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700262 /**
263 * Indicates missing storage volume when checking the installation status of the resources
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700264 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000265 *
266 * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700267 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000268 @Deprecated
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700269 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
Charles Chen99a0fee2009-07-02 10:41:51 -0700270
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000271 /**
272 * Intent for starting a TTS service. Services that handle this intent must
273 * extend {@link TextToSpeechService}. Normal applications should not use this intent
274 * directly, instead they should talk to the TTS service using the the methods in this
275 * class.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000276 */
277 @SdkConstant(SdkConstantType.SERVICE_ACTION)
278 public static final String INTENT_ACTION_TTS_SERVICE =
279 "android.intent.action.TTS_SERVICE";
280
Narayan Kamath4d034622011-06-16 12:43:46 +0100281 /**
282 * Name under which a text to speech engine publishes information about itself.
283 * This meta-data should reference an XML resource containing a
284 * <code>&lt;{@link android.R.styleable#TextToSpeechEngine tts-engine}&gt;</code>
285 * tag.
286 */
287 public static final String SERVICE_META_DATA = "android.speech.tts";
288
Jean-Michel Trivied065782009-07-28 14:31:48 -0700289 // intents to ask engine to install data or check its data
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700290 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700291 * Activity Action: Triggers the platform TextToSpeech engine to
Jean-Michel Trivied065782009-07-28 14:31:48 -0700292 * start the activity that installs the resource files on the device
293 * that are required for TTS to be operational. Since the installation
294 * of the data can be interrupted or declined by the user, the application
295 * shouldn't expect successful installation upon return from that intent,
296 * and if need be, should check installation status with
297 * {@link #ACTION_CHECK_TTS_DATA}.
298 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700299 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700300 public static final String ACTION_INSTALL_TTS_DATA =
301 "android.speech.tts.engine.INSTALL_TTS_DATA";
302
303 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000304 * Broadcast Action: broadcast to signal the change in the list of available
305 * languages or/and their features.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700306 */
307 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
308 public static final String ACTION_TTS_DATA_INSTALLED =
309 "android.speech.tts.engine.TTS_DATA_INSTALLED";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000310
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700311 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700312 * Activity Action: Starts the activity from the platform TextToSpeech
Jean-Michel Trivied065782009-07-28 14:31:48 -0700313 * engine to verify the proper installation and availability of the
314 * resource files on the system. Upon completion, the activity will
315 * return one of the following codes:
316 * {@link #CHECK_VOICE_DATA_PASS},
317 * {@link #CHECK_VOICE_DATA_FAIL},
Jean-Michel Trivied065782009-07-28 14:31:48 -0700318 * <p> Moreover, the data received in the activity result will contain the following
319 * fields:
320 * <ul>
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000321 * <li>{@link #EXTRA_AVAILABLE_VOICES} which contains an ArrayList<String> of all the
322 * available voices. The format of each voice is: lang-COUNTRY-variant where COUNTRY and
323 * variant are optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").</li>
324 * <li>{@link #EXTRA_UNAVAILABLE_VOICES} which contains an ArrayList<String> of all the
325 * unavailable voices (ones that user can install). The format of each voice is:
326 * lang-COUNTRY-variant where COUNTRY and variant are optional (ie, "eng" or
327 * "eng-USA" or "eng-USA-FEMALE").</li>
Jean-Michel Trivied065782009-07-28 14:31:48 -0700328 * </ul>
329 */
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700330 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Jean-Michel Trivied065782009-07-28 14:31:48 -0700331 public static final String ACTION_CHECK_TTS_DATA =
332 "android.speech.tts.engine.CHECK_TTS_DATA";
333
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000334 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000335 * Activity intent for getting some sample text to use for demonstrating TTS. Specific
336 * locale have to be requested by passing following extra parameters:
337 * <ul>
338 * <li>language</li>
339 * <li>country</li>
340 * <li>variant</li>
341 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000342 *
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000343 * Upon completion, the activity result may contain the following fields:
344 * <ul>
345 * <li>{@link #EXTRA_SAMPLE_TEXT} which contains an String with sample text.</li>
346 * </ul>
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000347 */
348 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
349 public static final String ACTION_GET_SAMPLE_TEXT =
350 "android.speech.tts.engine.GET_SAMPLE_TEXT";
351
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000352 /**
353 * Extra information received with the {@link #ACTION_GET_SAMPLE_TEXT} intent result where
354 * the TextToSpeech engine returns an String with sample text for requested voice
355 */
356 public static final String EXTRA_SAMPLE_TEXT = "sampleText";
357
358
Jean-Michel Trivied065782009-07-28 14:31:48 -0700359 // extras for a TTS engine's check data activity
360 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000361 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800362 * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
363 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
364 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
365 */
366 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000367
Charles Chen76d9c3c2010-02-11 16:44:45 -0800368 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000369 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
Charles Chen76d9c3c2010-02-11 16:44:45 -0800370 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
371 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
372 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
373 */
374 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000375
Charles Chen76d9c3c2010-02-11 16:44:45 -0800376 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000377 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
378 * the TextToSpeech engine specifies the path to its resources.
379 *
380 * It may be used by language packages to find out where to put their data.
381 *
382 * @deprecated TTS engine implementation detail, this information has no use for
383 * text-to-speech API client.
384 */
385 @Deprecated
386 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
387
388 /**
389 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
390 * the TextToSpeech engine specifies the file names of its resources under the
391 * resource path.
392 *
393 * @deprecated TTS engine implementation detail, this information has no use for
394 * text-to-speech API client.
395 */
396 @Deprecated
397 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
398
399 /**
400 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
401 * the TextToSpeech engine specifies the locale associated with each resource file.
402 *
403 * @deprecated TTS engine implementation detail, this information has no use for
404 * text-to-speech API client.
405 */
406 @Deprecated
407 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
408
409 /**
Charles Chen76d9c3c2010-02-11 16:44:45 -0800410 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
411 * caller indicates to the TextToSpeech engine which specific sets of voice data to
412 * check for by sending an ArrayList<String> of the voices that are of interest.
413 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
414 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000415 *
416 * @deprecated Redundant functionality, checking for existence of specific sets of voice
417 * data can be done on client side.
Charles Chen76d9c3c2010-02-11 16:44:45 -0800418 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000419 @Deprecated
Charles Chen76d9c3c2010-02-11 16:44:45 -0800420 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
Charles Chen99a0fee2009-07-02 10:41:51 -0700421
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700422 // extras for a TTS engine's data installation
423 /**
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000424 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent result.
Jean-Michel Trivi9f5eadd2009-08-14 15:44:31 -0700425 * It indicates whether the data files for the synthesis engine were successfully
426 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA}
427 * intent. The possible values for this extra are
428 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000429 *
430 * @deprecated No longer in use. If client ise interested in information about what
431 * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700432 */
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000433 @Deprecated
Jean-Michel Trivi77a5d392009-08-07 17:26:36 -0700434 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
435
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700436 // keys for the parameters passed with speak commands. Hidden keys are used internally
437 // to maintain engine state for each TextToSpeech instance.
438 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000439 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700440 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700441 public static final String KEY_PARAM_RATE = "rate";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000442
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700443 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000444 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700445 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700446 public static final String KEY_PARAM_LANGUAGE = "language";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000447
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700448 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000449 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700450 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700451 public static final String KEY_PARAM_COUNTRY = "country";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000452
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700453 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000454 * @hide
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700455 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700456 public static final String KEY_PARAM_VARIANT = "variant";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000457
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700458 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000459 * @hide
Charles Chen60dd3602010-01-07 18:56:24 -0800460 */
461 public static final String KEY_PARAM_ENGINE = "engine";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000462
Charles Chen60dd3602010-01-07 18:56:24 -0800463 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000464 * @hide
Charles Chen1a2712c2010-04-01 17:16:28 -0700465 */
466 public static final String KEY_PARAM_PITCH = "pitch";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000467
Charles Chen1a2712c2010-04-01 17:16:28 -0700468 /**
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700469 * Parameter key to specify the audio stream type to be used when speaking text
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000470 * or playing back a file. The value should be one of the STREAM_ constants
471 * defined in {@link AudioManager}.
472 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700473 * @see TextToSpeech#speak(String, int, HashMap)
474 * @see TextToSpeech#playEarcon(String, int, HashMap)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700475 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700476 public static final String KEY_PARAM_STREAM = "streamType";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000477
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700478 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700479 * Parameter key to identify an utterance in the
480 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700481 * spoken, a file has been played back or a silence duration has elapsed.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000482 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700483 * @see TextToSpeech#speak(String, int, HashMap)
484 * @see TextToSpeech#playEarcon(String, int, HashMap)
485 * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700486 */
Jean-Michel Trivied065782009-07-28 14:31:48 -0700487 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000488
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800489 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800490 * Parameter key to specify the speech volume relative to the current stream type
491 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
Jean-Michel Trivi9011ec82011-01-11 11:55:00 -0800492 * where 0 is silence, and 1 is the maximum volume (the default behavior).
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000493 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800494 * @see TextToSpeech#speak(String, int, HashMap)
495 * @see TextToSpeech#playEarcon(String, int, HashMap)
496 */
497 public static final String KEY_PARAM_VOLUME = "volume";
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000498
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800499 /**
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800500 * Parameter key to specify how the speech is panned from left to right when speaking text.
501 * 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 -0800502 * 0 to center (the default behavior), and +1 to hard-right.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000503 *
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -0800504 * @see TextToSpeech#speak(String, int, HashMap)
505 * @see TextToSpeech#playEarcon(String, int, HashMap)
506 */
507 public static final String KEY_PARAM_PAN = "pan";
Jean-Michel Trivi62253a32009-07-14 13:55:19 -0700508
Narayan Kamath748af662011-10-31 14:20:01 +0000509 /**
510 * Feature key for network synthesis. See {@link TextToSpeech#getFeatures(Locale)}
511 * for a description of how feature keys work. If set (and supported by the engine
512 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
513 * use network based synthesis.
514 *
515 * @see TextToSpeech#speak(String, int, java.util.HashMap)
516 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
517 * @see TextToSpeech#getFeatures(java.util.Locale)
518 */
519 public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
520
521 /**
522 * Feature key for embedded synthesis. See {@link TextToSpeech#getFeatures(Locale)}
523 * for a description of how feature keys work. If set and supported by the engine
524 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
525 * text on-device (without making network requests).
Przemyslaw Szczepaniak647abce2013-01-09 11:52:03 +0000526 *
527 * @see TextToSpeech#speak(String, int, java.util.HashMap)
528 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
529 * @see TextToSpeech#getFeatures(java.util.Locale)
Narayan Kamath748af662011-10-31 14:20:01 +0000530 */
531 public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
Jean-Michel Trivid1468742009-06-18 14:41:41 -0700532 }
533
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000534 private final Context mContext;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000535 private Connection mConnectingServiceConnection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000536 private Connection mServiceConnection;
537 private OnInitListener mInitListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +0100538 // Written from an unspecified application thread, read from
539 // a binder thread.
Narayan Kamath754c72e2011-11-09 14:22:32 +0000540 private volatile UtteranceProgressListener mUtteranceProgressListener;
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700541 private final Object mStartLock = new Object();
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000542
543 private String mRequestedEngine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000544 // Whether to initialize this TTS object with the default engine,
545 // if the requested engine is not available. Valid only if mRequestedEngine
546 // is not null. Used only for testing, though potentially useful API wise
547 // too.
548 private final boolean mUseFallback;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000549 private final Map<String, Uri> mEarcons;
550 private final Map<String, Uri> mUtterances;
551 private final Bundle mParams = new Bundle();
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100552 private final TtsEngines mEnginesHelper;
Narayan Kamath68e2af52011-11-28 17:10:04 +0000553 private final String mPackageName;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100554 private volatile String mCurrentEngine = null;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700555
556 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100557 * The constructor for the TextToSpeech class, using the default TTS engine.
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700558 * This will also initialize the associated TextToSpeech engine if it isn't already running.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700559 *
560 * @param context
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700561 * The context this instance is running in.
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700562 * @param listener
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700563 * The {@link TextToSpeech.OnInitListener} that will be called when the
564 * TextToSpeech engine has initialized.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700565 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700566 public TextToSpeech(Context context, OnInitListener listener) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000567 this(context, listener, null);
568 }
569
570 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100571 * The constructor for the TextToSpeech class, using the given TTS engine.
572 * This will also initialize the associated TextToSpeech engine if it isn't already running.
573 *
574 * @param context
575 * The context this instance is running in.
576 * @param listener
577 * The {@link TextToSpeech.OnInitListener} that will be called when the
578 * TextToSpeech engine has initialized.
579 * @param engine Package name of the TTS engine to use.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000580 */
581 public TextToSpeech(Context context, OnInitListener listener, String engine) {
Narayan Kamathc60aad22011-12-06 16:40:03 +0000582 this(context, listener, engine, null, true);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000583 }
584
585 /**
586 * Used by the framework to instantiate TextToSpeech objects with a supplied
587 * package name, instead of using {@link android.content.Context#getPackageName()}
588 *
589 * @hide
590 */
591 public TextToSpeech(Context context, OnInitListener listener, String engine,
Narayan Kamathc60aad22011-12-06 16:40:03 +0000592 String packageName, boolean useFallback) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700593 mContext = context;
594 mInitListener = listener;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000595 mRequestedEngine = engine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000596 mUseFallback = useFallback;
Jean-Michel Trivi87c96842009-06-25 14:29:15 -0700597
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000598 mEarcons = new HashMap<String, Uri>();
599 mUtterances = new HashMap<String, Uri>();
Narayan Kamath68e2af52011-11-28 17:10:04 +0000600 mUtteranceProgressListener = null;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700601
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100602 mEnginesHelper = new TtsEngines(mContext);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000603 if (packageName != null) {
604 mPackageName = packageName;
605 } else {
606 mPackageName = mContext.getPackageName();
607 }
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700608 initTts();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700609 }
610
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000611 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method,
612 boolean onlyEstablishedConnection) {
613 return runAction(action, errorResult, method, false, onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000614 }
615
616 private <R> R runAction(Action<R> action, R errorResult, String method) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000617 return runAction(action, errorResult, method, true, true);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000618 }
619
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000620 private <R> R runAction(Action<R> action, R errorResult, String method,
621 boolean reconnect, boolean onlyEstablishedConnection) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000622 synchronized (mStartLock) {
623 if (mServiceConnection == null) {
624 Log.w(TAG, method + " failed: not bound to TTS engine");
625 return errorResult;
626 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000627 return mServiceConnection.runAction(action, errorResult, method, reconnect,
628 onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000629 }
630 }
631
632 private int initTts() {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100633 // Step 1: Try connecting to the engine that was requested.
Narayan Kamathc60aad22011-12-06 16:40:03 +0000634 if (mRequestedEngine != null) {
635 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
636 if (connectToEngine(mRequestedEngine)) {
637 mCurrentEngine = mRequestedEngine;
638 return SUCCESS;
639 } else if (!mUseFallback) {
640 mCurrentEngine = null;
641 dispatchOnInit(ERROR);
642 return ERROR;
643 }
644 } else if (!mUseFallback) {
645 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine);
646 mCurrentEngine = null;
647 dispatchOnInit(ERROR);
648 return ERROR;
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100649 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000650 }
651
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100652 // Step 2: Try connecting to the user's default engine.
653 final String defaultEngine = getDefaultEngine();
654 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000655 if (connectToEngine(defaultEngine)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100656 mCurrentEngine = defaultEngine;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000657 return SUCCESS;
658 }
659 }
660
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100661 // Step 3: Try connecting to the highest ranked engine in the
662 // system.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100663 final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100664 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
665 !highestRanked.equals(defaultEngine)) {
Narayan Kamath22302fb2011-06-10 14:22:07 +0100666 if (connectToEngine(highestRanked)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100667 mCurrentEngine = highestRanked;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000668 return SUCCESS;
669 }
670 }
671
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100672 // NOTE: The API currently does not allow the caller to query whether
673 // they are actually connected to any engine. This might fail for various
674 // reasons like if the user disables all her TTS engines.
675
676 mCurrentEngine = null;
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100677 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000678 return ERROR;
679 }
680
681 private boolean connectToEngine(String engine) {
682 Connection connection = new Connection();
683 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
684 intent.setPackage(engine);
685 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
686 if (!bound) {
687 Log.e(TAG, "Failed to bind to " + engine);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000688 return false;
689 } else {
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100690 Log.i(TAG, "Sucessfully bound to " + engine);
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000691 mConnectingServiceConnection = connection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000692 return true;
693 }
694 }
695
696 private void dispatchOnInit(int result) {
697 synchronized (mStartLock) {
698 if (mInitListener != null) {
699 mInitListener.onInit(result);
700 mInitListener = null;
701 }
702 }
703 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700704
Narayan Kamath492b7f02011-11-29 17:02:06 +0000705 private IBinder getCallerIdentity() {
706 return mServiceConnection.getCallerIdentity();
707 }
708
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700709 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700710 * Releases the resources used by the TextToSpeech engine.
711 * It is good practice for instance to call this method in the onDestroy() method of an Activity
712 * so the TextToSpeech engine can be cleanly stopped.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700713 */
714 public void shutdown() {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000715 // Special case, we are asked to shutdown connection that did finalize its connection.
716 synchronized (mStartLock) {
717 if (mConnectingServiceConnection != null) {
718 mContext.unbindService(mConnectingServiceConnection);
719 mConnectingServiceConnection = null;
720 return;
721 }
722 }
723
724 // Post connection case
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000725 runActionNoReconnect(new Action<Void>() {
726 @Override
727 public Void run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000728 service.setCallback(getCallerIdentity(), null);
729 service.stop(getCallerIdentity());
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000730 mServiceConnection.disconnect();
Narayan Kamath90e56502011-07-18 14:43:07 +0100731 // Context#unbindService does not result in a call to
732 // ServiceConnection#onServiceDisconnected. As a result, the
733 // service ends up being destroyed (if there are no other open
734 // connections to it) but the process lives on and the
735 // ServiceConnection continues to refer to the destroyed service.
736 //
737 // This leads to tons of log spam about SynthThread being dead.
738 mServiceConnection = null;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100739 mCurrentEngine = null;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000740 return null;
741 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000742 }, null, "shutdown", false);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700743 }
744
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700745 /**
746 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700747 * package. After a call to this method, subsequent calls to
748 * {@link #speak(String, int, HashMap)} will play the specified sound resource
749 * if it is available, or synthesize the text it is missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700750 *
751 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700752 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700753 *
754 * @param packagename
755 * Pass the packagename of the application that contains the
756 * resource. If the resource is in your own application (this is
757 * the most common case), then put the packagename of your
758 * application here.<br/>
759 * Example: <b>"com.google.marvin.compass"</b><br/>
760 * The packagename can be found in the AndroidManifest.xml of
761 * your application.
762 * <p>
763 * <code>&lt;manifest xmlns:android=&quot;...&quot;
764 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
765 * </p>
766 *
767 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700768 * Example: <code>R.raw.south_south_east</code>
Charles Chen5c22f512009-06-29 15:52:47 -0700769 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700770 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700771 */
Charles Chen5c22f512009-06-29 15:52:47 -0700772 public int addSpeech(String text, String packagename, int resourceId) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000773 synchronized (mStartLock) {
774 mUtterances.put(text, makeResourceUri(packagename, resourceId));
775 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700776 }
777 }
778
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700779 /**
780 * Adds a mapping between a string of text and a sound file. Using this, it
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700781 * is possible to add custom pronounciations for a string of text.
782 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
783 * will play the specified sound resource if it is available, or synthesize the text it is
784 * missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700785 *
786 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700787 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700788 * @param filename
789 * The full path to the sound file (for example:
790 * "/sdcard/mysounds/hello.wav")
Charles Chen5c22f512009-06-29 15:52:47 -0700791 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700792 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700793 */
Charles Chen5c22f512009-06-29 15:52:47 -0700794 public int addSpeech(String text, String filename) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700795 synchronized (mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000796 mUtterances.put(text, Uri.parse(filename));
797 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700798 }
799 }
800
801
802 /**
Charles Chen904dfa52009-07-15 10:44:41 -0700803 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700804 * package. Use this to add custom earcons.
Charles Chen904dfa52009-07-15 10:44:41 -0700805 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700806 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700807 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700808 * @param earcon The name of the earcon.
809 * Example: <code>"[tick]"</code><br/>
Charles Chen904dfa52009-07-15 10:44:41 -0700810 *
811 * @param packagename
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700812 * the package name of the application that contains the
813 * resource. This can for instance be the package name of your own application.
Charles Chen904dfa52009-07-15 10:44:41 -0700814 * Example: <b>"com.google.marvin.compass"</b><br/>
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700815 * The package name can be found in the AndroidManifest.xml of
816 * the application containing the resource.
Charles Chen904dfa52009-07-15 10:44:41 -0700817 * <p>
818 * <code>&lt;manifest xmlns:android=&quot;...&quot;
819 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
820 * </p>
821 *
822 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700823 * Example: <code>R.raw.tick_snd</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700824 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700825 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700826 */
827 public int addEarcon(String earcon, String packagename, int resourceId) {
828 synchronized(mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000829 mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
830 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700831 }
832 }
833
Charles Chen904dfa52009-07-15 10:44:41 -0700834 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700835 * Adds a mapping between a string of text and a sound file.
836 * Use this to add custom earcons.
837 *
838 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700839 *
840 * @param earcon
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700841 * The name of the earcon.
842 * Example: <code>"[tick]"</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700843 * @param filename
844 * The full path to the sound file (for example:
845 * "/sdcard/mysounds/tick.wav")
846 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700847 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700848 */
849 public int addEarcon(String earcon, String filename) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000850 synchronized(mStartLock) {
851 mEarcons.put(earcon, Uri.parse(filename));
852 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700853 }
854 }
855
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000856 private Uri makeResourceUri(String packageName, int resourceId) {
857 return new Uri.Builder()
858 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
859 .encodedAuthority(packageName)
860 .appendEncodedPath(String.valueOf(resourceId))
861 .build();
862 }
Charles Chen904dfa52009-07-15 10:44:41 -0700863
864 /**
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100865 * Speaks the string using the specified queuing strategy and speech parameters.
866 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
867 * requests and then returns. The synthesis might not have finished (or even started!) at the
868 * time when this method returns. In order to reliably detect errors during synthesis,
869 * we recommend setting an utterance progress listener (see
870 * {@link #setOnUtteranceProgressListener}) and using the
871 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700872 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +0000873 * @param text The string of text to be spoken. No longer than
874 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000875 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
876 * @param params Parameters for the request. Can be null.
877 * Supported parameter names:
878 * {@link Engine#KEY_PARAM_STREAM},
879 * {@link Engine#KEY_PARAM_UTTERANCE_ID},
880 * {@link Engine#KEY_PARAM_VOLUME},
881 * {@link Engine#KEY_PARAM_PAN}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100882 * Engine specific parameters may be passed in but the parameter keys
883 * must be prefixed by the name of the engine they are intended for. For example
884 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
885 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700886 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100887 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700888 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000889 public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
890 return runAction(new Action<Integer>() {
891 @Override
892 public Integer run(ITextToSpeechService service) throws RemoteException {
893 Uri utteranceUri = mUtterances.get(text);
894 if (utteranceUri != null) {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000895 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000896 getParams(params));
897 } else {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000898 return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700899 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700900 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000901 }, ERROR, "speak");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700902 }
903
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700904 /**
905 * Plays the earcon using the specified queueing mode and parameters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000906 * The earcon must already have been added with {@link #addEarcon(String, String)} or
907 * {@link #addEarcon(String, String, int)}.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100908 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
909 * requests and then returns. The synthesis might not have finished (or even started!) at the
910 * time when this method returns. In order to reliably detect errors during synthesis,
911 * we recommend setting an utterance progress listener (see
912 * {@link #setOnUtteranceProgressListener}) and using the
913 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700914 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000915 * @param earcon The earcon that should be played
916 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
917 * @param params Parameters for the request. Can be null.
918 * Supported parameter names:
919 * {@link Engine#KEY_PARAM_STREAM},
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700920 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100921 * Engine specific parameters may be passed in but the parameter keys
922 * must be prefixed by the name of the engine they are intended for. For example
923 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
924 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700925 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100926 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700927 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000928 public int playEarcon(final String earcon, final int queueMode,
929 final HashMap<String, String> params) {
930 return runAction(new Action<Integer>() {
931 @Override
932 public Integer run(ITextToSpeechService service) throws RemoteException {
933 Uri earconUri = mEarcons.get(earcon);
934 if (earconUri == null) {
935 return ERROR;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700936 }
Narayan Kamath492b7f02011-11-29 17:02:06 +0000937 return service.playAudio(getCallerIdentity(), earconUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000938 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700939 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000940 }, ERROR, "playEarcon");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700941 }
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700942
Charles Chen5c22f512009-06-29 15:52:47 -0700943 /**
944 * Plays silence for the specified amount of time using the specified
945 * queue mode.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100946 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
947 * requests and then returns. The synthesis might not have finished (or even started!) at the
948 * time when this method returns. In order to reliably detect errors during synthesis,
949 * we recommend setting an utterance progress listener (see
950 * {@link #setOnUtteranceProgressListener}) and using the
951 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Charles Chen5c22f512009-06-29 15:52:47 -0700952 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000953 * @param durationInMs The duration of the silence.
954 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
955 * @param params Parameters for the request. Can be null.
956 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700957 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100958 * Engine specific parameters may be passed in but the parameter keys
959 * must be prefixed by the name of the engine they are intended for. For example
960 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
961 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700962 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100963 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
Charles Chen5c22f512009-06-29 15:52:47 -0700964 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000965 public int playSilence(final long durationInMs, final int queueMode,
966 final HashMap<String, String> params) {
967 return runAction(new Action<Integer>() {
968 @Override
969 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000970 return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000971 getParams(params));
Charles Chenf032bc72009-06-26 14:41:55 -0700972 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000973 }, ERROR, "playSilence");
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700974 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700975
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700976 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000977 * Queries the engine for the set of features it supports for a given locale.
978 * Features can either be framework defined, e.g.
979 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific.
980 * Engine specific keys must be prefixed by the name of the engine they
981 * are intended for. These keys can be used as parameters to
982 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and
983 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}.
984 *
985 * Features are boolean flags, and their values in the synthesis parameters
986 * must be behave as per {@link Boolean#parseBoolean(String)}.
987 *
988 * @param locale The locale to query features for.
989 */
990 public Set<String> getFeatures(final Locale locale) {
991 return runAction(new Action<Set<String>>() {
992 @Override
993 public Set<String> run(ITextToSpeechService service) throws RemoteException {
994 String[] features = service.getFeaturesForLanguage(
995 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant());
996 if (features != null) {
997 final Set<String> featureSet = new HashSet<String>();
998 Collections.addAll(featureSet, features);
999 return featureSet;
1000 }
1001 return null;
1002 }
1003 }, null, "getFeatures");
1004 }
1005
1006 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +01001007 * Checks whether the TTS engine is busy speaking. Note that a speech item is
1008 * considered complete once it's audio data has been sent to the audio mixer, or
1009 * written to a file. There might be a finite lag between this point, and when
1010 * the audio hardware completes playback.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001011 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001012 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001013 */
1014 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001015 return runAction(new Action<Boolean>() {
1016 @Override
1017 public Boolean run(ITextToSpeechService service) throws RemoteException {
1018 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001019 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001020 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001021 }
1022
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001023 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001024 * Interrupts the current utterance (whether played or rendered to file) and discards other
1025 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -07001026 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001027 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001028 */
Charles Chen5c22f512009-06-29 15:52:47 -07001029 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001030 return runAction(new Action<Integer>() {
1031 @Override
1032 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +00001033 return service.stop(getCallerIdentity());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001034 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001035 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001036 }
1037
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001038 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001039 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001040 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001041 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001042 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001043 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
1044 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
1045 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -07001046 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001047 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001048 */
Charles Chen5c22f512009-06-29 15:52:47 -07001049 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001050 if (speechRate > 0.0f) {
1051 int intRate = (int)(speechRate * 100);
1052 if (intRate > 0) {
1053 synchronized (mStartLock) {
1054 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001055 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001056 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001057 }
1058 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001059 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001060 }
1061
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001062 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001063 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001064 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001065 * This has no effect on any pre-recorded speech.
1066 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001067 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001068 * lower values lower the tone of the synthesized voice,
1069 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -07001070 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001071 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001072 */
Charles Chen5c22f512009-06-29 15:52:47 -07001073 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001074 if (pitch > 0.0f) {
1075 int intPitch = (int)(pitch * 100);
1076 if (intPitch > 0) {
1077 synchronized (mStartLock) {
1078 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001079 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001080 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001081 }
1082 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001083 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001084 }
1085
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001086 /**
Narayan Kamathbd2492e2011-06-27 18:35:47 +01001087 * @return the engine currently in use by this TextToSpeech instance.
1088 * @hide
1089 */
1090 public String getCurrentEngine() {
1091 return mCurrentEngine;
1092 }
1093
1094 /**
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001095 * Returns a Locale instance describing the language currently being used as the default
1096 * Text-to-speech language.
1097 *
1098 * @return language, country (if any) and variant (if any) used by the client stored in a
1099 * Locale instance, or {@code null} on error.
1100 */
1101 public Locale getDefaultLanguage() {
1102 return runAction(new Action<Locale>() {
1103 @Override
1104 public Locale run(ITextToSpeechService service) throws RemoteException {
1105 String[] defaultLanguage = service.getClientDefaultLanguage();
1106
1107 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]);
1108 }
1109 }, null, "getDefaultLanguage");
1110 }
1111
1112 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001113 * Sets the text-to-speech language.
1114 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001115 * language as represented by the Locale, but there is no guarantee that the exact same Locale
1116 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1117 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001118 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001119 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001120 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001121 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001122 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1123 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001124 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001125 public int setLanguage(final Locale loc) {
1126 return runAction(new Action<Integer>() {
1127 @Override
1128 public Integer run(ITextToSpeechService service) throws RemoteException {
1129 if (loc == null) {
1130 return LANG_NOT_SUPPORTED;
1131 }
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001132 String language = null, country = null;
1133 try {
1134 language = loc.getISO3Language();
1135 } catch (MissingResourceException e) {
1136 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1137 return LANG_NOT_SUPPORTED;
1138 }
1139
1140 try {
1141 country = loc.getISO3Country();
1142 } catch (MissingResourceException e) {
1143 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1144 return LANG_NOT_SUPPORTED;
1145 }
1146
Charles Chen1a2712c2010-04-01 17:16:28 -07001147 String variant = loc.getVariant();
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001148
Charles Chen1a2712c2010-04-01 17:16:28 -07001149 // Check if the language, country, variant are available, and cache
1150 // the available parts.
1151 // Note that the language is not actually set here, instead it is cached so it
1152 // will be associated with all upcoming utterances.
Przemyslaw Szczepaniak13896b72012-11-09 15:18:16 +00001153
1154 int result = service.loadLanguage(getCallerIdentity(), language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001155 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001156 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
1157 variant = "";
1158 if (result < LANG_COUNTRY_AVAILABLE) {
1159 country = "";
1160 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001161 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001162 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
1163 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
1164 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001165 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001166 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001167 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001168 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001169 }
1170
Charles Chenaaf842e2009-06-25 11:59:29 -07001171 /**
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001172 * Returns a Locale instance describing the language currently being used for synthesis
1173 * requests sent to the TextToSpeech engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001174 *
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001175 * In Android 4.2 and before (API <= 17) this function returns the language that is currently
1176 * being used by the TTS engine. That is the last language set by this or any other
1177 * client by a {@link TextToSpeech#setLanguage} call to the same engine.
1178 *
1179 * In Android versions after 4.2 this function returns the language that is currently being
1180 * used for the synthesis requests sent from this client. That is the last language set
1181 * by a {@link TextToSpeech#setLanguage} call on this instance.
1182 *
1183 * @return language, country (if any) and variant (if any) used by the client stored in a
1184 * Locale instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001185 */
1186 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001187 return runAction(new Action<Locale>() {
1188 @Override
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001189 public Locale run(ITextToSpeechService service) {
1190 /* No service call, but we're accessing mParams, hence need for
1191 wrapping it as an Action instance */
1192 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, "");
1193 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, "");
1194 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, "");
1195 return new Locale(lang, country, variant);
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001196 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001197 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001198 }
1199
1200 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001201 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -07001202 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001203 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001204 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001205 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001206 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1207 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -07001208 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001209 public int isLanguageAvailable(final Locale loc) {
1210 return runAction(new Action<Integer>() {
1211 @Override
1212 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001213 String language = null, country = null;
1214
1215 try {
1216 language = loc.getISO3Language();
1217 } catch (MissingResourceException e) {
1218 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1219 return LANG_NOT_SUPPORTED;
1220 }
1221
1222 try {
1223 country = loc.getISO3Country();
1224 } catch (MissingResourceException e) {
1225 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1226 return LANG_NOT_SUPPORTED;
1227 }
1228
1229 return service.isLanguageAvailable(language, country, loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001230 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001231 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -07001232 }
1233
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001234 /**
Charles Chend4989092009-06-26 15:32:46 -07001235 * Synthesizes the given text to a file using the specified parameters.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001236 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
1237 * requests and then returns. The synthesis might not have finished (or even started!) at the
1238 * time when this method returns. In order to reliably detect errors during synthesis,
1239 * we recommend setting an utterance progress listener (see
1240 * {@link #setOnUtteranceProgressListener}) and using the
1241 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001242 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001243 * @param text The text that should be synthesized. No longer than
1244 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001245 * @param params Parameters for the request. Can be null.
1246 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001247 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +01001248 * Engine specific parameters may be passed in but the parameter keys
1249 * must be prefixed by the name of the engine they are intended for. For example
1250 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
1251 * engine named "com.svox.pico" if it is being used.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001252 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001253 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -07001254 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001255 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001256 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001257 public int synthesizeToFile(final String text, final HashMap<String, String> params,
1258 final String filename) {
1259 return runAction(new Action<Integer>() {
1260 @Override
1261 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +00001262 ParcelFileDescriptor fileDescriptor;
1263 int returnValue;
1264 try {
1265 File file = new File(filename);
1266 if(file.exists() && !file.canWrite()) {
1267 Log.e(TAG, "Can't write to " + filename);
1268 return ERROR;
1269 }
1270 fileDescriptor = ParcelFileDescriptor.open(file,
1271 ParcelFileDescriptor.MODE_WRITE_ONLY |
1272 ParcelFileDescriptor.MODE_CREATE |
1273 ParcelFileDescriptor.MODE_TRUNCATE);
1274 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
1275 fileDescriptor, getParams(params));
1276 fileDescriptor.close();
1277 return returnValue;
1278 } catch (FileNotFoundException e) {
1279 Log.e(TAG, "Opening file " + filename + " failed", e);
1280 return ERROR;
1281 } catch (IOException e) {
1282 Log.e(TAG, "Closing file " + filename + " failed", e);
1283 return ERROR;
1284 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001285 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001286 }, ERROR, "synthesizeToFile");
1287 }
1288
1289 private Bundle getParams(HashMap<String, String> params) {
1290 if (params != null && !params.isEmpty()) {
1291 Bundle bundle = new Bundle(mParams);
1292 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
1293 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
1294 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
1295 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
Narayan Kamathb956f372011-05-16 16:51:44 +01001296
Narayan Kamath748af662011-10-31 14:20:01 +00001297 // Copy feature strings defined by the framework.
1298 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
Narayan Kamath6c07a202011-11-07 14:21:39 +00001299 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
Narayan Kamath748af662011-10-31 14:20:01 +00001300
Narayan Kamathb956f372011-05-16 16:51:44 +01001301 // Copy over all parameters that start with the name of the
1302 // engine that we are currently connected to. The engine is
1303 // free to interpret them as it chooses.
1304 if (!TextUtils.isEmpty(mCurrentEngine)) {
1305 for (Map.Entry<String, String> entry : params.entrySet()) {
1306 final String key = entry.getKey();
1307 if (key != null && key.startsWith(mCurrentEngine)) {
1308 bundle.putString(key, entry.getValue());
1309 }
1310 }
1311 }
1312
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001313 return bundle;
1314 } else {
1315 return mParams;
1316 }
1317 }
1318
1319 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
1320 String value = params.get(key);
1321 if (value != null) {
1322 bundle.putString(key, value);
1323 }
1324 }
1325
1326 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
1327 String valueString = params.get(key);
1328 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001329 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001330 int value = Integer.parseInt(valueString);
1331 bundle.putInt(key, value);
1332 } catch (NumberFormatException ex) {
1333 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001334 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001335 }
1336 }
1337
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001338 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
1339 String valueString = params.get(key);
1340 if (!TextUtils.isEmpty(valueString)) {
1341 try {
1342 float value = Float.parseFloat(valueString);
1343 bundle.putFloat(key, value);
1344 } catch (NumberFormatException ex) {
1345 // don't set the value in the bundle
1346 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -08001347 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -07001348 }
1349
Charles Chen78c9d0d2009-07-13 16:22:41 -07001350 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001351 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001352 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001353 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001354 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001355 * @return {@link #ERROR} or {@link #SUCCESS}.
Narayan Kamath754c72e2011-11-09 14:22:32 +00001356 *
1357 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1358 * instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001359 */
Narayan Kamath754c72e2011-11-09 14:22:32 +00001360 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001361 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001362 mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1363 return TextToSpeech.SUCCESS;
1364 }
1365
1366 /**
1367 * Sets the listener that will be notified of various events related to the
1368 * synthesis of a given utterance.
1369 *
1370 * See {@link UtteranceProgressListener} and
1371 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1372 *
1373 * @param listener the listener to use.
1374 * @return {@link #ERROR} or {@link #SUCCESS}
1375 */
1376 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1377 mUtteranceProgressListener = listener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001378 return TextToSpeech.SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001379 }
1380
Charles Chenb4fbe762009-11-18 16:34:32 -08001381 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001382 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001383 *
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001384 * @deprecated This doesn't inform callers when the TTS engine has been
1385 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
Narayan Kamathb9db1fb2011-07-14 15:30:36 +01001386 * can be used with the appropriate engine name. Also, there is no
1387 * guarantee that the engine specified will be loaded. If it isn't
1388 * installed or disabled, the user / system wide defaults will apply.
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001389 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001390 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001391 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001392 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001393 */
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001394 @Deprecated
Charles Chen60dd3602010-01-07 18:56:24 -08001395 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001396 mRequestedEngine = enginePackageName;
1397 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001398 }
1399
Charles Chendef71852010-03-25 19:59:50 -07001400 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001401 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001402 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001403 * @return Package name of the TTS engine that the user has chosen
1404 * as their default.
Charles Chendef71852010-03-25 19:59:50 -07001405 */
1406 public String getDefaultEngine() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001407 return mEnginesHelper.getDefaultEngine();
Charles Chendef71852010-03-25 19:59:50 -07001408 }
Charles Chen42229252010-03-29 18:30:30 -07001409
Charles Chen42229252010-03-29 18:30:30 -07001410 /**
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001411 * Checks whether the user's settings should override settings requested
1412 * by the calling application. As of the Ice cream sandwich release,
1413 * user settings never forcibly override the app's settings.
Charles Chen42229252010-03-29 18:30:30 -07001414 */
1415 public boolean areDefaultsEnforced() {
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001416 return false;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001417 }
1418
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001419 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001420 * Gets a list of all installed TTS engines.
1421 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001422 * @return A list of engine info objects. The list can be empty, but never {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001423 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001424 public List<EngineInfo> getEngines() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001425 return mEnginesHelper.getEngines();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001426 }
1427
1428 private class Connection implements ServiceConnection {
1429 private ITextToSpeechService mService;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001430
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001431 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask;
1432
1433 private boolean mEstablished;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001434
Narayan Kamatha57f2382011-10-04 17:20:09 +01001435 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
1436 @Override
Narayan Kamath754c72e2011-11-09 14:22:32 +00001437 public void onDone(String utteranceId) {
1438 UtteranceProgressListener listener = mUtteranceProgressListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001439 if (listener != null) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001440 listener.onDone(utteranceId);
1441 }
1442 }
1443
1444 @Override
1445 public void onError(String utteranceId) {
1446 UtteranceProgressListener listener = mUtteranceProgressListener;
1447 if (listener != null) {
1448 listener.onError(utteranceId);
1449 }
1450 }
1451
1452 @Override
1453 public void onStart(String utteranceId) {
1454 UtteranceProgressListener listener = mUtteranceProgressListener;
1455 if (listener != null) {
1456 listener.onStart(utteranceId);
Narayan Kamatha57f2382011-10-04 17:20:09 +01001457 }
1458 }
1459 };
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001460
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001461 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001462 private final ComponentName mName;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001463
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001464 public SetupConnectionAsyncTask(ComponentName name) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001465 mName = name;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001466 }
1467
1468 @Override
1469 protected Integer doInBackground(Void... params) {
1470 synchronized(mStartLock) {
1471 if (isCancelled()) {
1472 return null;
1473 }
1474
1475 try {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001476 mService.setCallback(getCallerIdentity(), mCallback);
1477 String[] defaultLanguage = mService.getClientDefaultLanguage();
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001478
1479 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]);
1480 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]);
1481 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]);
1482
1483 Log.i(TAG, "Set up connection to " + mName);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001484 return SUCCESS;
1485 } catch (RemoteException re) {
1486 Log.e(TAG, "Error connecting to service, setCallback() failed");
1487 return ERROR;
1488 }
1489 }
1490 }
1491
1492 @Override
1493 protected void onPostExecute(Integer result) {
1494 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001495 if (mOnSetupConnectionAsyncTask == this) {
1496 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001497 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001498 mEstablished = true;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001499 dispatchOnInit(result);
1500 }
1501 }
1502 }
1503
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001504 @Override
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001505 public void onServiceConnected(ComponentName name, IBinder service) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001506 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001507 mConnectingServiceConnection = null;
1508
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001509 Log.i(TAG, "Connected to " + name);
1510
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001511 if (mOnSetupConnectionAsyncTask != null) {
1512 mOnSetupConnectionAsyncTask.cancel(false);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001513 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001514
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001515 mService = ITextToSpeechService.Stub.asInterface(service);
1516 mServiceConnection = Connection.this;
1517
1518 mEstablished = false;
1519 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name);
1520 mOnSetupConnectionAsyncTask.execute();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001521 }
1522 }
1523
Narayan Kamath492b7f02011-11-29 17:02:06 +00001524 public IBinder getCallerIdentity() {
1525 return mCallback;
1526 }
1527
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001528 /**
1529 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
1530 *
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001531 * @return true if we cancel mOnSetupConnectionAsyncTask in progress.
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001532 */
1533 private boolean clearServiceConnection() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001534 synchronized(mStartLock) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001535 boolean result = false;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001536 if (mOnSetupConnectionAsyncTask != null) {
1537 result = mOnSetupConnectionAsyncTask.cancel(false);
1538 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001539 }
1540
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001541 mService = null;
1542 // If this is the active connection, clear it
1543 if (mServiceConnection == this) {
1544 mServiceConnection = null;
1545 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001546 return result;
1547 }
1548 }
1549
1550 @Override
1551 public void onServiceDisconnected(ComponentName name) {
1552 Log.i(TAG, "Asked to disconnect from " + name);
1553 if (clearServiceConnection()) {
1554 /* We need to protect against a rare case where engine
1555 * dies just after successful connection - and we process onServiceDisconnected
1556 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
1557 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
1558 * with ERROR as argument.
1559 */
1560 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001561 }
1562 }
1563
1564 public void disconnect() {
1565 mContext.unbindService(this);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001566 clearServiceConnection();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001567 }
1568
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001569 public boolean isEstablished() {
1570 return mService != null && mEstablished;
1571 }
1572
1573 public <R> R runAction(Action<R> action, R errorResult, String method,
1574 boolean reconnect, boolean onlyEstablishedConnection) {
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001575 synchronized (mStartLock) {
1576 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001577 if (mService == null) {
1578 Log.w(TAG, method + " failed: not connected to TTS engine");
1579 return errorResult;
1580 }
Fergus Henderson1c2df382013-01-25 14:59:59 +00001581 if (onlyEstablishedConnection && !isEstablished()) {
1582 Log.w(TAG, method + " failed: TTS engine connection not fully set up");
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001583 return errorResult;
1584 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001585 return action.run(mService);
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001586 } catch (RemoteException ex) {
1587 Log.e(TAG, method + " failed", ex);
1588 if (reconnect) {
1589 disconnect();
1590 initTts();
1591 }
1592 return errorResult;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001593 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001594 }
1595 }
1596 }
1597
1598 private interface Action<R> {
1599 R run(ITextToSpeechService service) throws RemoteException;
1600 }
1601
1602 /**
1603 * Information about an installed text-to-speech engine.
1604 *
1605 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001606 */
1607 public static class EngineInfo {
1608 /**
1609 * Engine package name..
1610 */
1611 public String name;
1612 /**
1613 * Localized label for the engine.
1614 */
1615 public String label;
1616 /**
1617 * Icon for the engine.
1618 */
1619 public int icon;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001620 /**
1621 * Whether this engine is a part of the system
1622 * image.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001623 *
1624 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001625 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001626 public boolean system;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001627 /**
1628 * The priority the engine declares for the the intent filter
1629 * {@code android.intent.action.TTS_SERVICE}
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001630 *
1631 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001632 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001633 public int priority;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001634
1635 @Override
1636 public String toString() {
1637 return "EngineInfo{name=" + name + "}";
1638 }
1639
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001640 }
Narayan Kamath22302fb2011-06-10 14:22:07 +01001641
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001642 /**
1643 * Limit of length of input string passed to speak and synthesizeToFile.
1644 *
1645 * @see #speak
1646 * @see #synthesizeToFile
1647 */
1648 public static int getMaxSpeechInputLength() {
1649 return 4000;
1650 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001651}