summaryrefslogtreecommitdiffstats
path: root/core/java/android/speech
diff options
context:
space:
mode:
authorPrzemyslaw Szczepaniak <pszczepaniak@google.com>2014-06-13 12:04:00 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-06-11 15:57:38 +0000
commite31ab2d8fcb7413e4775a7cfdd340636a9eea7e7 (patch)
tree29cb279ff1b39d7ed83e46a2d27f95fbd21a15db /core/java/android/speech
parent53a1eaa7711af753a276290f9c9b812704dfd023 (diff)
parent1b5637ee32c5d4e5d857fa86a1b1c1db23d027b7 (diff)
downloadframeworks_base-e31ab2d8fcb7413e4775a7cfdd340636a9eea7e7.zip
frameworks_base-e31ab2d8fcb7413e4775a7cfdd340636a9eea7e7.tar.gz
frameworks_base-e31ab2d8fcb7413e4775a7cfdd340636a9eea7e7.tar.bz2
Merge "Expose "default tts locale" to the TTS V2 API."
Diffstat (limited to 'core/java/android/speech')
-rw-r--r--core/java/android/speech/tts/RequestConfigHelper.java12
-rw-r--r--core/java/android/speech/tts/SynthesisRequestV2.java4
-rw-r--r--core/java/android/speech/tts/TextToSpeechClient.java25
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java4
-rw-r--r--core/java/android/speech/tts/TtsEngines.java228
5 files changed, 168 insertions, 105 deletions
diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java
index 3b5490b..bc65280 100644
--- a/core/java/android/speech/tts/RequestConfigHelper.java
+++ b/core/java/android/speech/tts/RequestConfigHelper.java
@@ -46,7 +46,8 @@ public final class RequestConfigHelper {
/**
* Score positively voices that exactly match the given locale
- * @param locale Reference locale. If null, the default locale will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public ExactLocaleMatcher(Locale locale) {
if (locale == null) {
@@ -70,7 +71,8 @@ public final class RequestConfigHelper {
/**
* Score positively voices with similar locale.
- * @param locale Reference locale. If null, default will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public LanguageMatcher(Locale locale) {
if (locale == null) {
@@ -164,10 +166,10 @@ public final class RequestConfigHelper {
}
/**
- * Get highest quality voice for the default locale.
+ * Get highest quality voice for the TTS default locale.
*
* Call {@link #highestQuality(EngineStatus, boolean, VoiceScorer)} with
- * {@link LanguageMatcher} set to device default locale.
+ * {@link LanguageMatcher} set to the {@link EngineStatus#getDefaultLocale()}.
*
* @param engineStatus
* Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call.
@@ -179,7 +181,7 @@ public final class RequestConfigHelper {
public static RequestConfig highestQuality(EngineStatus engineStatus,
boolean hasToBeEmbedded) {
return highestQuality(engineStatus, hasToBeEmbedded,
- new LanguageMatcher(Locale.getDefault()));
+ new LanguageMatcher(engineStatus.getDefaultLocale()));
}
}
diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java
index a42aa16..938458c 100644
--- a/core/java/android/speech/tts/SynthesisRequestV2.java
+++ b/core/java/android/speech/tts/SynthesisRequestV2.java
@@ -167,9 +167,7 @@ public final class SynthesisRequestV2 implements Parcelable {
}
};
- /**
- * @hide
- */
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 0c0be83..f726743 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -42,6 +42,7 @@ import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -357,9 +358,13 @@ public class TextToSpeechClient {
/** Name of the TTS engine package */
private final String mPackageName;
- private EngineStatus(String packageName, List<VoiceInfo> voices) {
+ /** Engine default locale */
+ private final Locale mDefaultLocale;
+
+ private EngineStatus(String packageName, List<VoiceInfo> voices, Locale defaultLocale) {
this.mVoices = Collections.unmodifiableList(voices);
this.mPackageName = packageName;
+ this.mDefaultLocale = defaultLocale;
}
/**
@@ -375,6 +380,16 @@ public class TextToSpeechClient {
public String getEnginePackage() {
return mPackageName;
}
+
+ /**
+ * Get the default locale to use for TTS with this TTS engine.
+ * Unless the user changed the TTS settings for this engine, the value returned should be
+ * the same as the system default locale for the current user
+ * ({@link Locale#getDefault()}).
+ */
+ public Locale getDefaultLocale() {
+ return mDefaultLocale;
+ }
}
/** Unique synthesis request identifier. */
@@ -638,7 +653,9 @@ public class TextToSpeechClient {
return null;
}
- return new EngineStatus(mServiceConnection.getEngineName(), voices);
+ return new EngineStatus(mServiceConnection.getEngineName(), voices,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
}
private class Connection implements ServiceConnection {
@@ -696,7 +713,9 @@ public class TextToSpeechClient {
public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) {
synchronized (mLock) {
mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
- voicesInfo);
+ voicesInfo,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
mEngineStatus).sendToTarget();
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 14a4024..20f3ad7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -460,8 +460,8 @@ public abstract class TextToSpeechService extends Service {
}
private String[] getSettingsLocale() {
- final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
- return TtsEngines.parseLocalePref(locale);
+ final Locale locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
+ return TtsEngines.toOldLocaleStringFormat(locale);
}
private int getSecureSettingInt(String name, int defaultValue) {
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 9b929a3..b4c2824 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -28,6 +28,7 @@ import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+
import static android.provider.Settings.Secure.getString;
import android.provider.Settings;
@@ -42,8 +43,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.MissingResourceException;
/**
@@ -53,16 +56,52 @@ import java.util.MissingResourceException;
* Comments in this class the use the shorthand "system engines" for engines that
* are a part of the system image.
*
+ * This class is thread-safe/
+ *
* @hide
*/
public class TtsEngines {
private static final String TAG = "TtsEngines";
private static final boolean DBG = false;
- private static final String LOCALE_DELIMITER = "-";
+ /** Locale delimiter used by the old-style 3 char locale string format (like "eng-usa") */
+ private static final String LOCALE_DELIMITER_OLD = "-";
+
+ /** Locale delimiter used by the new-style locale string format (Locale.toString() results,
+ * like "en_US") */
+ private static final String LOCALE_DELIMITER_NEW = "_";
private final Context mContext;
+ /** Mapping of various language strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeLanguage;
+
+ /** Mapping of various country strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeCountry;
+
+ // Populate the sNormalize* maps
+ static {
+ HashMap<String, String> normalizeLanguage = new HashMap<String, String>();
+ for (String language : Locale.getISOLanguages()) {
+ try {
+ normalizeLanguage.put(new Locale(language).getISO3Language(), language);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeLanguage = Collections.unmodifiableMap(normalizeLanguage);
+
+ HashMap<String, String> normalizeCountry = new HashMap<String, String>();
+ for (String country : Locale.getISOCountries()) {
+ try {
+ normalizeCountry.put(new Locale("", country).getISO3Country(), country);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeCountry = Collections.unmodifiableMap(normalizeCountry);
+ }
+
public TtsEngines(Context ctx) {
mContext = ctx;
}
@@ -282,139 +321,139 @@ public class TtsEngines {
}
/**
- * Returns the locale string for a given TTS engine. Attempts to read the
+ * Returns the default locale for a given TTS engine. Attempts to read the
* value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, the default phone locale is returned.
+ * default phone locale is returned.
*
* @param engineName the engine to return the locale for.
- * @return the locale string preference for this engine. Will be non null
- * and non empty.
+ * @return the locale preference for this engine. Will be non null.
*/
- public String getLocalePrefForEngine(String engineName) {
- String locale = parseEnginePrefFromList(
- getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
+ public Locale getLocalePrefForEngine(String engineName) {
+ return getLocalePrefForEngine(engineName,
+ getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE));
+ }
+
+ /**
+ * Returns the default locale for a given TTS engine from given settings string. */
+ public Locale getLocalePrefForEngine(String engineName, String prefValue) {
+ String localeString = parseEnginePrefFromList(
+ prefValue,
engineName);
- if (TextUtils.isEmpty(locale)) {
+ if (TextUtils.isEmpty(localeString)) {
// The new style setting is unset, attempt to return the old style setting.
- locale = getV1Locale();
+ return Locale.getDefault();
+ }
+
+ Locale result = parseLocaleString(localeString);
+ if (result == null) {
+ Log.w(TAG, "Failed to parse locale " + localeString + ", returning en_US instead");
+ result = Locale.US;
}
- if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale);
+ if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + result);
- return locale;
+ return result;
}
+
/**
* True if a given TTS engine uses the default phone locale as a default locale. Attempts to
- * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, this methods returns true.
+ * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}. If
+ * its value is empty, this methods returns true.
*
* @param engineName the engine to return the locale for.
*/
public boolean isLocaleSetToDefaultForEngine(String engineName) {
- return (TextUtils.isEmpty(parseEnginePrefFromList(
+ return TextUtils.isEmpty(parseEnginePrefFromList(
getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
- engineName)) &&
- TextUtils.isEmpty(
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.TTS_DEFAULT_LANG)));
+ engineName));
}
-
/**
- * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
- * Varies from {@link String#split} in that it will always return an array
- * of length 3 with non null values.
+ * Parses a locale encoded as a string, and tries its best to return a valid {@link Locale}
+ * object, even if the input string is encoded using the old-style 3 character format e.g.
+ * "deu-deu". At the end, we test if the resulting locale can return ISO3 language and
+ * country codes ({@link Locale#getISO3Language()} and {@link Locale#getISO3Country()}),
+ * if it fails to do so, we return null.
*/
- public static String[] parseLocalePref(String pref) {
- String[] returnVal = new String[] { "", "", ""};
- if (!TextUtils.isEmpty(pref)) {
- String[] split = pref.split(LOCALE_DELIMITER);
- System.arraycopy(split, 0, returnVal, 0, split.length);
- }
-
- if (DBG) Log.d(TAG, "parseLocalePref(" + returnVal[0] + "," + returnVal[1] +
- "," + returnVal[2] +")");
-
- return returnVal;
- }
-
- /**
- * @return the old style locale string constructed from
- * {@link Settings.Secure#TTS_DEFAULT_LANG},
- * {@link Settings.Secure#TTS_DEFAULT_COUNTRY} and
- * {@link Settings.Secure#TTS_DEFAULT_VARIANT}. If no such locale is set,
- * then return the default phone locale.
- */
- private String getV1Locale() {
- final ContentResolver cr = mContext.getContentResolver();
-
- final String lang = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_LANG);
- final String country = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_COUNTRY);
- final String variant = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_VARIANT);
+ public Locale parseLocaleString(String localeString) {
+ String language = "", country = "", variant = "";
+ if (!TextUtils.isEmpty(localeString)) {
+ String[] split = localeString.split(
+ "[" + LOCALE_DELIMITER_OLD + LOCALE_DELIMITER_NEW + "]");
+ language = split[0].toLowerCase();
+ if (split.length == 0) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Only" +
+ " separators");
+ return null;
+ }
+ if (split.length > 3) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Too" +
+ " many separators");
+ return null;
+ }
+ if (split.length >= 2) {
+ country = split[1].toUpperCase();
+ }
+ if (split.length >= 3) {
+ variant = split[2];
+ }
- if (TextUtils.isEmpty(lang)) {
- return getDefaultLocale();
}
- String v1Locale = lang;
- if (!TextUtils.isEmpty(country)) {
- v1Locale += LOCALE_DELIMITER + country;
- } else {
- return v1Locale;
+ String normalizedLanguage = sNormalizeLanguage.get(language);
+ if (normalizedLanguage != null) {
+ language = normalizedLanguage;
}
- if (!TextUtils.isEmpty(variant)) {
- v1Locale += LOCALE_DELIMITER + variant;
+ String normalizedCountry= sNormalizeCountry.get(country);
+ if (normalizedCountry != null) {
+ country = normalizedCountry;
}
- return v1Locale;
+ if (DBG) Log.d(TAG, "parseLocalePref(" + language + "," + country +
+ "," + variant +")");
+
+ Locale result = new Locale(language, country, variant);
+ try {
+ result.getISO3Language();
+ result.getISO3Country();
+ return result;
+ } catch(MissingResourceException e) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object.");
+ return null;
+ }
}
/**
- * Return the default device locale in form of 3 letter codes delimited by
- * {@link #LOCALE_DELIMITER}:
+ * Return the old-style string form of the locale. It consists of 3 letter codes:
* <ul>
- * <li> "ISO 639-2/T language code" if locale have no country entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code "
- * if locale have no variant entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code
- * {@link #LOCALE_DELIMITER} variant" if locale have variant entry</li>
+ * <li>"ISO 639-2/T language code" if the locale has no country entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code"
+ * if the locale has no variant entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country
+ * code{@link #LOCALE_DELIMITER}variant" if the locale has a variant entry</li>
* </ul>
+ * If we fail to generate those codes using {@link Locale#getISO3Country()} and
+ * {@link Locale#getISO3Language()}, then we return new String[]{"eng","USA",""};
*/
- public String getDefaultLocale() {
- final Locale locale = Locale.getDefault();
-
+ static public String[] toOldLocaleStringFormat(Locale locale) {
+ String[] ret = new String[]{"","",""};
try {
// Note that the default locale might have an empty variant
// or language, and we take care that the construction is
// the same as {@link #getV1Locale} i.e no trailing delimiters
// or spaces.
- String defaultLocale = locale.getISO3Language();
- if (TextUtils.isEmpty(defaultLocale)) {
- Log.w(TAG, "Default locale is empty.");
- return "";
- }
+ ret[0] = locale.getISO3Language();
+ ret[1] = locale.getISO3Country();
+ ret[2] = locale.getVariant();
- if (!TextUtils.isEmpty(locale.getISO3Country())) {
- defaultLocale += LOCALE_DELIMITER + locale.getISO3Country();
- } else {
- // Do not allow locales of the form lang--variant with
- // an empty country.
- return defaultLocale;
- }
- if (!TextUtils.isEmpty(locale.getVariant())) {
- defaultLocale += LOCALE_DELIMITER + locale.getVariant();
- }
-
- return defaultLocale;
+ return ret;
} catch (MissingResourceException e) {
// Default locale does not have a ISO 3166 and/or ISO 639-2/T codes. Return the
// default "eng-usa" (that would be the result of Locale.getDefault() == Locale.US).
- return "eng-usa";
+ return new String[]{"eng","USA",""};
}
}
@@ -443,16 +482,21 @@ public class TtsEngines {
return null;
}
- public synchronized void updateLocalePrefForEngine(String name, String newLocale) {
+ /**
+ * Serialize the locale to a string and store it as a default locale for the given engine. If
+ * the passed locale is null, an empty string will be serialized; that empty string, when
+ * read back, will evaluate to {@line Locale#getDefault()}.
+ */
+ public synchronized void updateLocalePrefForEngine(String engineName, Locale newLocale) {
final String prefList = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.TTS_DEFAULT_LOCALE);
if (DBG) {
- Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale +
+ Log.d(TAG, "updateLocalePrefForEngine(" + engineName + ", " + newLocale +
"), originally: " + prefList);
}
final String newPrefList = updateValueInCommaSeparatedList(prefList,
- name, newLocale);
+ engineName, (newLocale != null) ? newLocale.toString() : "");
if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString());