blob: 2752085a427e06c6849088f9b29f87610098bb3d [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
Przemyslaw Szczepaniake86a936a2013-04-30 16:41:14 +0100564 * TextToSpeech engine has initialized. In a case of a failure the listener
565 * may be called immediately, before TextToSpeech instance is fully constructed.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700566 */
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700567 public TextToSpeech(Context context, OnInitListener listener) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000568 this(context, listener, null);
569 }
570
571 /**
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100572 * The constructor for the TextToSpeech class, using the given TTS engine.
573 * This will also initialize the associated TextToSpeech engine if it isn't already running.
574 *
575 * @param context
576 * The context this instance is running in.
577 * @param listener
578 * The {@link TextToSpeech.OnInitListener} that will be called when the
Przemyslaw Szczepaniake86a936a2013-04-30 16:41:14 +0100579 * TextToSpeech engine has initialized. In a case of a failure the listener
580 * may be called immediately, before TextToSpeech instance is fully constructed.
Bjorn Bringert4bbca882011-04-19 18:45:25 +0100581 * @param engine Package name of the TTS engine to use.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000582 */
583 public TextToSpeech(Context context, OnInitListener listener, String engine) {
Narayan Kamathc60aad22011-12-06 16:40:03 +0000584 this(context, listener, engine, null, true);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000585 }
586
587 /**
588 * Used by the framework to instantiate TextToSpeech objects with a supplied
589 * package name, instead of using {@link android.content.Context#getPackageName()}
590 *
591 * @hide
592 */
593 public TextToSpeech(Context context, OnInitListener listener, String engine,
Narayan Kamathc60aad22011-12-06 16:40:03 +0000594 String packageName, boolean useFallback) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700595 mContext = context;
596 mInitListener = listener;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000597 mRequestedEngine = engine;
Narayan Kamathc60aad22011-12-06 16:40:03 +0000598 mUseFallback = useFallback;
Jean-Michel Trivi87c96842009-06-25 14:29:15 -0700599
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000600 mEarcons = new HashMap<String, Uri>();
601 mUtterances = new HashMap<String, Uri>();
Narayan Kamath68e2af52011-11-28 17:10:04 +0000602 mUtteranceProgressListener = null;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700603
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100604 mEnginesHelper = new TtsEngines(mContext);
Narayan Kamath68e2af52011-11-28 17:10:04 +0000605 if (packageName != null) {
606 mPackageName = packageName;
607 } else {
608 mPackageName = mContext.getPackageName();
609 }
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700610 initTts();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700611 }
612
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000613 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method,
614 boolean onlyEstablishedConnection) {
615 return runAction(action, errorResult, method, false, onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000616 }
617
618 private <R> R runAction(Action<R> action, R errorResult, String method) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000619 return runAction(action, errorResult, method, true, true);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000620 }
621
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000622 private <R> R runAction(Action<R> action, R errorResult, String method,
623 boolean reconnect, boolean onlyEstablishedConnection) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000624 synchronized (mStartLock) {
625 if (mServiceConnection == null) {
626 Log.w(TAG, method + " failed: not bound to TTS engine");
627 return errorResult;
628 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000629 return mServiceConnection.runAction(action, errorResult, method, reconnect,
630 onlyEstablishedConnection);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000631 }
632 }
633
634 private int initTts() {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100635 // Step 1: Try connecting to the engine that was requested.
Narayan Kamathc60aad22011-12-06 16:40:03 +0000636 if (mRequestedEngine != null) {
637 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
638 if (connectToEngine(mRequestedEngine)) {
639 mCurrentEngine = mRequestedEngine;
640 return SUCCESS;
641 } else if (!mUseFallback) {
642 mCurrentEngine = null;
643 dispatchOnInit(ERROR);
644 return ERROR;
645 }
646 } else if (!mUseFallback) {
647 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine);
648 mCurrentEngine = null;
649 dispatchOnInit(ERROR);
650 return ERROR;
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100651 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000652 }
653
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100654 // Step 2: Try connecting to the user's default engine.
655 final String defaultEngine = getDefaultEngine();
656 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000657 if (connectToEngine(defaultEngine)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100658 mCurrentEngine = defaultEngine;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000659 return SUCCESS;
660 }
661 }
662
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100663 // Step 3: Try connecting to the highest ranked engine in the
664 // system.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +0100665 final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100666 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
667 !highestRanked.equals(defaultEngine)) {
Narayan Kamath22302fb2011-06-10 14:22:07 +0100668 if (connectToEngine(highestRanked)) {
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100669 mCurrentEngine = highestRanked;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000670 return SUCCESS;
671 }
672 }
673
Narayan Kamathb9db1fb2011-07-14 15:30:36 +0100674 // NOTE: The API currently does not allow the caller to query whether
675 // they are actually connected to any engine. This might fail for various
676 // reasons like if the user disables all her TTS engines.
677
678 mCurrentEngine = null;
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100679 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000680 return ERROR;
681 }
682
683 private boolean connectToEngine(String engine) {
684 Connection connection = new Connection();
685 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
686 intent.setPackage(engine);
687 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
688 if (!bound) {
689 Log.e(TAG, "Failed to bind to " + engine);
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000690 return false;
691 } else {
Narayan Kamath0e20fe52011-06-14 12:39:55 +0100692 Log.i(TAG, "Sucessfully bound to " + engine);
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000693 mConnectingServiceConnection = connection;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000694 return true;
695 }
696 }
697
698 private void dispatchOnInit(int result) {
699 synchronized (mStartLock) {
700 if (mInitListener != null) {
701 mInitListener.onInit(result);
702 mInitListener = null;
703 }
704 }
705 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700706
Narayan Kamath492b7f02011-11-29 17:02:06 +0000707 private IBinder getCallerIdentity() {
708 return mServiceConnection.getCallerIdentity();
709 }
710
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700711 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700712 * Releases the resources used by the TextToSpeech engine.
713 * It is good practice for instance to call this method in the onDestroy() method of an Activity
714 * so the TextToSpeech engine can be cleanly stopped.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700715 */
716 public void shutdown() {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000717 // Special case, we are asked to shutdown connection that did finalize its connection.
718 synchronized (mStartLock) {
719 if (mConnectingServiceConnection != null) {
720 mContext.unbindService(mConnectingServiceConnection);
721 mConnectingServiceConnection = null;
722 return;
723 }
724 }
725
726 // Post connection case
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000727 runActionNoReconnect(new Action<Void>() {
728 @Override
729 public Void run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000730 service.setCallback(getCallerIdentity(), null);
731 service.stop(getCallerIdentity());
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000732 mServiceConnection.disconnect();
Narayan Kamath90e56502011-07-18 14:43:07 +0100733 // Context#unbindService does not result in a call to
734 // ServiceConnection#onServiceDisconnected. As a result, the
735 // service ends up being destroyed (if there are no other open
736 // connections to it) but the process lives on and the
737 // ServiceConnection continues to refer to the destroyed service.
738 //
739 // This leads to tons of log spam about SynthThread being dead.
740 mServiceConnection = null;
Narayan Kamathbd2492e2011-06-27 18:35:47 +0100741 mCurrentEngine = null;
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000742 return null;
743 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +0000744 }, null, "shutdown", false);
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700745 }
746
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700747 /**
748 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700749 * package. After a call to this method, subsequent calls to
750 * {@link #speak(String, int, HashMap)} will play the specified sound resource
751 * if it is available, or synthesize the text it is missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700752 *
753 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700754 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700755 *
756 * @param packagename
757 * Pass the packagename of the application that contains the
758 * resource. If the resource is in your own application (this is
759 * the most common case), then put the packagename of your
760 * application here.<br/>
761 * Example: <b>"com.google.marvin.compass"</b><br/>
762 * The packagename can be found in the AndroidManifest.xml of
763 * your application.
764 * <p>
765 * <code>&lt;manifest xmlns:android=&quot;...&quot;
766 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
767 * </p>
768 *
769 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700770 * Example: <code>R.raw.south_south_east</code>
Charles Chen5c22f512009-06-29 15:52:47 -0700771 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700772 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700773 */
Charles Chen5c22f512009-06-29 15:52:47 -0700774 public int addSpeech(String text, String packagename, int resourceId) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000775 synchronized (mStartLock) {
776 mUtterances.put(text, makeResourceUri(packagename, resourceId));
777 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700778 }
779 }
780
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700781 /**
782 * Adds a mapping between a string of text and a sound file. Using this, it
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700783 * is possible to add custom pronounciations for a string of text.
784 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
785 * will play the specified sound resource if it is available, or synthesize the text it is
786 * missing.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700787 *
788 * @param text
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700789 * The string of text. Example: <code>"south_south_east"</code>
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700790 * @param filename
791 * The full path to the sound file (for example:
792 * "/sdcard/mysounds/hello.wav")
Charles Chen5c22f512009-06-29 15:52:47 -0700793 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700794 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700795 */
Charles Chen5c22f512009-06-29 15:52:47 -0700796 public int addSpeech(String text, String filename) {
Jean-Michel Trivi91bf30a2009-06-11 14:35:48 -0700797 synchronized (mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000798 mUtterances.put(text, Uri.parse(filename));
799 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700800 }
801 }
802
803
804 /**
Charles Chen904dfa52009-07-15 10:44:41 -0700805 * Adds a mapping between a string of text and a sound resource in a
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700806 * package. Use this to add custom earcons.
Charles Chen904dfa52009-07-15 10:44:41 -0700807 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700808 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700809 *
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700810 * @param earcon The name of the earcon.
811 * Example: <code>"[tick]"</code><br/>
Charles Chen904dfa52009-07-15 10:44:41 -0700812 *
813 * @param packagename
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700814 * the package name of the application that contains the
815 * resource. This can for instance be the package name of your own application.
Charles Chen904dfa52009-07-15 10:44:41 -0700816 * Example: <b>"com.google.marvin.compass"</b><br/>
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700817 * The package name can be found in the AndroidManifest.xml of
818 * the application containing the resource.
Charles Chen904dfa52009-07-15 10:44:41 -0700819 * <p>
820 * <code>&lt;manifest xmlns:android=&quot;...&quot;
821 * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
822 * </p>
823 *
824 * @param resourceId
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700825 * Example: <code>R.raw.tick_snd</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700826 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700827 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700828 */
829 public int addEarcon(String earcon, String packagename, int resourceId) {
830 synchronized(mStartLock) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000831 mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
832 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700833 }
834 }
835
Charles Chen904dfa52009-07-15 10:44:41 -0700836 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700837 * Adds a mapping between a string of text and a sound file.
838 * Use this to add custom earcons.
839 *
840 * @see #playEarcon(String, int, HashMap)
Charles Chen904dfa52009-07-15 10:44:41 -0700841 *
842 * @param earcon
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700843 * The name of the earcon.
844 * Example: <code>"[tick]"</code>
Charles Chen904dfa52009-07-15 10:44:41 -0700845 * @param filename
846 * The full path to the sound file (for example:
847 * "/sdcard/mysounds/tick.wav")
848 *
Jean-Michel Trivied065782009-07-28 14:31:48 -0700849 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
Charles Chen904dfa52009-07-15 10:44:41 -0700850 */
851 public int addEarcon(String earcon, String filename) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000852 synchronized(mStartLock) {
853 mEarcons.put(earcon, Uri.parse(filename));
854 return SUCCESS;
Charles Chen904dfa52009-07-15 10:44:41 -0700855 }
856 }
857
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000858 private Uri makeResourceUri(String packageName, int resourceId) {
859 return new Uri.Builder()
860 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
861 .encodedAuthority(packageName)
862 .appendEncodedPath(String.valueOf(resourceId))
863 .build();
864 }
Charles Chen904dfa52009-07-15 10:44:41 -0700865
866 /**
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100867 * Speaks the string using the specified queuing strategy and speech parameters.
868 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
869 * requests and then returns. The synthesis might not have finished (or even started!) at the
870 * time when this method returns. In order to reliably detect errors during synthesis,
871 * we recommend setting an utterance progress listener (see
872 * {@link #setOnUtteranceProgressListener}) and using the
873 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700874 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +0000875 * @param text The string of text to be spoken. No longer than
876 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000877 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
878 * @param params Parameters for the request. Can be null.
879 * Supported parameter names:
880 * {@link Engine#KEY_PARAM_STREAM},
881 * {@link Engine#KEY_PARAM_UTTERANCE_ID},
882 * {@link Engine#KEY_PARAM_VOLUME},
883 * {@link Engine#KEY_PARAM_PAN}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100884 * Engine specific parameters may be passed in but the parameter keys
885 * must be prefixed by the name of the engine they are intended for. For example
886 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
887 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700888 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100889 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700890 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000891 public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
892 return runAction(new Action<Integer>() {
893 @Override
894 public Integer run(ITextToSpeechService service) throws RemoteException {
895 Uri utteranceUri = mUtterances.get(text);
896 if (utteranceUri != null) {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000897 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000898 getParams(params));
899 } else {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000900 return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700901 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700902 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000903 }, ERROR, "speak");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700904 }
905
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700906 /**
907 * Plays the earcon using the specified queueing mode and parameters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000908 * The earcon must already have been added with {@link #addEarcon(String, String)} or
909 * {@link #addEarcon(String, String, int)}.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100910 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
911 * requests and then returns. The synthesis might not have finished (or even started!) at the
912 * time when this method returns. In order to reliably detect errors during synthesis,
913 * we recommend setting an utterance progress listener (see
914 * {@link #setOnUtteranceProgressListener}) and using the
915 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700916 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000917 * @param earcon The earcon that should be played
918 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
919 * @param params Parameters for the request. Can be null.
920 * Supported parameter names:
921 * {@link Engine#KEY_PARAM_STREAM},
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700922 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100923 * Engine specific parameters may be passed in but the parameter keys
924 * must be prefixed by the name of the engine they are intended for. For example
925 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
926 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700927 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100928 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700929 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000930 public int playEarcon(final String earcon, final int queueMode,
931 final HashMap<String, String> params) {
932 return runAction(new Action<Integer>() {
933 @Override
934 public Integer run(ITextToSpeechService service) throws RemoteException {
935 Uri earconUri = mEarcons.get(earcon);
936 if (earconUri == null) {
937 return ERROR;
Jean-Michel Trivia9810132009-07-10 12:08:59 -0700938 }
Narayan Kamath492b7f02011-11-29 17:02:06 +0000939 return service.playAudio(getCallerIdentity(), earconUri, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000940 getParams(params));
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700941 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000942 }, ERROR, "playEarcon");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700943 }
Jean-Michel Trivi679d7282009-06-16 15:36:28 -0700944
Charles Chen5c22f512009-06-29 15:52:47 -0700945 /**
946 * Plays silence for the specified amount of time using the specified
947 * queue mode.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100948 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
949 * requests and then returns. The synthesis might not have finished (or even started!) at the
950 * time when this method returns. In order to reliably detect errors during synthesis,
951 * we recommend setting an utterance progress listener (see
952 * {@link #setOnUtteranceProgressListener}) and using the
953 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Charles Chen5c22f512009-06-29 15:52:47 -0700954 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000955 * @param durationInMs The duration of the silence.
956 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
957 * @param params Parameters for the request. Can be null.
958 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -0700959 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +0100960 * Engine specific parameters may be passed in but the parameter keys
961 * must be prefixed by the name of the engine they are intended for. For example
962 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
963 * engine named "com.svox.pico" if it is being used.
Charles Chen5c22f512009-06-29 15:52:47 -0700964 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +0100965 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
Charles Chen5c22f512009-06-29 15:52:47 -0700966 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000967 public int playSilence(final long durationInMs, final int queueMode,
968 final HashMap<String, String> params) {
969 return runAction(new Action<Integer>() {
970 @Override
971 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +0000972 return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000973 getParams(params));
Charles Chenf032bc72009-06-26 14:41:55 -0700974 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +0000975 }, ERROR, "playSilence");
Jean-Michel Trivia8518c12009-06-10 17:33:34 -0700976 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700977
Jean-Michel Trivie74d5072009-05-26 10:43:08 -0700978 /**
Narayan Kamath748af662011-10-31 14:20:01 +0000979 * Queries the engine for the set of features it supports for a given locale.
980 * Features can either be framework defined, e.g.
981 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific.
982 * Engine specific keys must be prefixed by the name of the engine they
983 * are intended for. These keys can be used as parameters to
984 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and
985 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}.
986 *
987 * Features are boolean flags, and their values in the synthesis parameters
988 * must be behave as per {@link Boolean#parseBoolean(String)}.
989 *
990 * @param locale The locale to query features for.
991 */
992 public Set<String> getFeatures(final Locale locale) {
993 return runAction(new Action<Set<String>>() {
994 @Override
995 public Set<String> run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniakca4f1fc2013-09-20 15:29:25 +0100996 String[] features = null;
997 try {
998 features = service.getFeaturesForLanguage(
Narayan Kamath748af662011-10-31 14:20:01 +0000999 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant());
Przemyslaw Szczepaniakca4f1fc2013-09-20 15:29:25 +01001000 } catch(MissingResourceException e) {
1001 Log.w(TAG, "Couldn't retrieve 3 letter ISO 639-2/T language and/or ISO 3166 " +
1002 "country code for locale: " + locale, e);
1003 return null;
1004 }
1005
Narayan Kamath748af662011-10-31 14:20:01 +00001006 if (features != null) {
1007 final Set<String> featureSet = new HashSet<String>();
1008 Collections.addAll(featureSet, features);
1009 return featureSet;
1010 }
1011 return null;
1012 }
1013 }, null, "getFeatures");
1014 }
1015
1016 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +01001017 * Checks whether the TTS engine is busy speaking. Note that a speech item is
1018 * considered complete once it's audio data has been sent to the audio mixer, or
1019 * written to a file. There might be a finite lag between this point, and when
1020 * the audio hardware completes playback.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001021 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001022 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001023 */
1024 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001025 return runAction(new Action<Boolean>() {
1026 @Override
1027 public Boolean run(ITextToSpeechService service) throws RemoteException {
1028 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001029 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001030 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001031 }
1032
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001033 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001034 * Interrupts the current utterance (whether played or rendered to file) and discards other
1035 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -07001036 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001037 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001038 */
Charles Chen5c22f512009-06-29 15:52:47 -07001039 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001040 return runAction(new Action<Integer>() {
1041 @Override
1042 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +00001043 return service.stop(getCallerIdentity());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001044 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001045 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001046 }
1047
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001048 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001049 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001050 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001051 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001052 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001053 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
1054 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
1055 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -07001056 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001057 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001058 */
Charles Chen5c22f512009-06-29 15:52:47 -07001059 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001060 if (speechRate > 0.0f) {
1061 int intRate = (int)(speechRate * 100);
1062 if (intRate > 0) {
1063 synchronized (mStartLock) {
1064 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001065 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001066 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001067 }
1068 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001069 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001070 }
1071
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001072 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001073 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001074 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001075 * This has no effect on any pre-recorded speech.
1076 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001077 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001078 * lower values lower the tone of the synthesized voice,
1079 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -07001080 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001081 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001082 */
Charles Chen5c22f512009-06-29 15:52:47 -07001083 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001084 if (pitch > 0.0f) {
1085 int intPitch = (int)(pitch * 100);
1086 if (intPitch > 0) {
1087 synchronized (mStartLock) {
1088 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001089 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001090 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001091 }
1092 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001093 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001094 }
1095
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001096 /**
Narayan Kamathbd2492e2011-06-27 18:35:47 +01001097 * @return the engine currently in use by this TextToSpeech instance.
1098 * @hide
1099 */
1100 public String getCurrentEngine() {
1101 return mCurrentEngine;
1102 }
1103
1104 /**
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001105 * Returns a Locale instance describing the language currently being used as the default
1106 * Text-to-speech language.
1107 *
1108 * @return language, country (if any) and variant (if any) used by the client stored in a
1109 * Locale instance, or {@code null} on error.
1110 */
1111 public Locale getDefaultLanguage() {
1112 return runAction(new Action<Locale>() {
1113 @Override
1114 public Locale run(ITextToSpeechService service) throws RemoteException {
1115 String[] defaultLanguage = service.getClientDefaultLanguage();
1116
1117 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]);
1118 }
1119 }, null, "getDefaultLanguage");
1120 }
1121
1122 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001123 * Sets the text-to-speech language.
1124 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001125 * language as represented by the Locale, but there is no guarantee that the exact same Locale
1126 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1127 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001128 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001129 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001130 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001131 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001132 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1133 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001134 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001135 public int setLanguage(final Locale loc) {
1136 return runAction(new Action<Integer>() {
1137 @Override
1138 public Integer run(ITextToSpeechService service) throws RemoteException {
1139 if (loc == null) {
1140 return LANG_NOT_SUPPORTED;
1141 }
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001142 String language = null, country = null;
1143 try {
1144 language = loc.getISO3Language();
1145 } catch (MissingResourceException e) {
1146 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1147 return LANG_NOT_SUPPORTED;
1148 }
1149
1150 try {
1151 country = loc.getISO3Country();
1152 } catch (MissingResourceException e) {
1153 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1154 return LANG_NOT_SUPPORTED;
1155 }
1156
Charles Chen1a2712c2010-04-01 17:16:28 -07001157 String variant = loc.getVariant();
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001158
Charles Chen1a2712c2010-04-01 17:16:28 -07001159 // Check if the language, country, variant are available, and cache
1160 // the available parts.
1161 // Note that the language is not actually set here, instead it is cached so it
1162 // will be associated with all upcoming utterances.
Przemyslaw Szczepaniak13896b72012-11-09 15:18:16 +00001163
1164 int result = service.loadLanguage(getCallerIdentity(), language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001165 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001166 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
1167 variant = "";
1168 if (result < LANG_COUNTRY_AVAILABLE) {
1169 country = "";
1170 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001171 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001172 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
1173 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
1174 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001175 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001176 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001177 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001178 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001179 }
1180
Charles Chenaaf842e2009-06-25 11:59:29 -07001181 /**
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001182 * Returns a Locale instance describing the language currently being used for synthesis
1183 * requests sent to the TextToSpeech engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001184 *
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001185 * In Android 4.2 and before (API <= 17) this function returns the language that is currently
1186 * being used by the TTS engine. That is the last language set by this or any other
1187 * client by a {@link TextToSpeech#setLanguage} call to the same engine.
1188 *
1189 * In Android versions after 4.2 this function returns the language that is currently being
1190 * used for the synthesis requests sent from this client. That is the last language set
1191 * by a {@link TextToSpeech#setLanguage} call on this instance.
1192 *
1193 * @return language, country (if any) and variant (if any) used by the client stored in a
1194 * Locale instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001195 */
1196 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001197 return runAction(new Action<Locale>() {
1198 @Override
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001199 public Locale run(ITextToSpeechService service) {
1200 /* No service call, but we're accessing mParams, hence need for
1201 wrapping it as an Action instance */
1202 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, "");
1203 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, "");
1204 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, "");
1205 return new Locale(lang, country, variant);
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001206 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001207 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001208 }
1209
1210 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001211 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -07001212 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001213 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001214 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001215 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001216 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1217 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -07001218 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001219 public int isLanguageAvailable(final Locale loc) {
1220 return runAction(new Action<Integer>() {
1221 @Override
1222 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001223 String language = null, country = null;
1224
1225 try {
1226 language = loc.getISO3Language();
1227 } catch (MissingResourceException e) {
1228 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1229 return LANG_NOT_SUPPORTED;
1230 }
1231
1232 try {
1233 country = loc.getISO3Country();
1234 } catch (MissingResourceException e) {
1235 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1236 return LANG_NOT_SUPPORTED;
1237 }
1238
1239 return service.isLanguageAvailable(language, country, loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001240 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001241 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -07001242 }
1243
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001244 /**
Charles Chend4989092009-06-26 15:32:46 -07001245 * Synthesizes the given text to a file using the specified parameters.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001246 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
1247 * requests and then returns. The synthesis might not have finished (or even started!) at the
1248 * time when this method returns. In order to reliably detect errors during synthesis,
1249 * we recommend setting an utterance progress listener (see
1250 * {@link #setOnUtteranceProgressListener}) and using the
1251 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001252 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001253 * @param text The text that should be synthesized. No longer than
1254 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001255 * @param params Parameters for the request. Can be null.
1256 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001257 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +01001258 * Engine specific parameters may be passed in but the parameter keys
1259 * must be prefixed by the name of the engine they are intended for. For example
1260 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
1261 * engine named "com.svox.pico" if it is being used.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001262 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001263 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -07001264 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001265 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001266 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001267 public int synthesizeToFile(final String text, final HashMap<String, String> params,
1268 final String filename) {
1269 return runAction(new Action<Integer>() {
1270 @Override
1271 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +00001272 ParcelFileDescriptor fileDescriptor;
1273 int returnValue;
1274 try {
1275 File file = new File(filename);
1276 if(file.exists() && !file.canWrite()) {
1277 Log.e(TAG, "Can't write to " + filename);
1278 return ERROR;
1279 }
1280 fileDescriptor = ParcelFileDescriptor.open(file,
1281 ParcelFileDescriptor.MODE_WRITE_ONLY |
1282 ParcelFileDescriptor.MODE_CREATE |
1283 ParcelFileDescriptor.MODE_TRUNCATE);
1284 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
1285 fileDescriptor, getParams(params));
1286 fileDescriptor.close();
1287 return returnValue;
1288 } catch (FileNotFoundException e) {
1289 Log.e(TAG, "Opening file " + filename + " failed", e);
1290 return ERROR;
1291 } catch (IOException e) {
1292 Log.e(TAG, "Closing file " + filename + " failed", e);
1293 return ERROR;
1294 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001295 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001296 }, ERROR, "synthesizeToFile");
1297 }
1298
1299 private Bundle getParams(HashMap<String, String> params) {
1300 if (params != null && !params.isEmpty()) {
1301 Bundle bundle = new Bundle(mParams);
1302 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
1303 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
1304 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
1305 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
Narayan Kamathb956f372011-05-16 16:51:44 +01001306
Narayan Kamath748af662011-10-31 14:20:01 +00001307 // Copy feature strings defined by the framework.
1308 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
Narayan Kamath6c07a202011-11-07 14:21:39 +00001309 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
Narayan Kamath748af662011-10-31 14:20:01 +00001310
Narayan Kamathb956f372011-05-16 16:51:44 +01001311 // Copy over all parameters that start with the name of the
1312 // engine that we are currently connected to. The engine is
1313 // free to interpret them as it chooses.
1314 if (!TextUtils.isEmpty(mCurrentEngine)) {
1315 for (Map.Entry<String, String> entry : params.entrySet()) {
1316 final String key = entry.getKey();
1317 if (key != null && key.startsWith(mCurrentEngine)) {
1318 bundle.putString(key, entry.getValue());
1319 }
1320 }
1321 }
1322
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001323 return bundle;
1324 } else {
1325 return mParams;
1326 }
1327 }
1328
1329 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
1330 String value = params.get(key);
1331 if (value != null) {
1332 bundle.putString(key, value);
1333 }
1334 }
1335
1336 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
1337 String valueString = params.get(key);
1338 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001339 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001340 int value = Integer.parseInt(valueString);
1341 bundle.putInt(key, value);
1342 } catch (NumberFormatException ex) {
1343 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001344 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001345 }
1346 }
1347
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001348 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
1349 String valueString = params.get(key);
1350 if (!TextUtils.isEmpty(valueString)) {
1351 try {
1352 float value = Float.parseFloat(valueString);
1353 bundle.putFloat(key, value);
1354 } catch (NumberFormatException ex) {
1355 // don't set the value in the bundle
1356 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -08001357 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -07001358 }
1359
Charles Chen78c9d0d2009-07-13 16:22:41 -07001360 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001361 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001362 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001363 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001364 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001365 * @return {@link #ERROR} or {@link #SUCCESS}.
Narayan Kamath754c72e2011-11-09 14:22:32 +00001366 *
1367 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1368 * instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001369 */
Narayan Kamath754c72e2011-11-09 14:22:32 +00001370 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001371 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001372 mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1373 return TextToSpeech.SUCCESS;
1374 }
1375
1376 /**
1377 * Sets the listener that will be notified of various events related to the
1378 * synthesis of a given utterance.
1379 *
1380 * See {@link UtteranceProgressListener} and
1381 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1382 *
1383 * @param listener the listener to use.
1384 * @return {@link #ERROR} or {@link #SUCCESS}
1385 */
1386 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1387 mUtteranceProgressListener = listener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001388 return TextToSpeech.SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001389 }
1390
Charles Chenb4fbe762009-11-18 16:34:32 -08001391 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001392 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001393 *
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001394 * @deprecated This doesn't inform callers when the TTS engine has been
1395 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
Narayan Kamathb9db1fb2011-07-14 15:30:36 +01001396 * can be used with the appropriate engine name. Also, there is no
1397 * guarantee that the engine specified will be loaded. If it isn't
1398 * installed or disabled, the user / system wide defaults will apply.
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001399 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001400 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001401 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001402 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001403 */
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001404 @Deprecated
Charles Chen60dd3602010-01-07 18:56:24 -08001405 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001406 mRequestedEngine = enginePackageName;
1407 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001408 }
1409
Charles Chendef71852010-03-25 19:59:50 -07001410 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001411 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001412 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001413 * @return Package name of the TTS engine that the user has chosen
1414 * as their default.
Charles Chendef71852010-03-25 19:59:50 -07001415 */
1416 public String getDefaultEngine() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001417 return mEnginesHelper.getDefaultEngine();
Charles Chendef71852010-03-25 19:59:50 -07001418 }
Charles Chen42229252010-03-29 18:30:30 -07001419
Charles Chen42229252010-03-29 18:30:30 -07001420 /**
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001421 * Checks whether the user's settings should override settings requested
1422 * by the calling application. As of the Ice cream sandwich release,
1423 * user settings never forcibly override the app's settings.
Charles Chen42229252010-03-29 18:30:30 -07001424 */
1425 public boolean areDefaultsEnforced() {
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001426 return false;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001427 }
1428
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001429 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001430 * Gets a list of all installed TTS engines.
1431 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001432 * @return A list of engine info objects. The list can be empty, but never {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001433 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001434 public List<EngineInfo> getEngines() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001435 return mEnginesHelper.getEngines();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001436 }
1437
1438 private class Connection implements ServiceConnection {
1439 private ITextToSpeechService mService;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001440
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001441 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask;
1442
1443 private boolean mEstablished;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001444
Narayan Kamatha57f2382011-10-04 17:20:09 +01001445 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
1446 @Override
Narayan Kamath754c72e2011-11-09 14:22:32 +00001447 public void onDone(String utteranceId) {
1448 UtteranceProgressListener listener = mUtteranceProgressListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001449 if (listener != null) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001450 listener.onDone(utteranceId);
1451 }
1452 }
1453
1454 @Override
1455 public void onError(String utteranceId) {
1456 UtteranceProgressListener listener = mUtteranceProgressListener;
1457 if (listener != null) {
1458 listener.onError(utteranceId);
1459 }
1460 }
1461
1462 @Override
1463 public void onStart(String utteranceId) {
1464 UtteranceProgressListener listener = mUtteranceProgressListener;
1465 if (listener != null) {
1466 listener.onStart(utteranceId);
Narayan Kamatha57f2382011-10-04 17:20:09 +01001467 }
1468 }
1469 };
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001470
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001471 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001472 private final ComponentName mName;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001473
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001474 public SetupConnectionAsyncTask(ComponentName name) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001475 mName = name;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001476 }
1477
1478 @Override
1479 protected Integer doInBackground(Void... params) {
1480 synchronized(mStartLock) {
1481 if (isCancelled()) {
1482 return null;
1483 }
1484
1485 try {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001486 mService.setCallback(getCallerIdentity(), mCallback);
1487 String[] defaultLanguage = mService.getClientDefaultLanguage();
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001488
1489 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]);
1490 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]);
1491 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]);
1492
1493 Log.i(TAG, "Set up connection to " + mName);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001494 return SUCCESS;
1495 } catch (RemoteException re) {
1496 Log.e(TAG, "Error connecting to service, setCallback() failed");
1497 return ERROR;
1498 }
1499 }
1500 }
1501
1502 @Override
1503 protected void onPostExecute(Integer result) {
1504 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001505 if (mOnSetupConnectionAsyncTask == this) {
1506 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001507 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001508 mEstablished = true;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001509 dispatchOnInit(result);
1510 }
1511 }
1512 }
1513
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001514 @Override
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001515 public void onServiceConnected(ComponentName name, IBinder service) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001516 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001517 mConnectingServiceConnection = null;
1518
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001519 Log.i(TAG, "Connected to " + name);
1520
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001521 if (mOnSetupConnectionAsyncTask != null) {
1522 mOnSetupConnectionAsyncTask.cancel(false);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001523 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001524
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001525 mService = ITextToSpeechService.Stub.asInterface(service);
1526 mServiceConnection = Connection.this;
1527
1528 mEstablished = false;
1529 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name);
1530 mOnSetupConnectionAsyncTask.execute();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001531 }
1532 }
1533
Narayan Kamath492b7f02011-11-29 17:02:06 +00001534 public IBinder getCallerIdentity() {
1535 return mCallback;
1536 }
1537
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001538 /**
1539 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
1540 *
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001541 * @return true if we cancel mOnSetupConnectionAsyncTask in progress.
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001542 */
1543 private boolean clearServiceConnection() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001544 synchronized(mStartLock) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001545 boolean result = false;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001546 if (mOnSetupConnectionAsyncTask != null) {
1547 result = mOnSetupConnectionAsyncTask.cancel(false);
1548 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001549 }
1550
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001551 mService = null;
1552 // If this is the active connection, clear it
1553 if (mServiceConnection == this) {
1554 mServiceConnection = null;
1555 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001556 return result;
1557 }
1558 }
1559
1560 @Override
1561 public void onServiceDisconnected(ComponentName name) {
1562 Log.i(TAG, "Asked to disconnect from " + name);
1563 if (clearServiceConnection()) {
1564 /* We need to protect against a rare case where engine
1565 * dies just after successful connection - and we process onServiceDisconnected
1566 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
1567 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
1568 * with ERROR as argument.
1569 */
1570 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001571 }
1572 }
1573
1574 public void disconnect() {
1575 mContext.unbindService(this);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001576 clearServiceConnection();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001577 }
1578
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001579 public boolean isEstablished() {
1580 return mService != null && mEstablished;
1581 }
1582
1583 public <R> R runAction(Action<R> action, R errorResult, String method,
1584 boolean reconnect, boolean onlyEstablishedConnection) {
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001585 synchronized (mStartLock) {
1586 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001587 if (mService == null) {
1588 Log.w(TAG, method + " failed: not connected to TTS engine");
1589 return errorResult;
1590 }
Fergus Henderson1c2df382013-01-25 14:59:59 +00001591 if (onlyEstablishedConnection && !isEstablished()) {
1592 Log.w(TAG, method + " failed: TTS engine connection not fully set up");
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001593 return errorResult;
1594 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001595 return action.run(mService);
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001596 } catch (RemoteException ex) {
1597 Log.e(TAG, method + " failed", ex);
1598 if (reconnect) {
1599 disconnect();
1600 initTts();
1601 }
1602 return errorResult;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001603 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001604 }
1605 }
1606 }
1607
1608 private interface Action<R> {
1609 R run(ITextToSpeechService service) throws RemoteException;
1610 }
1611
1612 /**
1613 * Information about an installed text-to-speech engine.
1614 *
1615 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001616 */
1617 public static class EngineInfo {
1618 /**
1619 * Engine package name..
1620 */
1621 public String name;
1622 /**
1623 * Localized label for the engine.
1624 */
1625 public String label;
1626 /**
1627 * Icon for the engine.
1628 */
1629 public int icon;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001630 /**
1631 * Whether this engine is a part of the system
1632 * image.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001633 *
1634 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001635 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001636 public boolean system;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001637 /**
1638 * The priority the engine declares for the the intent filter
1639 * {@code android.intent.action.TTS_SERVICE}
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001640 *
1641 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001642 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001643 public int priority;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001644
1645 @Override
1646 public String toString() {
1647 return "EngineInfo{name=" + name + "}";
1648 }
1649
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001650 }
Narayan Kamath22302fb2011-06-10 14:22:07 +01001651
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001652 /**
1653 * Limit of length of input string passed to speak and synthesizeToFile.
1654 *
1655 * @see #speak
1656 * @see #synthesizeToFile
1657 */
1658 public static int getMaxSpeechInputLength() {
1659 return 4000;
1660 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001661}