/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.text.style; import java.text.NumberFormat; import java.util.Locale; import android.os.Parcel; import android.os.PersistableBundle; import android.text.ParcelableSpan; import android.text.TextUtils; /** * A span that supplies additional meta-data for the associated text intended * for text-to-speech engines. If the text is being processed by a * text-to-speech engine, the engine may use the data in this span in addition * to or instead of its associated text. * * Each instance of a TtsSpan has a type, for example {@link #TYPE_DATE} * or {@link #TYPE_MEASURE}. And a list of arguments, provided as * key-value pairs in a bundle. * * The inner classes are there for convenience and provide builders for each * TtsSpan type. */ public class TtsSpan implements ParcelableSpan { private final String mType; private final PersistableBundle mArgs; /** * This span type can be used to add morphosyntactic features to the text it * spans over, or synthesize a something else than the spanned text. Use * the argument {@link #ARG_TEXT} to set a different text. * Accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_TEXT = "android.type.text"; /** * The text associated with this span is a cardinal. Must include the * number to be synthesized with {@link #ARG_NUMBER}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_CARDINAL = "android.type.cardinal"; /** * The text associated with this span is an ordinal. Must include the * number to be synthesized with {@link #ARG_NUMBER}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_ORDINAL = "android.type.ordinal"; /** * The text associated with this span is a decimal number. Must include the * number to be synthesized with {@link #ARG_INTEGER_PART} and * {@link #ARG_FRACTIONAL_PART}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_DECIMAL = "android.type.decimal"; /** * The text associated with this span is a fractional number. Must include * the number to be synthesized with {@link #ARG_NUMERATOR} and * {@link #ARG_DENOMINATOR}. {@link #ARG_INTEGER_PART} is optional * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_FRACTION = "android.type.fraction"; /** * The text associated with this span is a measure, consisting of a number * and a unit. The number can be a cardinal, decimal or a fraction. Set the * number with the same arguments as {@link #TYPE_CARDINAL}, * {@link #TYPE_DECIMAL} or {@link #TYPE_FRACTION}. The unit can be * specified with {@link #ARG_UNIT}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_MEASURE = "android.type.measure"; /** * The text associated with this span is a time, consisting of a number of * hours and minutes, specified with {@link #ARG_HOURS} and * {@link #ARG_MINUTES}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and * {@link #ARG_CASE}. */ public static final String TYPE_TIME = "android.type.time"; /** * The text associated with this span is a date. At least one of the * arguments {@link #ARG_MONTH} and {@link #ARG_YEAR} has to be provided. * The argument {@link #ARG_DAY} is optional if {@link #ARG_MONTH} is set. * The argument {@link #ARG_WEEKDAY} is optional if {@link #ARG_DAY} is set. * Also accepts the arguments {@link #ARG_GENDER}, {@link #ARG_ANIMACY}, * {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_DATE = "android.type.date"; /** * The text associated with this span is a telephone number. The argument * {@link #ARG_NUMBER_PARTS} is required. {@link #ARG_COUNTRY_CODE} and * {@link #ARG_EXTENSION} are optional. * Also accepts the arguments {@link #ARG_GENDER}, {@link #ARG_ANIMACY}, * {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_TELEPHONE = "android.type.telephone"; /** * The text associated with this span is a URI (can be used for URLs and * email addresses). The full schema for URLs, which email addresses can * effectively be seen as a subset of, is: * protocol://username:password@domain:port/path?query_string#fragment_id * Hence populating just username and domain will read as an email address. * All arguments are optional, but at least one has to be provided: * {@link #ARG_PROTOCOL}, {@link #ARG_USERNAME}, {@link #ARG_PASSWORD}, * {@link #ARG_DOMAIN}, {@link #ARG_PORT}, {@link #ARG_PATH}, * {@link #ARG_QUERY_STRING} and {@link #ARG_FRAGMENT_ID}. * Also accepts the arguments {@link #ARG_GENDER}, {@link #ARG_ANIMACY}, * {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_ELECTRONIC = "android.type.electronic"; /** * The text associated with this span is an amount of money. Set the amount * with the same arguments as {@link #TYPE_DECIMAL}. * {@link #ARG_CURRENCY} is used to set the currency. {@link #ARG_QUANTITY} * is optional. * Also accepts the arguments {@link #ARG_GENDER}, {@link #ARG_ANIMACY}, * {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_MONEY = "android.type.money"; /** * The text associated with this span is a series of digits that have to be * read sequentially. The digits can be set with {@link #ARG_DIGITS}. * Also accepts the arguments {@link #ARG_GENDER}, {@link #ARG_ANIMACY}, * {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_DIGITS = "android.type.digits"; /** * The text associated with this span is a series of characters that have to * be read verbatim. The engine will attempt to read out any character like * punctuation but excluding whitespace. {@link #ARG_VERBATIM} is required. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. */ public static final String TYPE_VERBATIM = "android.type.verbatim"; /** * String argument supplying gender information. Can be any of * {@link #GENDER_NEUTRAL}, {@link #GENDER_MALE} and * {@link #GENDER_FEMALE}. */ public static final String ARG_GENDER = "android.arg.gender"; public static final String GENDER_NEUTRAL = "android.neutral"; public static final String GENDER_MALE = "android.male"; public static final String GENDER_FEMALE = "android.female"; /** * String argument supplying animacy information. Can be * {@link #ANIMACY_ANIMATE} or * {@link #ANIMACY_INANIMATE} */ public static final String ARG_ANIMACY = "android.arg.animacy"; public static final String ANIMACY_ANIMATE = "android.animate"; public static final String ANIMACY_INANIMATE = "android.inanimate"; /** * String argument supplying multiplicity information. Can be any of * {@link #MULTIPLICITY_SINGLE}, {@link #MULTIPLICITY_DUAL} and * {@link #MULTIPLICITY_PLURAL} */ public static final String ARG_MULTIPLICITY = "android.arg.multiplicity"; public static final String MULTIPLICITY_SINGLE = "android.single"; public static final String MULTIPLICITY_DUAL = "android.dual"; public static final String MULTIPLICITY_PLURAL = "android.plural"; /** * String argument supplying case information. Can be any of * {@link #CASE_NOMINATIVE}, {@link #CASE_ACCUSATIVE}, {@link #CASE_DATIVE}, * {@link #CASE_ABLATIVE}, {@link #CASE_GENITIVE}, {@link #CASE_VOCATIVE}, * {@link #CASE_LOCATIVE} and {@link #CASE_INSTRUMENTAL} */ public static final String ARG_CASE = "android.arg.case"; public static final String CASE_NOMINATIVE = "android.nominative"; public static final String CASE_ACCUSATIVE = "android.accusative"; public static final String CASE_DATIVE = "android.dative"; public static final String CASE_ABLATIVE = "android.ablative"; public static final String CASE_GENITIVE = "android.genitive"; public static final String CASE_VOCATIVE = "android.vocative"; public static final String CASE_LOCATIVE = "android.locative"; public static final String CASE_INSTRUMENTAL = "android.instrumental"; /** * String supplying the text to be synthesized. The synthesizer is free * to decide how to interpret the text. * Can be used with {@link #TYPE_TEXT}. */ public static final String ARG_TEXT = "android.arg.text"; /** * Argument used to specify a whole number. The value can be a string of * digits of any size optionally prefixed with a - or +. * Can be used with {@link #TYPE_CARDINAL} and {@link #TYPE_ORDINAL}. */ public static final String ARG_NUMBER = "android.arg.number"; /** * Argument used to specify the integer part of a decimal or fraction. The * value can be a string of digits of any size optionally prefixed with * a - or +. * Can be used with {@link #TYPE_DECIMAL} and {@link #TYPE_FRACTION}. */ public static final String ARG_INTEGER_PART = "android.arg.integer_part"; /** * Argument used to specify the fractional part of a decimal. The value can * be a string of digits of any size. * Can be used with {@link #TYPE_DECIMAL}. */ public static final String ARG_FRACTIONAL_PART = "android.arg.fractional_part"; /** * Argument used to choose the suffix (thousand, million, etc) that is used * to pronounce large amounts of money. For example it can be used to * disambiguate between "two thousand five hundred dollars" and * "two point five thousand dollars". * If implemented, engines should support at least "1000", "1000000", * "1000000000" and "1000000000000". * Example: if the {@link #ARG_INTEGER_PART} argument is "10", the * {@link #ARG_FRACTIONAL_PART} argument is "4", the {@link #ARG_QUANTITY} * argument is "1000" and the {@link #ARG_CURRENCY} argument is "usd", the * TTS engine may pronounce the span as "ten point four thousand dollars". * With the same example but with the quantity set as "1000000" the TTS * engine may pronounce the span as "ten point four million dollars". * Can be used with {@link #TYPE_MONEY}. */ public static final String ARG_QUANTITY = "android.arg.quantity"; /** * Argument used to specify the numerator of a fraction. The value can be a * string of digits of any size optionally prefixed with a - or +. * Can be used with {@link #TYPE_FRACTION}. */ public static final String ARG_NUMERATOR = "android.arg.numerator"; /** * Argument used to specify the denominator of a fraction. The value can be * a string of digits of any size optionally prefixed with a + or -. * Can be used with {@link #TYPE_FRACTION}. */ public static final String ARG_DENOMINATOR = "android.arg.denominator"; /** * Argument used to specify the unit of a measure. The unit should always be * specified in English singular form. Prefixes may be used. Engines will do * their best to pronounce them correctly in the language used. Engines are * expected to at least support the most common ones like "meter", "second", * "degree celsius" and "degree fahrenheit" with some common prefixes like * "milli" and "kilo". * Can be used with {@link #TYPE_MEASURE}. */ public static final String ARG_UNIT = "android.arg.unit"; /** * Argument used to specify the hours of a time. The hours should be * provided as an integer in the range from 0 up to and including 24. * Can be used with {@link #TYPE_TIME}. */ public static final String ARG_HOURS = "android.arg.hours"; /** * Argument used to specify the minutes of a time. The hours should be * provided as an integer in the range from 0 up to and including 59. * Can be used with {@link #TYPE_TIME}. */ public static final String ARG_MINUTES = "android.arg.minutes"; /** * Argument used to specify the weekday of a date. The value should be * provided as an integer and can be any of {@link #WEEKDAY_SUNDAY}, * {@link #WEEKDAY_MONDAY}, {@link #WEEKDAY_TUESDAY}, * {@link #WEEKDAY_WEDNESDAY}, {@link #WEEKDAY_THURSDAY}, * {@link #WEEKDAY_FRIDAY} and {@link #WEEKDAY_SATURDAY}. * Can be used with {@link #TYPE_DATE}. */ public static final String ARG_WEEKDAY = "android.arg.weekday"; public static final int WEEKDAY_SUNDAY = 1; public static final int WEEKDAY_MONDAY = 2; public static final int WEEKDAY_TUESDAY = 3; public static final int WEEKDAY_WEDNESDAY = 4; public static final int WEEKDAY_THURSDAY = 5; public static final int WEEKDAY_FRIDAY = 6; public static final int WEEKDAY_SATURDAY = 7; /** * Argument used to specify the day of the month of a date. The value should * be provided as an integer in the range from 1 up to and including 31. * Can be used with {@link #TYPE_DATE}. */ public static final String ARG_DAY = "android.arg.day"; /** * Argument used to specify the month of a date. The value should be * provided as an integer and can be any of {@link #MONTH_JANUARY}, * {@link #MONTH_FEBRUARY}, {@link #MONTH_MARCH}, {@link #MONTH_APRIL}, * {@link #MONTH_MAY}, {@link #MONTH_JUNE}, {@link #MONTH_JULY}, * {@link #MONTH_AUGUST}, {@link #MONTH_SEPTEMBER}, {@link #MONTH_OCTOBER}, * {@link #MONTH_NOVEMBER} and {@link #MONTH_DECEMBER}. * Can be used with {@link #TYPE_DATE}. */ public static final String ARG_MONTH = "android.arg.month"; public static final int MONTH_JANUARY = 0; public static final int MONTH_FEBRUARY = 1; public static final int MONTH_MARCH = 2; public static final int MONTH_APRIL = 3; public static final int MONTH_MAY = 4; public static final int MONTH_JUNE = 5; public static final int MONTH_JULY = 6; public static final int MONTH_AUGUST = 7; public static final int MONTH_SEPTEMBER = 8; public static final int MONTH_OCTOBER = 9; public static final int MONTH_NOVEMBER = 10; public static final int MONTH_DECEMBER = 11; /** * Argument used to specify the year of a date. The value should be provided * as a positive integer. * Can be used with {@link #TYPE_DATE}. */ public static final String ARG_YEAR = "android.arg.year"; /** * Argument used to specify the country code of a telephone number. Can be * a string of digits optionally prefixed with a "+". * Can be used with {@link #TYPE_TELEPHONE}. */ public static final String ARG_COUNTRY_CODE = "android.arg.country_code"; /** * Argument used to specify the main number part of a telephone number. Can * be a string of digits where the different parts of the telephone number * can be separated with a space, '-', '/' or '.'. * Can be used with {@link #TYPE_TELEPHONE}. */ public static final String ARG_NUMBER_PARTS = "android.arg.number_parts"; /** * Argument used to specify the extension part of a telephone number. Can be * a string of digits. * Can be used with {@link #TYPE_TELEPHONE}. */ public static final String ARG_EXTENSION = "android.arg.extension"; /** * Argument used to specify the protocol of a URI. Examples are "http" and * "ftp". * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_PROTOCOL = "android.arg.protocol"; /** * Argument used to specify the username part of a URI. Should be set as a * string. * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_USERNAME = "android.arg.username"; /** * Argument used to specify the password part of a URI. Should be set as a * string. * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_PASSWORD = "android.arg.password"; /** * Argument used to specify the domain part of a URI. For example * "source.android.com". * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_DOMAIN = "android.arg.domain"; /** * Argument used to specify the port number of a URI. Should be specified as * an integer. * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_PORT = "android.arg.port"; /** * Argument used to specify the path part of a URI. For example * "source/index.html". * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_PATH = "android.arg.path"; /** * Argument used to specify the query string of a URI. For example * "arg=value&argtwo=value". * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_QUERY_STRING = "android.arg.query_string"; /** * Argument used to specify the fragment id of a URI. Should be specified as * a string. * Can be used with {@link #TYPE_ELECTRONIC}. */ public static final String ARG_FRAGMENT_ID = "android.arg.fragment_id"; /** * Argument used to specify the currency. Should be a ISO4217 currency code, * e.g. "USD". * Can be used with {@link #TYPE_MONEY}. */ public static final String ARG_CURRENCY = "android.arg.money"; /** * Argument used to specify a string of digits. * Can be used with {@link #TYPE_DIGITS}. */ public static final String ARG_DIGITS = "android.arg.digits"; /** * Argument used to specify a string where the characters are read verbatim, * except whitespace. * Can be used with {@link #TYPE_VERBATIM}. */ public static final String ARG_VERBATIM = "android.arg.verbatim"; public TtsSpan(String type, PersistableBundle args) { mType = type; mArgs = args; } public TtsSpan(Parcel src) { mType = src.readString(); mArgs = src.readPersistableBundle(); } /** * Returns the type. * @return The type of this instance. */ public String getType() { return mType; } /** * Returns a bundle of the arguments set. * @return The bundle of the arguments set. */ public PersistableBundle getArgs() { return mArgs; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { writeToParcelInternal(dest, flags); } /** @hide */ public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mType); dest.writePersistableBundle(mArgs); } @Override public int getSpanTypeId() { return getSpanTypeIdInternal(); } /** @hide */ public int getSpanTypeIdInternal() { return TextUtils.TTS_SPAN; } /** * A simple builder for TtsSpans. * This builder can be used directly, but the more specific subclasses of * this builder like {@link TtsSpan.TextBuilder} and * {@link TtsSpan.CardinalBuilder} are likely more useful. * * This class uses generics so methods from this class can return instances * of its child classes, resulting in a fluent API (CRTP pattern). */ public static class Builder<C extends Builder<?>> { // Holds the type of this class. private final String mType; // Holds the arguments of this class. It only stores objects of type // String, Integer and Long. private PersistableBundle mArgs = new PersistableBundle(); public Builder(String type) { mType = type; } /** * Returns a TtsSpan built from the parameters set by the setter * methods. * @return A TtsSpan built with parameters of this builder. */ public TtsSpan build() { return new TtsSpan(mType, mArgs); } /** * Sets an argument to a string value. * @param arg The argument name. * @param value The value the argument should be set to. * @return This instance. */ @SuppressWarnings("unchecked") public C setStringArgument(String arg, String value) { mArgs.putString(arg, value); return (C) this; } /** * Sets an argument to an int value. * @param arg The argument name. * @param value The value the argument should be set to. */ @SuppressWarnings("unchecked") public C setIntArgument(String arg, int value) { mArgs.putInt(arg, value); return (C) this; } /** * Sets an argument to a long value. * @param arg The argument name. * @param value The value the argument should be set to. */ @SuppressWarnings("unchecked") public C setLongArgument(String arg, long value) { mArgs.putLong(arg, value); return (C) this; } } /** * A builder for TtsSpans, has setters for morphosyntactic features. * This builder can be used directly, but the more specific subclasses of * this builder like {@link TtsSpan.TextBuilder} and * {@link TtsSpan.CardinalBuilder} are likely more useful. */ public static class SemioticClassBuilder<C extends SemioticClassBuilder<?>> extends Builder<C> { public SemioticClassBuilder(String type) { super(type); } /** * Sets the gender information for this instance. * @param gender Can any of {@link #GENDER_NEUTRAL}, * {@link #GENDER_MALE} and {@link #GENDER_FEMALE}. * @return This instance. */ public C setGender(String gender) { return setStringArgument(TtsSpan.ARG_GENDER, gender); } /** * Sets the animacy information for this instance. * @param animacy Can be any of {@link #ANIMACY_ANIMATE} and * {@link #ANIMACY_INANIMATE}. * @return This instance. */ public C setAnimacy(String animacy) { return setStringArgument(TtsSpan.ARG_ANIMACY, animacy); } /** * Sets the multiplicity information for this instance. * @param multiplicity Can be any of * {@link #MULTIPLICITY_SINGLE}, {@link #MULTIPLICITY_DUAL} and * {@link #MULTIPLICITY_PLURAL}. * @return This instance. */ public C setMultiplicity(String multiplicity) { return setStringArgument(TtsSpan.ARG_MULTIPLICITY, multiplicity); } /** * Sets the grammatical case information for this instance. * @param grammaticalCase Can be any of {@link #CASE_NOMINATIVE}, * {@link #CASE_ACCUSATIVE}, {@link #CASE_DATIVE}, * {@link #CASE_ABLATIVE}, {@link #CASE_GENITIVE}, * {@link #CASE_VOCATIVE}, {@link #CASE_LOCATIVE} and * {@link #CASE_INSTRUMENTAL}. * @return This instance. */ public C setCase(String grammaticalCase) { return setStringArgument(TtsSpan.ARG_CASE, grammaticalCase); } } /** * A builder for TtsSpans of type {@link #TYPE_TEXT}. */ public static class TextBuilder extends SemioticClassBuilder<TextBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_TEXT}. */ public TextBuilder() { super(TtsSpan.TYPE_TEXT); } /** * Creates a TtsSpan of type {@link #TYPE_TEXT} and sets the * {@link #ARG_TEXT} argument. * @param text The text to be synthesized. * @see #setText(String) */ public TextBuilder(String text) { this(); setText(text); } /** * Sets the {@link #ARG_TEXT} argument, the text to be synthesized. * @param text The string that will be synthesized. * @return This instance. */ public TextBuilder setText(String text) { return setStringArgument(TtsSpan.ARG_TEXT, text); } } /** * A builder for TtsSpans of type {@link #TYPE_CARDINAL}. */ public static class CardinalBuilder extends SemioticClassBuilder<CardinalBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_CARDINAL}. */ public CardinalBuilder() { super(TtsSpan.TYPE_CARDINAL); } /** * Creates a TtsSpan of type {@link #TYPE_CARDINAL} and sets the * {@link #ARG_NUMBER} argument. * @param number The number to synthesize. * @see #setNumber(long) */ public CardinalBuilder(long number) { this(); setNumber(number); } /** * Creates a TtsSpan of type {@link #TYPE_CARDINAL} and sets the * {@link #ARG_NUMBER} argument. * @param number The number to synthesize. * @see #setNumber(String) */ public CardinalBuilder(String number) { this(); setNumber(number); } /** * Convenience method that converts the number to a String and set it to * the value for {@link #ARG_NUMBER}. * @param number The number that will be synthesized. * @return This instance. */ public CardinalBuilder setNumber(long number) { return setNumber(String.valueOf(number)); } /** * Sets the {@link #ARG_NUMBER} argument. * @param number A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public CardinalBuilder setNumber(String number) { return setStringArgument(TtsSpan.ARG_NUMBER, number); } } /** * A builder for TtsSpans of type {@link #TYPE_ORDINAL}. */ public static class OrdinalBuilder extends SemioticClassBuilder<OrdinalBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_ORDINAL}. */ public OrdinalBuilder() { super(TtsSpan.TYPE_ORDINAL); } /** * Creates a TtsSpan of type {@link #TYPE_ORDINAL} and sets the * {@link #ARG_NUMBER} argument. * @param number The ordinal number to synthesize. * @see #setNumber(long) */ public OrdinalBuilder(long number) { this(); setNumber(number); } /** * Creates a TtsSpan of type {@link #TYPE_ORDINAL} and sets the * {@link #ARG_NUMBER} argument. * @param number The number to synthesize. * @see #setNumber(String) */ public OrdinalBuilder(String number) { this(); setNumber(number); } /** * Convenience method that converts the number to a String and sets it * to the value for {@link #ARG_NUMBER}. * @param number The ordinal number that will be synthesized. * @return This instance. */ public OrdinalBuilder setNumber(long number) { return setNumber(String.valueOf(number)); } /** * Sets the {@link #ARG_NUMBER} argument. * @param number A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public OrdinalBuilder setNumber(String number) { return setStringArgument(TtsSpan.ARG_NUMBER, number); } } /** * A builder for TtsSpans of type {@link #TYPE_DECIMAL}. */ public static class DecimalBuilder extends SemioticClassBuilder<DecimalBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_DECIMAL}. */ public DecimalBuilder() { super(TtsSpan.TYPE_DECIMAL); } /** * Creates a TtsSpan of type {@link #TYPE_DECIMAL} and sets the * {@link #ARG_INTEGER_PART} and {@link #ARG_FRACTIONAL_PART} arguments. * @see {@link #setArgumentsFromDouble(double, int, int) */ public DecimalBuilder(double number, int minimumFractionDigits, int maximumFractionDigits) { this(); setArgumentsFromDouble(number, minimumFractionDigits, maximumFractionDigits); } /** * Creates a TtsSpan of type {@link #TYPE_DECIMAL} and sets the * {@link #ARG_INTEGER_PART} and {@link #ARG_FRACTIONAL_PART} arguments. */ public DecimalBuilder(String integerPart, String fractionalPart) { this(); setIntegerPart(integerPart); setFractionalPart(fractionalPart); } /** * Convenience method takes a double and a maximum number of fractional * digits, it sets the {@link #ARG_INTEGER_PART} and * {@link #ARG_FRACTIONAL_PART} arguments. * @param number The number to be synthesized. * @param minimumFractionDigits The minimum number of fraction digits * that are pronounced. * @param maximumFractionDigits The maximum number of fraction digits * that are pronounced. If maximumFractionDigits < * minimumFractionDigits then minimumFractionDigits will be assumed * to be equal to maximumFractionDigits. * @return This instance. */ public DecimalBuilder setArgumentsFromDouble( double number, int minimumFractionDigits, int maximumFractionDigits) { // Format double. NumberFormat formatter = NumberFormat.getInstance(Locale.US); formatter.setMinimumFractionDigits(maximumFractionDigits); formatter.setMaximumFractionDigits(maximumFractionDigits); formatter.setGroupingUsed(false); String str = formatter.format(number); // Split at decimal point. int i = str.indexOf('.'); if (i >= 0) { setIntegerPart(str.substring(0, i)); setFractionalPart(str.substring(i + 1)); } else { setIntegerPart(str); } return this; } /** * Convenience method that converts the number to a String and sets it * to the value for {@link #ARG_INTEGER_PART}. * @param integerPart The integer part of the decimal. * @return This instance. */ public DecimalBuilder setIntegerPart(long integerPart) { return setIntegerPart(String.valueOf(integerPart)); } /** * Sets the {@link #ARG_INTEGER_PART} argument. * @param integerPart A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public DecimalBuilder setIntegerPart(String integerPart) { return setStringArgument(TtsSpan.ARG_INTEGER_PART, integerPart); } /** * Sets the {@link #ARG_FRACTIONAL_PART} argument. * @param fractionalPart A non-empty string of digits. * @return This instance. */ public DecimalBuilder setFractionalPart(String fractionalPart) { return setStringArgument(TtsSpan.ARG_FRACTIONAL_PART, fractionalPart); } } /** * A builder for TtsSpans of type {@link #TYPE_FRACTION}. */ public static class FractionBuilder extends SemioticClassBuilder<FractionBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_FRACTION}. */ public FractionBuilder() { super(TtsSpan.TYPE_FRACTION); } /** * Creates a TtsSpan of type {@link #TYPE_FRACTION} and sets the * {@link #ARG_INTEGER_PART}, {@link #ARG_NUMERATOR}, and * {@link #ARG_DENOMINATOR} arguments. */ public FractionBuilder(long integerPart, long numerator, long denominator) { this(); setIntegerPart(integerPart); setNumerator(numerator); setDenominator(denominator); } /** * Convenience method that converts the integer to a String and sets the * argument {@link #ARG_NUMBER}. * @param integerPart The integer part. * @return This instance. */ public FractionBuilder setIntegerPart(long integerPart) { return setIntegerPart(String.valueOf(integerPart)); } /** * Sets the {@link #ARG_INTEGER_PART} argument. * @param integerPart A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public FractionBuilder setIntegerPart(String integerPart) { return setStringArgument(TtsSpan.ARG_INTEGER_PART, integerPart); } /** * Convenience method that converts the numerator to a String and sets * the argument {@link #ARG_NUMERATOR}. * @param numerator The numerator. * @return This instance. */ public FractionBuilder setNumerator(long numerator) { return setNumerator(String.valueOf(numerator)); } /** * Sets the {@link #ARG_NUMERATOR} argument. * @param numerator A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public FractionBuilder setNumerator(String numerator) { return setStringArgument(TtsSpan.ARG_NUMERATOR, numerator); } /** * Convenience method that converts the denominator to a String and sets * the argument {@link #ARG_DENOMINATOR}. * @param denominator The denominator. * @return This instance. */ public FractionBuilder setDenominator(long denominator) { return setDenominator(String.valueOf(denominator)); } /** * Sets the {@link #ARG_DENOMINATOR} argument. * @param denominator A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public FractionBuilder setDenominator(String denominator) { return setStringArgument(TtsSpan.ARG_DENOMINATOR, denominator); } } /** * A builder for TtsSpans of type {@link #TYPE_MEASURE}. */ public static class MeasureBuilder extends SemioticClassBuilder<MeasureBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_MEASURE}. */ public MeasureBuilder() { super(TtsSpan.TYPE_MEASURE); } /** * Convenience method that converts the number to a String and set it to * the value for {@link #ARG_NUMBER}. * @param number The amount of the measure. * @return This instance. */ public MeasureBuilder setNumber(long number) { return setNumber(String.valueOf(number)); } /** * Sets the {@link #ARG_NUMBER} argument. * @param number A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public MeasureBuilder setNumber(String number) { return setStringArgument(TtsSpan.ARG_NUMBER, number); } /** * Convenience method that converts the integer part to a String and set * it to the value for {@link #ARG_INTEGER_PART}. * @param integerPart The integer part of a decimal or fraction. * @return This instance. */ public MeasureBuilder setIntegerPart(long integerPart) { return setNumber(String.valueOf(integerPart)); } /** * Sets the {@link #ARG_INTEGER_PART} argument. * @param integerPart The integer part of a decimal or fraction; a * non-empty string of digits with an optional * leading + or -. * @return This instance. */ public MeasureBuilder setIntegerPart(String integerPart) { return setStringArgument(TtsSpan.ARG_INTEGER_PART, integerPart); } /** * Sets the {@link #ARG_FRACTIONAL_PART} argument. * @param fractionalPart The fractional part of a decimal; a non-empty * string of digits with an optional leading + or -. * @return This instance. */ public MeasureBuilder setFractionalPart(String fractionalPart) { return setStringArgument(TtsSpan.ARG_FRACTIONAL_PART, fractionalPart); } /** * Convenience method that converts the numerator to a String and set it * to the value for {@link #ARG_NUMERATOR}. * @param numerator The numerator of a fraction. * @return This instance. */ public MeasureBuilder setNumerator(long numerator) { return setNumerator(String.valueOf(numerator)); } /** * Sets the {@link #ARG_NUMERATOR} argument. * @param numerator The numerator of a fraction; a non-empty string of * digits with an optional leading + or -. * @return This instance. */ public MeasureBuilder setNumerator(String numerator) { return setStringArgument(TtsSpan.ARG_NUMERATOR, numerator); } /** * Convenience method that converts the denominator to a String and set * it to the value for {@link #ARG_DENOMINATOR}. * @param denominator The denominator of a fraction. * @return This instance. */ public MeasureBuilder setDenominator(long denominator) { return setDenominator(String.valueOf(denominator)); } /** * Sets the {@link #ARG_DENOMINATOR} argument. * @param denominator The denominator of a fraction; a non-empty string * of digits with an optional leading + or -. * @return This instance. */ public MeasureBuilder setDenominator(String denominator) { return setStringArgument(TtsSpan.ARG_DENOMINATOR, denominator); } /** * Sets the {@link #ARG_UNIT} argument. * @param unit The unit of the measure. * @return This instance. * @see {@link TtsSpan.ARG_UNIT} */ public MeasureBuilder setUnit(String unit) { return setStringArgument(TtsSpan.ARG_UNIT, unit); } } /** * A builder for TtsSpans of type {@link #TYPE_TIME}. */ public static class TimeBuilder extends SemioticClassBuilder<TimeBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_TIME}. */ public TimeBuilder() { super(TtsSpan.TYPE_TIME); } /** * Creates a builder for a TtsSpan of type {@link #TYPE_TIME} and * sets the {@link #ARG_HOURS} and {@link #ARG_MINUTES} arguments. */ public TimeBuilder(int hours, int minutes) { this(); setHours(hours); setMinutes(minutes); } /** * Sets the {@link #ARG_HOURS} argument. * @param hours The value to be set for hours. See {@link #ARG_HOURS}. * @return This instance. * @see {@link #ARG_HOURS} */ public TimeBuilder setHours(int hours) { return setIntArgument(TtsSpan.ARG_HOURS, hours); } /** * Sets the {@link #ARG_MINUTES} argument. * @param minutes The value to be set for minutes. See * {@link #ARG_MINUTES}. * @return This instance. * @see {@link #ARG_MINUTES} */ public TimeBuilder setMinutes(int minutes) { return setIntArgument(TtsSpan.ARG_MINUTES, minutes); } } /** * A builder for TtsSpans of type {@link #TYPE_DATE}. */ public static class DateBuilder extends SemioticClassBuilder<DateBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_DATE}. */ public DateBuilder() { super(TtsSpan.TYPE_DATE); } /** * Creates a builder for a TtsSpan of type {@link #TYPE_TIME} and * possibly sets the {@link #ARG_WEEKDAY}, {@link #ARG_DAY}, * {@link #ARG_MONTH} and {@link #ARG_YEAR} arguments. Pass null to any * argument to leave it unset. */ public DateBuilder(Integer weekday, Integer day, Integer month, Integer year) { this(); if (weekday != null) { setWeekday(weekday); } if (day != null) { setDay(day); } if (month != null) { setMonth(month); } if (year != null) { setYear(year); } } /** * Sets the {@link #ARG_WEEKDAY} argument. * @param weekday The value to be set for weekday. See * {@link #ARG_WEEKDAY}. * @return This instance. * @see {@link #ARG_WEEKDAY} */ public DateBuilder setWeekday(int weekday) { return setIntArgument(TtsSpan.ARG_WEEKDAY, weekday); } /** * Sets the {@link #ARG_DAY} argument. * @param day The value to be set for day. See {@link #ARG_DAY}. * @return This instance. * @see {@link #ARG_DAY} */ public DateBuilder setDay(int day) { return setIntArgument(TtsSpan.ARG_DAY, day); } /** * Sets the {@link #ARG_MONTH} argument. * @param month The value to be set for month. See {@link #ARG_MONTH}. * @return This instance. * @see {@link #ARG_MONTH} */ public DateBuilder setMonth(int month) { return setIntArgument(TtsSpan.ARG_MONTH, month); } /** * Sets the {@link #ARG_YEAR} argument. * @param year The value to be set for year. See {@link #ARG_YEAR}. * @return This instance. * @see {@link #ARG_YEAR} */ public DateBuilder setYear(int year) { return setIntArgument(TtsSpan.ARG_YEAR, year); } } /** * A builder for TtsSpans of type {@link #TYPE_MONEY}. */ public static class MoneyBuilder extends SemioticClassBuilder<MoneyBuilder> { /** * Creates a TtsSpan of type {@link #TYPE_MONEY}. */ public MoneyBuilder() { super(TtsSpan.TYPE_MONEY); } /** * Convenience method that converts the number to a String and set it to * the value for {@link #ARG_INTEGER_PART}. * @param integerPart The integer part of the amount. * @return This instance. */ public MoneyBuilder setIntegerPart(long integerPart) { return setIntegerPart(String.valueOf(integerPart)); } /** * Sets the {@link #ARG_INTEGER_PART} argument. * @param integerPart A non-empty string of digits with an optional * leading + or -. * @return This instance. */ public MoneyBuilder setIntegerPart(String integerPart) { return setStringArgument(TtsSpan.ARG_INTEGER_PART, integerPart); } /** * Sets the {@link #ARG_FRACTIONAL_PART} argument. * @param fractionalPart Can be a string of digits of any size. * @return This instance. */ public MoneyBuilder setFractionalPart(String fractionalPart) { return setStringArgument(TtsSpan.ARG_FRACTIONAL_PART, fractionalPart); } /** * Sets the {@link #ARG_CURRENCY} argument. * @param currency Should be a ISO4217 currency code, e.g. "USD". * @return This instance. */ public MoneyBuilder setCurrency(String currency) { return setStringArgument(TtsSpan.ARG_CURRENCY, currency); } /** * Sets the {@link #ARG_QUANTITY} argument. * @param quantity * @return This instance. */ public MoneyBuilder setQuantity(String quantity) { return setStringArgument(TtsSpan.ARG_QUANTITY, quantity); } } /** * A builder for TtsSpans of type {@link #TYPE_TELEPHONE}. */ public static class TelephoneBuilder extends SemioticClassBuilder<TelephoneBuilder> { /** * Creates a TtsSpan of type {@link #TYPE_TELEPHONE}. */ public TelephoneBuilder() { super(TtsSpan.TYPE_TELEPHONE); } /** * Creates a TtsSpan of type {@link #TYPE_TELEPHONE} and sets the * {@link #ARG_NUMBER_PARTS} argument. */ public TelephoneBuilder(String numberParts) { this(); setNumberParts(numberParts); } /** * Sets the {@link #ARG_COUNTRY_CODE} argument. * @param countryCode The country code can be a series of digits * optionally prefixed with a "+". * @return This instance. */ public TelephoneBuilder setCountryCode(String countryCode) { return setStringArgument(TtsSpan.ARG_COUNTRY_CODE, countryCode); } /** * Sets the {@link #ARG_NUMBER_PARTS} argument. * @param numberParts The main telephone number. Can be a series of * digits and letters separated by spaces, "/", "-" or ".". * @return This instance. */ public TelephoneBuilder setNumberParts(String numberParts) { return setStringArgument(TtsSpan.ARG_NUMBER_PARTS, numberParts); } /** * Sets the {@link #ARG_EXTENSION} argument. * @param extension The extension can be a series of digits. * @return This instance. */ public TelephoneBuilder setExtension(String extension) { return setStringArgument(TtsSpan.ARG_EXTENSION, extension); } } /** * A builder for TtsSpans of type {@link #TYPE_ELECTRONIC}. */ public static class ElectronicBuilder extends SemioticClassBuilder<ElectronicBuilder> { /** * Creates a TtsSpan of type {@link #TYPE_ELECTRONIC}. */ public ElectronicBuilder() { super(TtsSpan.TYPE_ELECTRONIC); } /** * Sets the {@link #ARG_USERNAME} and {@link #ARG_DOMAIN} * arguments, representing an email address. * @param username The part before the @ in the email address. * @param domain The part after the @ in the email address. * @return This instance. */ public ElectronicBuilder setEmailArguments(String username, String domain) { return setDomain(domain).setUsername(username); } /** * Sets the {@link #ARG_PROTOCOL} argument. * @param protocol The protocol of the URI. Examples are "http" and * "ftp". * @return This instance. */ public ElectronicBuilder setProtocol(String protocol) { return setStringArgument(TtsSpan.ARG_PROTOCOL, protocol); } /** * Sets the {@link #ARG_USERNAME} argument. * @return This instance. */ public ElectronicBuilder setUsername(String username) { return setStringArgument(TtsSpan.ARG_USERNAME, username); } /** * Sets the {@link #ARG_PASSWORD} argument. * @return This instance. */ public ElectronicBuilder setPassword(String password) { return setStringArgument(TtsSpan.ARG_PASSWORD, password); } /** * Sets the {@link #ARG_DOMAIN} argument. * @param domain The domain, for example "source.android.com". * @return This instance. */ public ElectronicBuilder setDomain(String domain) { return setStringArgument(TtsSpan.ARG_DOMAIN, domain); } /** * Sets the {@link #ARG_PORT} argument. * @return This instance. */ public ElectronicBuilder setPort(int port) { return setIntArgument(TtsSpan.ARG_PORT, port); } /** * Sets the {@link #ARG_PATH} argument. * @param path For example "source/index.html". * @return This instance. */ public ElectronicBuilder setPath(String path) { return setStringArgument(TtsSpan.ARG_PATH, path); } /** * Sets the {@link #ARG_QUERY_STRING} argument. * @param queryString For example "arg=value&argtwo=value". * @return This instance. */ public ElectronicBuilder setQueryString(String queryString) { return setStringArgument(TtsSpan.ARG_QUERY_STRING, queryString); } /** * Sets the {@link #ARG_FRAGMENT_ID} argument. * @return This instance. */ public ElectronicBuilder setFragmentId(String fragmentId) { return setStringArgument(TtsSpan.ARG_FRAGMENT_ID, fragmentId); } } /** * A builder for TtsSpans of type {@link #TYPE_DIGITS}. */ public static class DigitsBuilder extends SemioticClassBuilder<DigitsBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_DIGITS}. */ public DigitsBuilder() { super(TtsSpan.TYPE_DIGITS); } /** * Creates a builder for a TtsSpan of type {@link #TYPE_DIGITS} * and sets the {@link #ARG_DIGITS} argument. */ public DigitsBuilder(String digits) { this(); setDigits(digits); } /** * Sets the {@link #ARG_DIGITS} argument. * @param digits A string of digits. * @return This instance. */ public DigitsBuilder setDigits(String digits) { return setStringArgument(TtsSpan.ARG_DIGITS, digits); } } /** * A builder for TtsSpans of type {@link #TYPE_VERBATIM}. */ public static class VerbatimBuilder extends SemioticClassBuilder<VerbatimBuilder> { /** * Creates a builder for a TtsSpan of type {@link #TYPE_VERBATIM}. */ public VerbatimBuilder() { super(TtsSpan.TYPE_VERBATIM); } /** * Creates a builder for a TtsSpan of type {@link #TYPE_VERBATIM} * and sets the {@link #ARG_VERBATIM} argument. */ public VerbatimBuilder(String verbatim) { this(); setVerbatim(verbatim); } /** * Sets the {@link #ARG_VERBATIM} argument. * @param verbatim A string of characters that will be read verbatim, * except whitespace. * @return This instance. */ public VerbatimBuilder setVerbatim(String verbatim) { return setStringArgument(TtsSpan.ARG_VERBATIM, verbatim); } } }