diff options
| author | Narayan Kamath <narayan@google.com> | 2011-08-22 15:37:47 +0100 |
|---|---|---|
| committer | Narayan Kamath <narayan@google.com> | 2011-08-23 10:20:42 +0100 |
| commit | e5b8c4dfc70288f661e0da4f082dd51cc1399f86 (patch) | |
| tree | a5ca8e73d2ec68dc018c18280eed283100c0b150 | |
| parent | e644b647837a2f2835c20423d0657cca19d3595a (diff) | |
| download | frameworks_base-e5b8c4dfc70288f661e0da4f082dd51cc1399f86.zip frameworks_base-e5b8c4dfc70288f661e0da4f082dd51cc1399f86.tar.gz frameworks_base-e5b8c4dfc70288f661e0da4f082dd51cc1399f86.tar.bz2 | |
Framework changes to support new TTS settings features.
Locale is now stored per engine, instead of as a global
option.
bug:5149036
Change-Id: I9848172623fe8aea1dd8e6678bca008da6a4cfb1
| -rw-r--r-- | core/java/android/provider/Settings.java | 10 | ||||
| -rw-r--r-- | core/java/android/speech/tts/TextToSpeechService.java | 36 | ||||
| -rw-r--r-- | core/java/android/speech/tts/TtsEngines.java | 188 |
3 files changed, 204 insertions, 30 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 554afd2..03cba3d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2815,6 +2815,16 @@ public final class Settings { public static final String TTS_DEFAULT_VARIANT = "tts_default_variant"; /** + * Stores the default tts locales on a per engine basis. Stored as + * a comma seperated list of values, each value being of the form + * {@code engine_name:locale} for example, + * {@code com.foo.ttsengine:eng-USA,com.bar.ttsengine:esp-ESP}. + * + * @hide + */ + public static final String TTS_DEFAULT_LOCALE = "tts_default_locale"; + + /** * Space delimited list of plugin packages that are enabled. */ public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins"; diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index b4e8ab4..a08ba2a 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -65,6 +65,7 @@ import java.util.Locale; * * {@link #onStop} tells the engine that it should stop all ongoing synthesis, if * any. Any pending data from the current synthesis will be discarded. + * */ // TODO: Add a link to the sample TTS engine once it's done. public abstract class TextToSpeechService extends Service { @@ -80,6 +81,7 @@ public abstract class TextToSpeechService extends Service { // associated with this TTS engine. Will handle all requests except synthesis // to file requests, which occur on the synthesis thread. private AudioPlaybackHandler mAudioPlaybackHandler; + private TtsEngines mEngineHelper; private CallbackMap mCallbacks; private String mPackageName; @@ -96,12 +98,15 @@ public abstract class TextToSpeechService extends Service { mAudioPlaybackHandler = new AudioPlaybackHandler(); mAudioPlaybackHandler.start(); + mEngineHelper = new TtsEngines(this); + mCallbacks = new CallbackMap(); mPackageName = getApplicationInfo().packageName; + String[] defaultLocale = getSettingsLocale(); // Load default language - onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant()); + onLoadLanguage(defaultLocale[0], defaultLocale[1], defaultLocale[2]); } @Override @@ -195,30 +200,15 @@ public abstract class TextToSpeechService extends Service { return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE); } - private String getDefaultLanguage() { - return getSecureSettingString(Settings.Secure.TTS_DEFAULT_LANG, - Locale.getDefault().getISO3Language()); - } - - private String getDefaultCountry() { - return getSecureSettingString(Settings.Secure.TTS_DEFAULT_COUNTRY, - Locale.getDefault().getISO3Country()); - } - - private String getDefaultVariant() { - return getSecureSettingString(Settings.Secure.TTS_DEFAULT_VARIANT, - Locale.getDefault().getVariant()); + private String[] getSettingsLocale() { + final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName); + return TtsEngines.parseLocalePref(locale); } private int getSecureSettingInt(String name, int defaultValue) { return Settings.Secure.getInt(getContentResolver(), name, defaultValue); } - private String getSecureSettingString(String name, String defaultValue) { - String value = Settings.Secure.getString(getContentResolver(), name); - return value != null ? value : defaultValue; - } - /** * Synthesizer thread. This thread is used to run {@link SynthHandler}. */ @@ -458,6 +448,7 @@ public abstract class TextToSpeechService extends Service { class SynthesisSpeechItem extends SpeechItem { private final String mText; private final SynthesisRequest mSynthesisRequest; + private final String[] mDefaultLocale; // Non null after synthesis has started, and all accesses // guarded by 'this'. private AbstractSynthesisCallback mSynthesisCallback; @@ -467,6 +458,7 @@ public abstract class TextToSpeechService extends Service { super(callingApp, params); mText = text; mSynthesisRequest = new SynthesisRequest(mText, mParams); + mDefaultLocale = getSettingsLocale(); setRequestParams(mSynthesisRequest); mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName); } @@ -523,7 +515,7 @@ public abstract class TextToSpeechService extends Service { } public String getLanguage() { - return getStringParam(Engine.KEY_PARAM_LANGUAGE, getDefaultLanguage()); + return getStringParam(Engine.KEY_PARAM_LANGUAGE, mDefaultLocale[0]); } private boolean hasLanguage() { @@ -531,12 +523,12 @@ public abstract class TextToSpeechService extends Service { } private String getCountry() { - if (!hasLanguage()) return getDefaultCountry(); + if (!hasLanguage()) return mDefaultLocale[1]; return getStringParam(Engine.KEY_PARAM_COUNTRY, ""); } private String getVariant() { - if (!hasLanguage()) return getDefaultVariant(); + if (!hasLanguage()) return mDefaultLocale[2]; return getStringParam(Engine.KEY_PARAM_VARIANT, ""); } diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java index 5f0cb74..bb72bea 100644 --- a/core/java/android/speech/tts/TtsEngines.java +++ b/core/java/android/speech/tts/TtsEngines.java @@ -17,6 +17,7 @@ package android.speech.tts; import org.xmlpull.v1.XmlPullParserException; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -27,6 +28,8 @@ 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; import android.speech.tts.TextToSpeech.Engine; import android.speech.tts.TextToSpeech.EngineInfo; @@ -40,6 +43,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; /** * Support class for querying the list of available engines @@ -52,6 +56,9 @@ import java.util.List; */ public class TtsEngines { private static final String TAG = "TtsEngines"; + private static final boolean DBG = false; + + private static final String LOCALE_DELIMITER = "-"; private final Context mContext; @@ -65,7 +72,7 @@ public class TtsEngines { * the highest ranked engine is returned as per {@link EngineInfoComparator}. */ public String getDefaultEngine() { - String engine = Settings.Secure.getString(mContext.getContentResolver(), + String engine = getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_SYNTH); return isEngineInstalled(engine) ? engine : getHighestRankedEngineName(); } @@ -129,12 +136,6 @@ public class TtsEngines { return engines; } - // TODO: Used only by the settings app. Remove once - // the settings UI change has been finalized. - public boolean isEngineEnabled(String engine) { - return isEngineInstalled(engine); - } - private boolean isSystemEngine(ServiceInfo info) { final ApplicationInfo appInfo = info.applicationInfo; return appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; @@ -182,7 +183,7 @@ public class TtsEngines { * The name of the XML tag that text to speech engines must use to * declare their meta data. * - * {@link com.android.internal.R.styleable.TextToSpeechEngine} + * {@link com.android.internal.R.styleable#TextToSpeechEngine} */ private static final String XML_TAG_NAME = "tts-engine"; @@ -279,4 +280,175 @@ public class TtsEngines { } } + /** + * Returns the locale string 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. + * + * @param engineName the engine to return the locale for. + * @return the locale string preference for this engine. Will be non null + * and non empty. + */ + public String getLocalePrefForEngine(String engineName) { + String locale = parseEnginePrefFromList( + getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE), + engineName); + + if (TextUtils.isEmpty(locale)) { + // The new style setting is unset, attempt to return the old style setting. + locale = getV1Locale(); + } + + if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale); + + return locale; + } + + /** + * 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. + */ + 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); + + if (TextUtils.isEmpty(lang)) { + return getDefaultLocale(); + } + + String v1Locale = lang; + if (!TextUtils.isEmpty(country)) { + v1Locale += LOCALE_DELIMITER + country; + } + if (!TextUtils.isEmpty(variant)) { + v1Locale += LOCALE_DELIMITER + variant; + } + + return v1Locale; + } + + private String getDefaultLocale() { + final Locale locale = Locale.getDefault(); + + return locale.getISO3Language() + LOCALE_DELIMITER + locale.getISO3Country() + + LOCALE_DELIMITER + locale.getVariant(); + } + + /** + * Parses a comma separated list of engine locale preferences. The list is of the + * form {@code "engine_name_1:locale_1,engine_name_2:locale2"} and so on and + * so forth. Returns null if the list is empty, malformed or if there is no engine + * specific preference in the list. + */ + private static String parseEnginePrefFromList(String prefValue, String engineName) { + if (TextUtils.isEmpty(prefValue)) { + return null; + } + + String[] prefValues = prefValue.split(","); + + for (String value : prefValues) { + final int delimiter = value.indexOf(':'); + if (delimiter > 0) { + if (engineName.equals(value.substring(0, delimiter))) { + return value.substring(delimiter + 1); + } + } + } + + return null; + } + + public synchronized void updateLocalePrefForEngine(String name, String newLocale) { + final String prefList = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.TTS_DEFAULT_LOCALE); + if (DBG) { + Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale + + "), originally: " + prefList); + } + + final String newPrefList = updateValueInCommaSeparatedList(prefList, + name, newLocale); + + if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString()); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.TTS_DEFAULT_LOCALE, newPrefList.toString()); + } + + /** + * Updates the value for a given key in a comma separated list of key value pairs, + * each of which are delimited by a colon. If no value exists for the given key, + * the kay value pair are appended to the end of the list. + */ + private String updateValueInCommaSeparatedList(String list, String key, + String newValue) { + StringBuilder newPrefList = new StringBuilder(); + if (TextUtils.isEmpty(list)) { + // If empty, create a new list with a single entry. + newPrefList.append(key).append(':').append(newValue); + } else { + String[] prefValues = list.split(","); + // Whether this is the first iteration in the loop. + boolean first = true; + // Whether we found the given key. + boolean found = false; + for (String value : prefValues) { + final int delimiter = value.indexOf(':'); + if (delimiter > 0) { + if (key.equals(value.substring(0, delimiter))) { + if (first) { + first = false; + } else { + newPrefList.append(','); + } + found = true; + newPrefList.append(key).append(':').append(newValue); + } else { + if (first) { + first = false; + } else { + newPrefList.append(','); + } + // Copy across the entire key + value as is. + newPrefList.append(value); + } + } + } + + if (!found) { + // Not found, but the rest of the keys would have been copied + // over already, so just append it to the end. + newPrefList.append(','); + newPrefList.append(key).append(':').append(newValue); + } + } + + return newPrefList.toString(); + } } |
