Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d03462b authored by Narayan Kamath's avatar Narayan Kamath
Browse files

New API for TTS settings.

Engines must declare a <meta-data> attribute in their
manifest with name "android.speech.tts". This must reference
an XML resource as per
com.android.internal.R.styleable.TextToSpeechEngine.

Change-Id: I56a6b9f1a360174f98c9f39da901ade83d0f38a7
parent 02e2f57d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17706,6 +17706,7 @@ package android.speech.tts {
    field public static final java.lang.String KEY_PARAM_STREAM = "streamType";
    field public static final java.lang.String KEY_PARAM_UTTERANCE_ID = "utteranceId";
    field public static final java.lang.String KEY_PARAM_VOLUME = "volume";
    field public static final java.lang.String SERVICE_META_DATA = "android.speech.tts";
  }
  public static class TextToSpeech.EngineInfo {
+8 −0
Original line number Diff line number Diff line
@@ -234,6 +234,14 @@ public class TextToSpeech {
        public static final String INTENT_ACTION_TTS_SERVICE =
                "android.intent.action.TTS_SERVICE";

        /**
         * Name under which a text to speech engine publishes information about itself.
         * This meta-data should reference an XML resource containing a
         * <code>&lt;{@link android.R.styleable#TextToSpeechEngine tts-engine}&gt;</code>
         * tag.
         */
        public static final String SERVICE_META_DATA = "android.speech.tts";

        // intents to ask engine to install data or check its data
        /**
         * Activity Action: Triggers the platform TextToSpeech engine to
+95 −0
Original line number Diff line number Diff line
@@ -15,17 +15,27 @@
 */
package android.speech.tts;

import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.provider.Settings;
import android.speech.tts.TextToSpeech.Engine;
import android.speech.tts.TextToSpeech.EngineInfo;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -41,6 +51,8 @@ import java.util.List;
 * @hide
 */
public class TtsEngines {
    private static final String TAG = "TtsEngines";

    private final Context mContext;

    public TtsEngines(Context ctx) {
@@ -139,6 +151,89 @@ public class TtsEngines {
        return getEngineInfo(engine) != null;
    }

    /**
     * @return an intent that can launch the settings activity for a given tts engine.
     */
    public Intent getSettingsIntent(String engine) {
        PackageManager pm = mContext.getPackageManager();
        Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
        intent.setPackage(engine);
        List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent,
                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA);
        // Note that the current API allows only one engine per
        // package name. Since the "engine name" is the same as
        // the package name.
        if (resolveInfos != null && resolveInfos.size() == 1) {
            ServiceInfo service = resolveInfos.get(0).serviceInfo;
            if (service != null) {
                final String settings = settingsActivityFromServiceInfo(service, pm);
                if (settings != null) {
                    Intent i = new Intent();
                    i.setClassName(engine, settings);
                    return i;
                }
            }
        }

        return null;
    }

    /**
     * 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}
     */
    private static final String XML_TAG_NAME = "tts-engine";

    private String settingsActivityFromServiceInfo(ServiceInfo si, PackageManager pm) {
        XmlResourceParser parser = null;
        try {
            parser = si.loadXmlMetaData(pm, TextToSpeech.Engine.SERVICE_META_DATA);
            if (parser == null) {
                Log.w(TAG, "No meta-data found for :" + si);
                return null;
            }

            final Resources res = pm.getResourcesForApplication(si.applicationInfo);

            int type;
            while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT) {
                if (type == XmlResourceParser.START_TAG) {
                    if (!XML_TAG_NAME.equals(parser.getName())) {
                        Log.w(TAG, "Package " + si + " uses unknown tag :"
                                + parser.getName());
                        return null;
                    }

                    final AttributeSet attrs = Xml.asAttributeSet(parser);
                    final TypedArray array = res.obtainAttributes(attrs,
                            com.android.internal.R.styleable.TextToSpeechEngine);
                    final String settings = array.getString(
                            com.android.internal.R.styleable.TextToSpeechEngine_settingsActivity);
                    array.recycle();

                    return settings;
                }
            }

            return null;
        } catch (NameNotFoundException e) {
            Log.w(TAG, "Could not load resources for : " + si);
            return null;
        } catch (XmlPullParserException e) {
            Log.w(TAG, "Error parsing metadata for " + si + ":" + e);
            return null;
        } catch (IOException e) {
            Log.w(TAG, "Error parsing metadata for " + si + ":" + e);
            return null;
        } finally {
            if (parser != null) {
                parser.close();
            }
        }
    }

    private EngineInfo getEngineInfo(ResolveInfo resolve, PackageManager pm) {
        ServiceInfo service = resolve.serviceInfo;
        if (service != null) {
+11 −0
Original line number Diff line number Diff line
@@ -5249,4 +5249,15 @@
        <attr name="disableDependentsState" />
    </declare-styleable>

    <!-- Use <code>tts-engine</code> as the root tag of the XML resource that
         describes a text to speech engine implemented as a subclass of
         {@link android.speech.tts.TextToSpeechService}.

         The XML resource must be referenced from its
         {@link android.speech.tts.TextToSpeech.Engine#SERVICE_META_DATA} meta-data
         entry. -->
    <declare-styleable name="TextToSpeechEngine">
        <attr name="settingsActivity" />
    </declare-styleable>

</resources>