Add a Duration type and ARG_SECONDS to TtsSpan
This will enable more understandable speech output of durations
for screen readers, since by default numbers like "4:33" will
typically be announced as times, but depending on the context the
ideal speech may instead be "4 minutes 33 seconds".
This will also move developers away from content descriptions,
which reduce app resources used and avoids conflicts between
accessibility events (Example: simultaneous content description
and text changes in stopwatches/timers).
Flag: com.android.text.flags.tts_span_duration
Bug: 337103893
Test: atest TtsSpanTest, manual
Change-Id: I7e08eeaa67b0d1dbcf31dacf1465cb427dfa80c6
diff --git a/core/api/current.txt b/core/api/current.txt
index 53da338..1ff211d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -49238,6 +49238,7 @@
field public static final String ARG_PROTOCOL = "android.arg.protocol";
field public static final String ARG_QUANTITY = "android.arg.quantity";
field public static final String ARG_QUERY_STRING = "android.arg.query_string";
+ field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String ARG_SECONDS = "android.arg.seconds";
field public static final String ARG_TEXT = "android.arg.text";
field public static final String ARG_UNIT = "android.arg.unit";
field public static final String ARG_USERNAME = "android.arg.username";
@@ -49274,6 +49275,7 @@
field public static final String TYPE_DATE = "android.type.date";
field public static final String TYPE_DECIMAL = "android.type.decimal";
field public static final String TYPE_DIGITS = "android.type.digits";
+ field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String TYPE_DURATION = "android.type.duration";
field public static final String TYPE_ELECTRONIC = "android.type.electronic";
field public static final String TYPE_FRACTION = "android.type.fraction";
field public static final String TYPE_MEASURE = "android.type.measure";
@@ -49333,6 +49335,13 @@
method public android.text.style.TtsSpan.DigitsBuilder setDigits(String);
}
+ @FlaggedApi("com.android.text.flags.tts_span_duration") public static class TtsSpan.DurationBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DurationBuilder> {
+ ctor @FlaggedApi("com.android.text.flags.tts_span_duration") public TtsSpan.DurationBuilder();
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setHours(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setMinutes(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setSeconds(int);
+ }
+
public static class TtsSpan.ElectronicBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.ElectronicBuilder> {
ctor public TtsSpan.ElectronicBuilder();
method public android.text.style.TtsSpan.ElectronicBuilder setDomain(String);
@@ -49415,6 +49424,7 @@
ctor public TtsSpan.TimeBuilder(int, int);
method public android.text.style.TtsSpan.TimeBuilder setHours(int);
method public android.text.style.TtsSpan.TimeBuilder setMinutes(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(int);
}
public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.VerbatimBuilder> {
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index ec5b488..09b2201 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -188,3 +188,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "tts_span_duration"
+ namespace: "text"
+ description: "Feature flag for adding a TYPE_DURATION to TtsSpan"
+ bug: "337103893"
+}
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index f9a1a0d..b7b8f0b1 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -16,6 +16,10 @@
package android.text.style;
+import static com.android.text.flags.Flags.FLAG_TTS_SPAN_DURATION;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.text.ParcelableSpan;
@@ -112,6 +116,16 @@
public static final String TYPE_TIME = "android.type.time";
/**
+ * The text associated with this span is a duration, consisting of a number of
+ * hours, minutes, and seconds specified with {@link #ARG_HOURS},
+ * {@link #ARG_MINUTES}, and {@link #ARG_SECONDS}. This is different from {@link #TYPE_TIME}.
+ * This should be used to convey an interval of time, while {@link #TYPE_TIME} should be used to
+ * convey a particular moment in time, such as a clock time.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static final String TYPE_DURATION = "android.type.duration";
+
+ /**
* 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.
@@ -302,13 +316,21 @@
public static final String ARG_HOURS = "android.arg.hours";
/**
- * Argument used to specify the minutes of a time. The hours should be
+ * Argument used to specify the minutes of a time. The minutes 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 seconds of a time or duration. The seconds should be
+ * provided as an integer in the range from 0 up to and including 59.
+ * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static final String ARG_SECONDS = "android.arg.seconds";
+
+ /**
* 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},
@@ -1132,9 +1154,70 @@
public TimeBuilder setMinutes(int minutes) {
return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
}
+
+ /**
+ * Sets the {@link #ARG_SECONDS} argument.
+ * @param seconds The value to be set for seconds.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public TimeBuilder setSeconds(int seconds) {
+ return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+ }
}
/**
+ * A builder for TtsSpans of type {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static class DurationBuilder
+ extends SemioticClassBuilder<DurationBuilder> {
+
+ /**
+ * Creates a builder for a TtsSpan of type {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public DurationBuilder() {
+ super(TtsSpan.TYPE_DURATION);
+ }
+
+ /**
+ * Sets the {@link #ARG_HOURS} argument.
+ * @param hours The value to be set for hours.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setHours(int hours) {
+ return setIntArgument(TtsSpan.ARG_HOURS, hours);
+ }
+
+ /**
+ * Sets the {@link #ARG_MINUTES} argument.
+ * @param minutes The value to be set for minutes.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setMinutes(int minutes) {
+ return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
+ }
+
+ /**
+ * Sets the {@link #ARG_SECONDS} argument.
+ * @param seconds The value to be set for seconds.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setSeconds(int seconds) {
+ return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+ }
+ }
+
+
+ /**
* A builder for TtsSpans of type {@link #TYPE_DATE}.
*/
public static class DateBuilder