AI2 Component  (Version nb184)
TextToSpeech.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2012 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.runtime;
8 
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.List;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.MissingResourceException;
15 
16 import android.media.AudioManager;
17 import android.util.Log;
18 
36 
54 // TODO(hal): This language and country code method using strings as abbreviations was
55 // deprecated in API level 21.
56 @DesignerComponent(version = YaVersion.TEXTTOSPEECH_COMPONENT_VERSION,
57 description = "The TestToSpeech component speaks a given text aloud. You can set " +
58  "the pitch and the rate of speech. " +
59  "<p>You can also set a language by supplying a language code. This changes the pronunciation " +
60  "of words, not the actual language spoken. For example, setting the language to French " +
61  "and speaking English text will sound like someone speaking English (en) with a French accent.</p> " +
62  "<p>You can also specify a country by supplying a country code. This can affect the " +
63  "pronunciation. For example, British English (GBR) will sound different from US English " +
64  "(USA). Not every country code will affect every language.</p> " +
65  "<p>The languages and countries available depend on the particular device, and can be listed " +
66  "with the AvailableLanguages and AvailableCountries properties.</p>",
67  category = ComponentCategory.MEDIA,
68  nonVisible = true,
69  iconName = "images/textToSpeech.png")
70 @SimpleObject
72 implements Component, OnStopListener, OnResumeListener, OnDestroyListener /*, ActivityResultListener */{
73 
74  private static final Map<String, Locale> iso3LanguageToLocaleMap = Maps.newHashMap();
75  private static final Map<String, Locale> iso3CountryToLocaleMap = Maps.newHashMap();
76  private float pitch = 1.0f;
77  private float speechRate = 1.0f;
78  private static final String LOG_TAG = "TextToSpeech";
79 
80  static {
81  initLocaleMaps();
82  }
83 
84  // List of available languages for the TTS
85  private ArrayList<String> languageList;
86 
87  // List of available ISO3 country codes for the TTS
88  // the might be more countries than this, but we should update TTS control
89  // to use voices and clarify the use of countries with TTS
90  private ArrayList<String> countryList;
91 
92  private YailList allLanguages;
93  private YailList allCountries;
94 
95  private boolean result;
96  private String language;
97  private String country;
98 
99  private final ITextToSpeech tts;
100  private String iso2Language;
101  private String iso2Country;
102 
103  private boolean isTtsPrepared;
104 
105  private static void initLocaleMaps() {
106  Locale[] locales = Locale.getAvailableLocales();
107  for (Locale locale : locales) {
108  try {
109  String iso3Country = locale.getISO3Country();
110  if (iso3Country.length() > 0) {
111  iso3CountryToLocaleMap.put(iso3Country, locale);
112  }
113  } catch (MissingResourceException e) {
114  // ignore;
115  }
116  try {
117  String iso3Language = locale.getISO3Language();
118  if (iso3Language.length() > 0) {
119  iso3LanguageToLocaleMap.put(iso3Language, locale);
120  }
121  } catch (MissingResourceException e) {
122  // ignore;
123  }
124  }
125  }
126 
132  public TextToSpeech(ComponentContainer container) {
133  super(container.$form());
134  result = false;
137  /* Determine which TTS library to use */
138  boolean useExternalLibrary = SdkLevel.getLevel() < SdkLevel.LEVEL_DONUT;
139  Log.v(LOG_TAG, "Using " + (useExternalLibrary ? "external" : "internal") + " TTS library.");
141  @Override
142  public void onSuccess() {
143  result = true;
144  AfterSpeaking(true);
145  }
146 
147  @Override
148  public void onFailure() {
149  result = false;
150  AfterSpeaking(false);
151  }
152  };
153  tts = useExternalLibrary ? new ExternalTextToSpeech(container, callback)
154  : new InternalTextToSpeech(container.$context(), callback);
155  // Set up listeners
156  form.registerForOnStop(this);
159  // Make volume buttons control media, not ringer.
160  form.setVolumeControlStream(AudioManager.STREAM_MUSIC);
161 
162  isTtsPrepared = false;
163  languageList = new ArrayList<String>();
164  countryList = new ArrayList<String>();
165  allLanguages = YailList.makeList(languageList);
166  allCountries = YailList.makeList(countryList);
167 
168  }
169 
175  category = PropertyCategory.BEHAVIOR)
176  public boolean Result() {
177  return result;
178  }
179 
191  description = "Sets the language for TextToSpeech. This changes the way that words are " +
192  "pronounced, not the actual language that is spoken. For example setting the language to " +
193  "and speaking English text with sound like someone speaking English with a Frernch accent.")
194  public void Language(String language) {
195  Locale locale;
196  switch (language.length()) {
197  case 3:
198  locale = iso3LanguageToLocale(language);
199  this.language = locale.getISO3Language();
200  break;
201  case 2:
202  locale = new Locale(language);
203  this.language = locale.getLanguage();
204  break;
205  default:
206  locale = Locale.getDefault();
207  this.language = locale.getLanguage();
208  break;
209  }
210  iso2Language = locale.getLanguage();
211  }
212 
213  private static Locale iso3LanguageToLocale(String iso3Language) {
214  Locale mappedLocale = iso3LanguageToLocaleMap.get(iso3Language);
215  if (mappedLocale == null) {
216  // Language codes should be lower case, but maybe the user doesn't know that.
217  mappedLocale = iso3LanguageToLocaleMap.get(iso3Language.toLowerCase(Locale.ENGLISH));
218  }
219  return mappedLocale == null ? Locale.getDefault() : mappedLocale;
220  }
221 
232  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT, defaultValue = "1.0")
233  @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Sets the Pitch for " +
234  "TextToSpeech The values should " +
235  "be between 0 and 2 where lower values lower the tone of synthesized voice and greater values " +
236  "raise it.")
237  public void Pitch(float pitch) {
238  if (pitch < 0 || pitch > 2) {
239  Log.i(LOG_TAG, "Pitch value should be between 0 and 2, but user specified: " + pitch);
240  return;
241  }
242 
243  this.pitch = pitch;
244 
245  /* Lowest pitch value should be > 0. If 0, we just set to .1f
246  * Rather than having user specify .1, we just check and if 0, we set to .1
247  */
248  tts.setPitch(pitch==0?.1f:pitch);
249  }
250 
255  @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Returns current value of Pitch")
256  public float Pitch() {
257  return this.pitch;
258  }
259 
272  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT, defaultValue = "1.0")
273  @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Sets the SpeechRate for TextToSpeech. " +
274  "The values should be between 0 and 2 where lower values slow down the pitch and greater values " +
275  "accelerate it.")
276  public void SpeechRate(float speechRate) {
277  if (speechRate < 0 || speechRate > 2) {
278  Log.i(LOG_TAG, "speechRate value should be between 0 and 2, but user specified: " + speechRate);
279  return;
280  }
281 
282  this.speechRate = speechRate;
283 
284  /* Lowest value should be > 0. If 0, we just set to .1f
285  * Rather than having user specify .1, we just check and if 0, we set to .1
286  */
287  tts.setSpeechRate(speechRate == 0 ? .1f : speechRate);
288  }
289 
294  @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Returns current value of SpeechRate")
295  public float SpeechRate() {
296  return this.speechRate;
297  }
298 
307  public String Language() {
308  return language;
309  }
310 
321  @SimpleProperty(description = "Country code to use for speech generation. This can affect the " +
322  "pronounciation. For example, British English (GBR) will sound different from US English " +
323  "(USA). Not every country code will affect every language.",
324  category = PropertyCategory.BEHAVIOR)
325  public void Country(String country) {
326  Locale locale;
327  switch (country.length()) {
328  case 3:
329  locale = iso3CountryToLocale(country);
330  this.country = locale.getISO3Country();
331  break;
332  case 2:
333  locale = new Locale(country);
334  this.country = locale.getCountry();
335  break;
336  default:
337  locale = Locale.getDefault();
338  this.country = locale.getCountry();
339  break;
340  }
341  iso2Country = locale.getCountry();
342  }
343 
344  private static Locale iso3CountryToLocale(String iso3Country) {
345  Locale mappedLocale = iso3CountryToLocaleMap.get(iso3Country);
346  if (mappedLocale == null) {
347  // Country codes should be upper case, but maybe the user doesn't know that.
348  mappedLocale = iso3CountryToLocaleMap.get(iso3Country.toUpperCase(Locale.ENGLISH));
349  }
350  return mappedLocale == null ? Locale.getDefault() : mappedLocale;
351  }
352 
360  @SimpleProperty
361  public String Country() {
362  return country;
363  }
364 
365  @SimpleProperty(description = "List of the languages available on this device " +
366  "for use with TextToSpeech. Check the Android developer documentation under supported " +
367  "languages to find the meanings of these abbreviations.")
370  return allLanguages;
371  }
372 
373  @SimpleProperty(description = "List of the country codes available on this device " +
374  "for use with TextToSpeech. Check the Android developer documentation under supported " +
375  "languages to find the meanings of these abbreviations.")
378  return allCountries;
379  }
380 
382  if (!isTtsPrepared) {
383  if (!tts.isInitialized()) {
384  form.dispatchErrorOccurredEvent(this, "TextToSpeech",
386  // Force the TTS engine to initialize by making it speak.
387  // If it's not ready the user will have to try again.
388  // Should we put a retry wait here?
389  Speak("");
390  } else {
391  getLanguageAndCountryLists();
392  isTtsPrepared = true;
393  }
394  }
395  }
396 
402  private void getLanguageAndCountryLists() {
403  // We do compute these lists pre-Donut. We probably could
404  // arrange to also do this in earlier releases, but that would be
405  // relying on the use of an external textToSpeech application and those
406  // old releases are obsolete anyway.
408  String tempLang;
409  String tempCountry;
410  for (Locale locale : Locale.getAvailableLocales()) {
411  // isLanguageAvailable requires tts to be initialized
412  int res = tts.isLanguageAvailable(locale);
413  if (!(res == android.speech.tts.TextToSpeech.LANG_NOT_SUPPORTED)){
414  tempLang = locale.getLanguage();
415  // We record only the ISO3 country codes for now. We should update the TTS control
416  // to use voices, and then we can straighten this out, maybe getting rid of
417  // country modifiers in TTS altogether.
418  tempCountry = locale.getISO3Country();
419  if (!tempLang.equals("") && (!languageList.contains(tempLang))){
420  languageList.add(tempLang);
421  }
422  if (!tempCountry.equals("") && (!countryList.contains(tempCountry))){
423  countryList.add(tempCountry);
424  }
425  }
426  }
427  Collections.sort(languageList);
428  Collections.sort(countryList);
429  allLanguages = YailList.makeList(languageList);
430  allCountries = YailList.makeList(countryList);
431  }
432  }
433 
437  @SimpleFunction
438  public void Speak(final String message) {
439  BeforeSpeaking();
440  final Locale loc = new Locale(iso2Language, iso2Country);
441  tts.speak(message, loc);
442  }
443 
444 
448  @SimpleEvent
449  public void BeforeSpeaking() {
450  EventDispatcher.dispatchEvent(this, "BeforeSpeaking");
451  }
452 
460  @SimpleEvent(description = "Event to raise after the message is spoken. The result will be true "
461  + "if the message is spoken successfully, otherwise it will be false.")
462  public void AfterSpeaking(boolean result) {
463  EventDispatcher.dispatchEvent(this, "AfterSpeaking", result);
464  }
465 
466  @Override
467  public void onStop() {
468  // tts.onStop in fact does nothing, but we'll keep this onStop here for flexibility
469  tts.onStop();
470  }
471 
472  @Override
473  public void onResume() {
474  tts.onResume();
475  }
476 
477  @Override
478  public void onDestroy() {
479  tts.onDestroy();
480  }
481 
482 }
com.google.appinventor.components.runtime.EventDispatcher
Definition: EventDispatcher.java:22
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_FLOAT
static final String PROPERTY_TYPE_FLOAT
Definition: PropertyTypeConstants.java:76
com.google.appinventor.components.runtime.TextToSpeech.AvailableLanguages
YailList AvailableLanguages()
Definition: TextToSpeech.java:368
com.google.appinventor.components.runtime.util.YailList
Definition: YailList.java:26
com.google.appinventor.components.runtime.util.ITextToSpeech.onResume
void onResume()
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.runtime.TextToSpeech.TextToSpeech
TextToSpeech(ComponentContainer container)
Definition: TextToSpeech.java:132
com.google.appinventor.components.runtime.Form.registerForOnDestroy
void registerForOnDestroy(OnDestroyListener component)
Definition: Form.java:817
com.google.appinventor.components.runtime.util.ErrorMessages
Definition: ErrorMessages.java:17
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components.runtime.TextToSpeech.onDestroy
void onDestroy()
Definition: TextToSpeech.java:478
com.google.appinventor.components.runtime.Form.registerForOnResume
void registerForOnResume(OnResumeListener component)
Definition: Form.java:740
com.google.appinventor.components.runtime.util.ITextToSpeech.TextToSpeechCallback
Definition: ITextToSpeech.java:24
com.google.appinventor.components
com.google.appinventor.components.runtime.util.ITextToSpeech.onStop
void onStop()
com.google.appinventor.components.runtime.util.YailList.makeList
static YailList makeList(Object[] objects)
Definition: YailList.java:59
com.google.appinventor.components.runtime.TextToSpeech.AvailableCountries
YailList AvailableCountries()
Definition: TextToSpeech.java:376
com.google.appinventor.components.runtime.TextToSpeech.Country
String Country()
Definition: TextToSpeech.java:361
com.google.appinventor.components.runtime.TextToSpeech.onStop
void onStop()
Definition: TextToSpeech.java:467
com.google.appinventor.components.runtime.TextToSpeech.Pitch
float Pitch()
Definition: TextToSpeech.java:256
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_TEXT_TO_SPEECH_LANGUAGES
static final String PROPERTY_TYPE_TEXT_TO_SPEECH_LANGUAGES
Definition: PropertyTypeConstants.java:296
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.annotations.PropertyCategory.BEHAVIOR
BEHAVIOR
Definition: PropertyCategory.java:15
com.google.appinventor.components.runtime.TextToSpeech.BeforeSpeaking
void BeforeSpeaking()
Definition: TextToSpeech.java:449
com.google.appinventor.components.runtime.TextToSpeech.Language
String Language()
Definition: TextToSpeech.java:307
com.google.appinventor.components.runtime.collect
Definition: Lists.java:7
com.google.appinventor.components.runtime.util.ITextToSpeech.speak
void speak(String message, Locale loc)
com.google.appinventor.components.runtime.OnResumeListener
Definition: OnResumeListener.java:14
com.google.appinventor.components.runtime.util.ITextToSpeech.onDestroy
void onDestroy()
com.google.appinventor.components.runtime.util.ExternalTextToSpeech
Definition: ExternalTextToSpeech.java:29
com.google.appinventor.components.runtime.TextToSpeech.AfterSpeaking
void AfterSpeaking(boolean result)
Definition: TextToSpeech.java:462
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_DONUT
static final int LEVEL_DONUT
Definition: SdkLevel.java:21
com.google.appinventor.components.runtime.util.ITextToSpeech.setPitch
void setPitch(float pitch)
com.google.appinventor.components.runtime.EventDispatcher.dispatchEvent
static boolean dispatchEvent(Component component, String eventName, Object...args)
Definition: EventDispatcher.java:188
com.google.appinventor.components.runtime.AndroidNonvisibleComponent
Definition: AndroidNonvisibleComponent.java:17
com.google.appinventor.components.runtime.util.SdkLevel
Definition: SdkLevel.java:19
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_TEXT_TO_SPEECH_COUNTRIES
static final String PROPERTY_TYPE_TEXT_TO_SPEECH_COUNTRIES
Definition: PropertyTypeConstants.java:290
com.google.appinventor.components.runtime.collect.Maps
Definition: Maps.java:19
com.google.appinventor.components.runtime.util.ITextToSpeech.setSpeechRate
void setSpeechRate(float speechRate)
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.runtime.collect.Maps.newHashMap
static< K, V > HashMap< K, V > newHashMap()
Definition: Maps.java:25
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.util.ITextToSpeech
Definition: ITextToSpeech.java:19
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
com.google.appinventor.components.runtime.util.SdkLevel.getLevel
static int getLevel()
Definition: SdkLevel.java:45
com.google.appinventor.components.runtime
Copyright 2009-2011 Google, All Rights reserved.
Definition: AccelerometerSensor.java:8
com.google.appinventor.components.runtime.Component
Definition: Component.java:17
com.google.appinventor.components.runtime.TextToSpeech.prepareLanguageAndCountryProperties
void prepareLanguageAndCountryProperties()
Definition: TextToSpeech.java:381
com.google.appinventor.components.runtime.Map< String, Locale >
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.runtime.TextToSpeech.onResume
void onResume()
Definition: TextToSpeech.java:473
com.google.appinventor.components.runtime.TextToSpeech
Definition: TextToSpeech.java:71
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.runtime.OnStopListener
Definition: OnStopListener.java:15
com.google.appinventor.components.runtime.Component.DEFAULT_VALUE_TEXT_TO_SPEECH_LANGUAGE
static final String DEFAULT_VALUE_TEXT_TO_SPEECH_LANGUAGE
Definition: Component.java:154
com.google.appinventor.components.runtime.Form.dispatchErrorOccurredEvent
void dispatchErrorOccurredEvent(final Component component, final String functionName, final int errorNumber, final Object... messageArgs)
Definition: Form.java:1011
com.google.appinventor.components.runtime.Form.registerForOnStop
void registerForOnStop(OnStopListener component)
Definition: Form.java:793
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google
com
com.google.appinventor.components.runtime.Component.DEFAULT_VALUE_TEXT_TO_SPEECH_COUNTRY
static final String DEFAULT_VALUE_TEXT_TO_SPEECH_COUNTRY
Definition: Component.java:153
com.google.appinventor.components.runtime.util.ITextToSpeech.isLanguageAvailable
int isLanguageAvailable(Locale loc)
com.google.appinventor.components.runtime.ComponentContainer.$form
Form $form()
com.google.appinventor.components.runtime.ComponentContainer.$context
Activity $context()
com.google.appinventor.components.runtime.TextToSpeech.Speak
void Speak(final String message)
Definition: TextToSpeech.java:438
com.google.appinventor.components.runtime.util.ITextToSpeech.isInitialized
boolean isInitialized()
com.google.appinventor.components.runtime.AndroidNonvisibleComponent.form
final Form form
Definition: AndroidNonvisibleComponent.java:19
com.google.appinventor.components.runtime.TextToSpeech.SpeechRate
float SpeechRate()
Definition: TextToSpeech.java:295
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.runtime.OnDestroyListener
Definition: OnDestroyListener.java:15
com.google.appinventor.components.annotations
com.google.appinventor.components.runtime.TextToSpeech.Result
boolean Result()
Definition: TextToSpeech.java:176
com.google.appinventor.components.runtime.util.ErrorMessages.ERROR_TTS_NOT_READY
static final int ERROR_TTS_NOT_READY
Definition: ErrorMessages.java:202
com.google.appinventor
com.google.appinventor.components.runtime.util.InternalTextToSpeech
Definition: InternalTextToSpeech.java:34