blob: b8083632bc4fcba716c9ec88b721180fce86ce35 [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 {
996 String[] features = service.getFeaturesForLanguage(
997 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant());
998 if (features != null) {
999 final Set<String> featureSet = new HashSet<String>();
1000 Collections.addAll(featureSet, features);
1001 return featureSet;
1002 }
1003 return null;
1004 }
1005 }, null, "getFeatures");
1006 }
1007
1008 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +01001009 * Checks whether the TTS engine is busy speaking. Note that a speech item is
1010 * considered complete once it's audio data has been sent to the audio mixer, or
1011 * written to a file. There might be a finite lag between this point, and when
1012 * the audio hardware completes playback.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001013 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001014 * @return {@code true} if the TTS engine is speaking.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001015 */
1016 public boolean isSpeaking() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001017 return runAction(new Action<Boolean>() {
1018 @Override
1019 public Boolean run(ITextToSpeechService service) throws RemoteException {
1020 return service.isSpeaking();
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001021 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001022 }, false, "isSpeaking");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001023 }
1024
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001025 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001026 * Interrupts the current utterance (whether played or rendered to file) and discards other
1027 * utterances in the queue.
Charles Chen5c22f512009-06-29 15:52:47 -07001028 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001029 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001030 */
Charles Chen5c22f512009-06-29 15:52:47 -07001031 public int stop() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001032 return runAction(new Action<Integer>() {
1033 @Override
1034 public Integer run(ITextToSpeechService service) throws RemoteException {
Narayan Kamath492b7f02011-11-29 17:02:06 +00001035 return service.stop(getCallerIdentity());
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001036 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001037 }, ERROR, "stop");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001038 }
1039
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001040 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001041 * Sets the speech rate.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001042 *
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001043 * This has no effect on any pre-recorded speech.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001044 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001045 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
1046 * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
1047 * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
Charles Chen5c22f512009-06-29 15:52:47 -07001048 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001049 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001050 */
Charles Chen5c22f512009-06-29 15:52:47 -07001051 public int setSpeechRate(float speechRate) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001052 if (speechRate > 0.0f) {
1053 int intRate = (int)(speechRate * 100);
1054 if (intRate > 0) {
1055 synchronized (mStartLock) {
1056 mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
Jean-Michel Trivi679d7282009-06-16 15:36:28 -07001057 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001058 return SUCCESS;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001059 }
1060 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001061 return ERROR;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001062 }
1063
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001064 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001065 * Sets the speech pitch for the TextToSpeech engine.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001066 *
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001067 * This has no effect on any pre-recorded speech.
1068 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001069 * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001070 * lower values lower the tone of the synthesized voice,
1071 * greater values increase it.
Charles Chen5c22f512009-06-29 15:52:47 -07001072 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001073 * @return {@link #ERROR} or {@link #SUCCESS}.
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001074 */
Charles Chen5c22f512009-06-29 15:52:47 -07001075 public int setPitch(float pitch) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001076 if (pitch > 0.0f) {
1077 int intPitch = (int)(pitch * 100);
1078 if (intPitch > 0) {
1079 synchronized (mStartLock) {
1080 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001081 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001082 return SUCCESS;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001083 }
1084 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001085 return ERROR;
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001086 }
1087
Jean-Michel Trivi2ea53492009-06-23 13:44:40 -07001088 /**
Narayan Kamathbd2492e2011-06-27 18:35:47 +01001089 * @return the engine currently in use by this TextToSpeech instance.
1090 * @hide
1091 */
1092 public String getCurrentEngine() {
1093 return mCurrentEngine;
1094 }
1095
1096 /**
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001097 * Returns a Locale instance describing the language currently being used as the default
1098 * Text-to-speech language.
1099 *
1100 * @return language, country (if any) and variant (if any) used by the client stored in a
1101 * Locale instance, or {@code null} on error.
1102 */
1103 public Locale getDefaultLanguage() {
1104 return runAction(new Action<Locale>() {
1105 @Override
1106 public Locale run(ITextToSpeechService service) throws RemoteException {
1107 String[] defaultLanguage = service.getClientDefaultLanguage();
1108
1109 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]);
1110 }
1111 }, null, "getDefaultLanguage");
1112 }
1113
1114 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001115 * Sets the text-to-speech language.
1116 * The TTS engine will try to use the closest match to the specified
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001117 * language as represented by the Locale, but there is no guarantee that the exact same Locale
1118 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1119 * before choosing the language to use for the next utterances.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001120 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001121 * @param loc The locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001122 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001123 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001124 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1125 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001126 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001127 public int setLanguage(final Locale loc) {
1128 return runAction(new Action<Integer>() {
1129 @Override
1130 public Integer run(ITextToSpeechService service) throws RemoteException {
1131 if (loc == null) {
1132 return LANG_NOT_SUPPORTED;
1133 }
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001134 String language = null, country = null;
1135 try {
1136 language = loc.getISO3Language();
1137 } catch (MissingResourceException e) {
1138 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1139 return LANG_NOT_SUPPORTED;
1140 }
1141
1142 try {
1143 country = loc.getISO3Country();
1144 } catch (MissingResourceException e) {
1145 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1146 return LANG_NOT_SUPPORTED;
1147 }
1148
Charles Chen1a2712c2010-04-01 17:16:28 -07001149 String variant = loc.getVariant();
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001150
Charles Chen1a2712c2010-04-01 17:16:28 -07001151 // Check if the language, country, variant are available, and cache
1152 // the available parts.
1153 // Note that the language is not actually set here, instead it is cached so it
1154 // will be associated with all upcoming utterances.
Przemyslaw Szczepaniak13896b72012-11-09 15:18:16 +00001155
1156 int result = service.loadLanguage(getCallerIdentity(), language, country, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001157 if (result >= LANG_AVAILABLE){
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001158 if (result < LANG_COUNTRY_VAR_AVAILABLE) {
1159 variant = "";
1160 if (result < LANG_COUNTRY_AVAILABLE) {
1161 country = "";
1162 }
Charles Chen1a2712c2010-04-01 17:16:28 -07001163 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001164 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
1165 mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
1166 mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
Charles Chen1a2712c2010-04-01 17:16:28 -07001167 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001168 return result;
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001169 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001170 }, LANG_NOT_SUPPORTED, "setLanguage");
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001171 }
1172
Charles Chenaaf842e2009-06-25 11:59:29 -07001173 /**
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001174 * Returns a Locale instance describing the language currently being used for synthesis
1175 * requests sent to the TextToSpeech engine.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001176 *
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001177 * In Android 4.2 and before (API <= 17) this function returns the language that is currently
1178 * being used by the TTS engine. That is the last language set by this or any other
1179 * client by a {@link TextToSpeech#setLanguage} call to the same engine.
1180 *
1181 * In Android versions after 4.2 this function returns the language that is currently being
1182 * used for the synthesis requests sent from this client. That is the last language set
1183 * by a {@link TextToSpeech#setLanguage} call on this instance.
1184 *
1185 * @return language, country (if any) and variant (if any) used by the client stored in a
1186 * Locale instance, or {@code null} on error.
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001187 */
1188 public Locale getLanguage() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001189 return runAction(new Action<Locale>() {
1190 @Override
Przemyslaw Szczepaniak228323e2012-11-12 11:04:56 +00001191 public Locale run(ITextToSpeechService service) {
1192 /* No service call, but we're accessing mParams, hence need for
1193 wrapping it as an Action instance */
1194 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, "");
1195 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, "");
1196 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, "");
1197 return new Locale(lang, country, variant);
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001198 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001199 }, null, "getLanguage");
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001200 }
1201
1202 /**
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001203 * Checks if the specified language as represented by the Locale is available and supported.
Charles Chenaaf842e2009-06-25 11:59:29 -07001204 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001205 * @param loc The Locale describing the language to be used.
Charles Chen5c22f512009-06-29 15:52:47 -07001206 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001207 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
Jean-Michel Trivied065782009-07-28 14:31:48 -07001208 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1209 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
Charles Chenaaf842e2009-06-25 11:59:29 -07001210 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001211 public int isLanguageAvailable(final Locale loc) {
1212 return runAction(new Action<Integer>() {
1213 @Override
1214 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniakd0b92792013-05-08 15:26:15 +01001215 String language = null, country = null;
1216
1217 try {
1218 language = loc.getISO3Language();
1219 } catch (MissingResourceException e) {
1220 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e);
1221 return LANG_NOT_SUPPORTED;
1222 }
1223
1224 try {
1225 country = loc.getISO3Country();
1226 } catch (MissingResourceException e) {
1227 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e);
1228 return LANG_NOT_SUPPORTED;
1229 }
1230
1231 return service.isLanguageAvailable(language, country, loc.getVariant());
Jean-Michel Trividdb0a802009-06-29 16:38:47 -07001232 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001233 }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
Charles Chenaaf842e2009-06-25 11:59:29 -07001234 }
1235
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001236 /**
Charles Chend4989092009-06-26 15:32:46 -07001237 * Synthesizes the given text to a file using the specified parameters.
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001238 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
1239 * requests and then returns. The synthesis might not have finished (or even started!) at the
1240 * time when this method returns. In order to reliably detect errors during synthesis,
1241 * we recommend setting an utterance progress listener (see
1242 * {@link #setOnUtteranceProgressListener}) and using the
1243 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001244 *
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001245 * @param text The text that should be synthesized. No longer than
1246 * {@link #getMaxSpeechInputLength()} characters.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001247 * @param params Parameters for the request. Can be null.
1248 * Supported parameter names:
Jean-Michel Trivia9b417e2009-09-11 18:34:02 -07001249 * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
Narayan Kamathb956f372011-05-16 16:51:44 +01001250 * Engine specific parameters may be passed in but the parameter keys
1251 * must be prefixed by the name of the engine they are intended for. For example
1252 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
1253 * engine named "com.svox.pico" if it is being used.
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001254 * @param filename Absolute file filename to write the generated audio data to.It should be
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001255 * something like "/sdcard/myappsounds/mysound.wav".
Charles Chen5c22f512009-06-29 15:52:47 -07001256 *
Przemyslaw Szczepaniak442f1782012-09-26 14:21:26 +01001257 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001258 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001259 public int synthesizeToFile(final String text, final HashMap<String, String> params,
1260 final String filename) {
1261 return runAction(new Action<Integer>() {
1262 @Override
1263 public Integer run(ITextToSpeechService service) throws RemoteException {
Przemyslaw Szczepaniak5acb33a2013-02-08 16:36:25 +00001264 ParcelFileDescriptor fileDescriptor;
1265 int returnValue;
1266 try {
1267 File file = new File(filename);
1268 if(file.exists() && !file.canWrite()) {
1269 Log.e(TAG, "Can't write to " + filename);
1270 return ERROR;
1271 }
1272 fileDescriptor = ParcelFileDescriptor.open(file,
1273 ParcelFileDescriptor.MODE_WRITE_ONLY |
1274 ParcelFileDescriptor.MODE_CREATE |
1275 ParcelFileDescriptor.MODE_TRUNCATE);
1276 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
1277 fileDescriptor, getParams(params));
1278 fileDescriptor.close();
1279 return returnValue;
1280 } catch (FileNotFoundException e) {
1281 Log.e(TAG, "Opening file " + filename + " failed", e);
1282 return ERROR;
1283 } catch (IOException e) {
1284 Log.e(TAG, "Closing file " + filename + " failed", e);
1285 return ERROR;
1286 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001287 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001288 }, ERROR, "synthesizeToFile");
1289 }
1290
1291 private Bundle getParams(HashMap<String, String> params) {
1292 if (params != null && !params.isEmpty()) {
1293 Bundle bundle = new Bundle(mParams);
1294 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
1295 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
1296 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
1297 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
Narayan Kamathb956f372011-05-16 16:51:44 +01001298
Narayan Kamath748af662011-10-31 14:20:01 +00001299 // Copy feature strings defined by the framework.
1300 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
Narayan Kamath6c07a202011-11-07 14:21:39 +00001301 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
Narayan Kamath748af662011-10-31 14:20:01 +00001302
Narayan Kamathb956f372011-05-16 16:51:44 +01001303 // Copy over all parameters that start with the name of the
1304 // engine that we are currently connected to. The engine is
1305 // free to interpret them as it chooses.
1306 if (!TextUtils.isEmpty(mCurrentEngine)) {
1307 for (Map.Entry<String, String> entry : params.entrySet()) {
1308 final String key = entry.getKey();
1309 if (key != null && key.startsWith(mCurrentEngine)) {
1310 bundle.putString(key, entry.getValue());
1311 }
1312 }
1313 }
1314
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001315 return bundle;
1316 } else {
1317 return mParams;
1318 }
1319 }
1320
1321 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
1322 String value = params.get(key);
1323 if (value != null) {
1324 bundle.putString(key, value);
1325 }
1326 }
1327
1328 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
1329 String valueString = params.get(key);
1330 if (!TextUtils.isEmpty(valueString)) {
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001331 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001332 int value = Integer.parseInt(valueString);
1333 bundle.putInt(key, value);
1334 } catch (NumberFormatException ex) {
1335 // don't set the value in the bundle
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001336 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001337 }
1338 }
1339
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001340 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
1341 String valueString = params.get(key);
1342 if (!TextUtils.isEmpty(valueString)) {
1343 try {
1344 float value = Float.parseFloat(valueString);
1345 bundle.putFloat(key, value);
1346 } catch (NumberFormatException ex) {
1347 // don't set the value in the bundle
1348 }
Jean-Michel Trivi9d2d26a2011-01-05 16:08:21 -08001349 }
Jean-Michel Trivia9810132009-07-10 12:08:59 -07001350 }
1351
Charles Chen78c9d0d2009-07-13 16:22:41 -07001352 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001353 * Sets the listener that will be notified when synthesis of an utterance completes.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001354 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001355 * @param listener The listener to use.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001356 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001357 * @return {@link #ERROR} or {@link #SUCCESS}.
Narayan Kamath754c72e2011-11-09 14:22:32 +00001358 *
1359 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1360 * instead.
Charles Chen78c9d0d2009-07-13 16:22:41 -07001361 */
Narayan Kamath754c72e2011-11-09 14:22:32 +00001362 @Deprecated
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001363 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001364 mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1365 return TextToSpeech.SUCCESS;
1366 }
1367
1368 /**
1369 * Sets the listener that will be notified of various events related to the
1370 * synthesis of a given utterance.
1371 *
1372 * See {@link UtteranceProgressListener} and
1373 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1374 *
1375 * @param listener the listener to use.
1376 * @return {@link #ERROR} or {@link #SUCCESS}
1377 */
1378 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1379 mUtteranceProgressListener = listener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001380 return TextToSpeech.SUCCESS;
Charles Chen78c9d0d2009-07-13 16:22:41 -07001381 }
1382
Charles Chenb4fbe762009-11-18 16:34:32 -08001383 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001384 * Sets the TTS engine to use.
Charles Chenb4fbe762009-11-18 16:34:32 -08001385 *
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001386 * @deprecated This doesn't inform callers when the TTS engine has been
1387 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
Narayan Kamathb9db1fb2011-07-14 15:30:36 +01001388 * can be used with the appropriate engine name. Also, there is no
1389 * guarantee that the engine specified will be loaded. If it isn't
1390 * installed or disabled, the user / system wide defaults will apply.
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001391 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001392 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
Charles Chenb4fbe762009-11-18 16:34:32 -08001393 *
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001394 * @return {@link #ERROR} or {@link #SUCCESS}.
Charles Chenb4fbe762009-11-18 16:34:32 -08001395 */
Narayan Kamath3f0363b2011-06-10 09:57:32 +01001396 @Deprecated
Charles Chen60dd3602010-01-07 18:56:24 -08001397 public int setEngineByPackageName(String enginePackageName) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001398 mRequestedEngine = enginePackageName;
1399 return initTts();
Charles Chenb4fbe762009-11-18 16:34:32 -08001400 }
1401
Charles Chendef71852010-03-25 19:59:50 -07001402 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001403 * Gets the package name of the default speech synthesis engine.
Charles Chendef71852010-03-25 19:59:50 -07001404 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001405 * @return Package name of the TTS engine that the user has chosen
1406 * as their default.
Charles Chendef71852010-03-25 19:59:50 -07001407 */
1408 public String getDefaultEngine() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001409 return mEnginesHelper.getDefaultEngine();
Charles Chendef71852010-03-25 19:59:50 -07001410 }
Charles Chen42229252010-03-29 18:30:30 -07001411
Charles Chen42229252010-03-29 18:30:30 -07001412 /**
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001413 * Checks whether the user's settings should override settings requested
1414 * by the calling application. As of the Ice cream sandwich release,
1415 * user settings never forcibly override the app's settings.
Charles Chen42229252010-03-29 18:30:30 -07001416 */
1417 public boolean areDefaultsEnforced() {
Narayan Kamathc3edf2a2011-06-15 12:35:06 +01001418 return false;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001419 }
1420
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001421 /**
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001422 * Gets a list of all installed TTS engines.
1423 *
Narayan Kamath22302fb2011-06-10 14:22:07 +01001424 * @return A list of engine info objects. The list can be empty, but never {@code null}.
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001425 */
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001426 public List<EngineInfo> getEngines() {
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001427 return mEnginesHelper.getEngines();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001428 }
1429
1430 private class Connection implements ServiceConnection {
1431 private ITextToSpeechService mService;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001432
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001433 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask;
1434
1435 private boolean mEstablished;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001436
Narayan Kamatha57f2382011-10-04 17:20:09 +01001437 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
1438 @Override
Narayan Kamath754c72e2011-11-09 14:22:32 +00001439 public void onDone(String utteranceId) {
1440 UtteranceProgressListener listener = mUtteranceProgressListener;
Narayan Kamatha57f2382011-10-04 17:20:09 +01001441 if (listener != null) {
Narayan Kamath754c72e2011-11-09 14:22:32 +00001442 listener.onDone(utteranceId);
1443 }
1444 }
1445
1446 @Override
1447 public void onError(String utteranceId) {
1448 UtteranceProgressListener listener = mUtteranceProgressListener;
1449 if (listener != null) {
1450 listener.onError(utteranceId);
1451 }
1452 }
1453
1454 @Override
1455 public void onStart(String utteranceId) {
1456 UtteranceProgressListener listener = mUtteranceProgressListener;
1457 if (listener != null) {
1458 listener.onStart(utteranceId);
Narayan Kamatha57f2382011-10-04 17:20:09 +01001459 }
1460 }
1461 };
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001462
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001463 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001464 private final ComponentName mName;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001465
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001466 public SetupConnectionAsyncTask(ComponentName name) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001467 mName = name;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001468 }
1469
1470 @Override
1471 protected Integer doInBackground(Void... params) {
1472 synchronized(mStartLock) {
1473 if (isCancelled()) {
1474 return null;
1475 }
1476
1477 try {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001478 mService.setCallback(getCallerIdentity(), mCallback);
1479 String[] defaultLanguage = mService.getClientDefaultLanguage();
Przemyslaw Szczepaniakb4653372012-12-04 14:57:58 +00001480
1481 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]);
1482 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]);
1483 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]);
1484
1485 Log.i(TAG, "Set up connection to " + mName);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001486 return SUCCESS;
1487 } catch (RemoteException re) {
1488 Log.e(TAG, "Error connecting to service, setCallback() failed");
1489 return ERROR;
1490 }
1491 }
1492 }
1493
1494 @Override
1495 protected void onPostExecute(Integer result) {
1496 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001497 if (mOnSetupConnectionAsyncTask == this) {
1498 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001499 }
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001500 mEstablished = true;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001501 dispatchOnInit(result);
1502 }
1503 }
1504 }
1505
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001506 @Override
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001507 public void onServiceConnected(ComponentName name, IBinder service) {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001508 synchronized(mStartLock) {
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001509 mConnectingServiceConnection = null;
1510
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001511 Log.i(TAG, "Connected to " + name);
1512
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001513 if (mOnSetupConnectionAsyncTask != null) {
1514 mOnSetupConnectionAsyncTask.cancel(false);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001515 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001516
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001517 mService = ITextToSpeechService.Stub.asInterface(service);
1518 mServiceConnection = Connection.this;
1519
1520 mEstablished = false;
1521 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name);
1522 mOnSetupConnectionAsyncTask.execute();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001523 }
1524 }
1525
Narayan Kamath492b7f02011-11-29 17:02:06 +00001526 public IBinder getCallerIdentity() {
1527 return mCallback;
1528 }
1529
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001530 /**
1531 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
1532 *
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001533 * @return true if we cancel mOnSetupConnectionAsyncTask in progress.
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001534 */
1535 private boolean clearServiceConnection() {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001536 synchronized(mStartLock) {
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001537 boolean result = false;
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001538 if (mOnSetupConnectionAsyncTask != null) {
1539 result = mOnSetupConnectionAsyncTask.cancel(false);
1540 mOnSetupConnectionAsyncTask = null;
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001541 }
1542
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001543 mService = null;
1544 // If this is the active connection, clear it
1545 if (mServiceConnection == this) {
1546 mServiceConnection = null;
1547 }
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001548 return result;
1549 }
1550 }
1551
1552 @Override
1553 public void onServiceDisconnected(ComponentName name) {
1554 Log.i(TAG, "Asked to disconnect from " + name);
1555 if (clearServiceConnection()) {
1556 /* We need to protect against a rare case where engine
1557 * dies just after successful connection - and we process onServiceDisconnected
1558 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
1559 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
1560 * with ERROR as argument.
1561 */
1562 dispatchOnInit(ERROR);
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001563 }
1564 }
1565
1566 public void disconnect() {
1567 mContext.unbindService(this);
Przemyslaw Szczepaniak8f3957c2012-11-07 14:03:53 +00001568 clearServiceConnection();
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001569 }
1570
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001571 public boolean isEstablished() {
1572 return mService != null && mEstablished;
1573 }
1574
1575 public <R> R runAction(Action<R> action, R errorResult, String method,
1576 boolean reconnect, boolean onlyEstablishedConnection) {
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001577 synchronized (mStartLock) {
1578 try {
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001579 if (mService == null) {
1580 Log.w(TAG, method + " failed: not connected to TTS engine");
1581 return errorResult;
1582 }
Fergus Henderson1c2df382013-01-25 14:59:59 +00001583 if (onlyEstablishedConnection && !isEstablished()) {
1584 Log.w(TAG, method + " failed: TTS engine connection not fully set up");
Przemyslaw Szczepaniak9c4012b2013-01-16 17:24:44 +00001585 return errorResult;
1586 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001587 return action.run(mService);
Przemyslaw Szczepaniak091d56c2012-08-16 16:34:54 +01001588 } catch (RemoteException ex) {
1589 Log.e(TAG, method + " failed", ex);
1590 if (reconnect) {
1591 disconnect();
1592 initTts();
1593 }
1594 return errorResult;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001595 }
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001596 }
1597 }
1598 }
1599
1600 private interface Action<R> {
1601 R run(ITextToSpeechService service) throws RemoteException;
1602 }
1603
1604 /**
1605 * Information about an installed text-to-speech engine.
1606 *
1607 * @see TextToSpeech#getEngines
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001608 */
1609 public static class EngineInfo {
1610 /**
1611 * Engine package name..
1612 */
1613 public String name;
1614 /**
1615 * Localized label for the engine.
1616 */
1617 public String label;
1618 /**
1619 * Icon for the engine.
1620 */
1621 public int icon;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001622 /**
1623 * Whether this engine is a part of the system
1624 * image.
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001625 *
1626 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001627 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001628 public boolean system;
Narayan Kamath22302fb2011-06-10 14:22:07 +01001629 /**
1630 * The priority the engine declares for the the intent filter
1631 * {@code android.intent.action.TTS_SERVICE}
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001632 *
1633 * @hide
Narayan Kamath22302fb2011-06-10 14:22:07 +01001634 */
Narayan Kamathd3ee2fa2011-06-10 16:19:52 +01001635 public int priority;
Bjorn Bringert50e657b2011-03-08 16:00:40 +00001636
1637 @Override
1638 public String toString() {
1639 return "EngineInfo{name=" + name + "}";
1640 }
1641
Bjorn Bringert2cad2cc2011-03-08 11:53:12 +00001642 }
Narayan Kamath22302fb2011-06-10 14:22:07 +01001643
Przemyslaw Szczepaniak2d940bc2012-11-19 12:22:59 +00001644 /**
1645 * Limit of length of input string passed to speak and synthesizeToFile.
1646 *
1647 * @see #speak
1648 * @see #synthesizeToFile
1649 */
1650 public static int getMaxSpeechInputLength() {
1651 return 4000;
1652 }
Jean-Michel Trivie74d5072009-05-26 10:43:08 -07001653}