Support for CharSequences in the V1 API.

Two newly deprecated methods:
  - TextToSpeech.speak (over TextToSpeech.speak with mandatory utteranceId)
  - SynthesisRequest.getText (over SynthesisRequest.getCharSequenceText)

Change-Id: I8a75ed335c91074c72d6ef374ff8b9c79a7c208d
diff --git a/api/current.txt b/api/current.txt
index 1912a6f..166beb8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26580,13 +26580,15 @@
 
   public final class SynthesisRequest {
     ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
+    ctor public SynthesisRequest(java.lang.CharSequence, android.os.Bundle);
     method public int getCallerUid();
+    method public java.lang.CharSequence getCharSequenceText();
     method public java.lang.String getCountry();
     method public java.lang.String getLanguage();
     method public android.os.Bundle getParams();
     method public int getPitch();
     method public int getSpeechRate();
-    method public java.lang.String getText();
+    method public deprecated java.lang.String getText();
     method public java.lang.String getVariant();
   }
 
@@ -26596,7 +26598,9 @@
     method public int addEarcon(java.lang.String, java.lang.String, int);
     method public int addEarcon(java.lang.String, java.lang.String);
     method public int addSpeech(java.lang.String, java.lang.String, int);
+    method public int addSpeech(java.lang.CharSequence, java.lang.String, int);
     method public int addSpeech(java.lang.String, java.lang.String);
+    method public int addSpeech(java.lang.CharSequence, java.lang.String);
     method public boolean areDefaultsEnforced();
     method public java.lang.String getDefaultEngine();
     method public java.util.Locale getDefaultLanguage();
@@ -26606,7 +26610,9 @@
     method public static int getMaxSpeechInputLength();
     method public int isLanguageAvailable(java.util.Locale);
     method public boolean isSpeaking();
-    method public int playEarcon(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public int playEarcon(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
+    method public deprecated int playEarcon(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
     method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
     method public deprecated int setEngineByPackageName(java.lang.String);
     method public int setLanguage(java.util.Locale);
@@ -26615,9 +26621,11 @@
     method public int setPitch(float);
     method public int setSpeechRate(float);
     method public void shutdown();
-    method public int speak(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public int speak(java.lang.CharSequence, int, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
+    method public deprecated int speak(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
     method public int stop();
-    method public int synthesizeToFile(java.lang.String, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
+    method public deprecated int synthesizeToFile(java.lang.String, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
+    method public int synthesizeToFile(java.lang.CharSequence, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String, java.lang.String);
     field public static final java.lang.String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_INVALID_REQUEST = -8; // 0xfffffff8
diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl
index 4d322df..694f25a 100644
--- a/core/java/android/speech/tts/ITextToSpeechService.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechService.aidl
@@ -36,8 +36,10 @@
      * @param text The text to synthesize.
      * @param queueMode Determines what to do to requests already in the queue.
      * @param param Request parameters.
+     * @param utteranceId Unique identifier of synthesized utterance.
      */
-    int speak(in IBinder callingInstance, in String text, in int queueMode, in Bundle params);
+    int speak(in IBinder callingInstance, in CharSequence text, in int queueMode, in Bundle params,
+            String utteranceId);
 
     /**
      * Tells the engine to synthesize some speech and write it to a file.
@@ -47,10 +49,11 @@
      * @param text The text to synthesize.
      * @param fileDescriptor The file descriptor to write the synthesized audio to. Has to be
               writable.
+     * @param utteranceId Unique identifier of synthesized utterance.
      * @param param Request parameters.
      */
-    int synthesizeToFileDescriptor(in IBinder callingInstance, in String text,
-        in ParcelFileDescriptor fileDescriptor, in Bundle params);
+    int synthesizeToFileDescriptor(in IBinder callingInstance, in CharSequence text,
+        in ParcelFileDescriptor fileDescriptor, in Bundle params, String utteranceId);
 
     /**
      * Plays an existing audio resource.
@@ -59,9 +62,11 @@
      *        TextToSpeech object.
      * @param audioUri URI for the audio resource (a file or android.resource URI)
      * @param queueMode Determines what to do to requests already in the queue.
+     * @param utteranceId Unique identifier of synthesized utterance.
      * @param param Request parameters.
      */
-    int playAudio(in IBinder callingInstance, in Uri audioUri, in int queueMode, in Bundle params);
+    int playAudio(in IBinder callingInstance, in Uri audioUri, in int queueMode, in Bundle params,
+            String utteranceId);
 
     /**
      * Plays silence.
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index 12a026b..eaacc06 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -34,7 +34,7 @@
  * and {@link TextToSpeech#synthesizeToFile}.
  */
 public final class SynthesisRequest {
-    private final String mText;
+    private final CharSequence mText;
     private final Bundle mParams;
     private String mLanguage;
     private String mCountry;
@@ -49,10 +49,25 @@
         mParams = new Bundle(params);
     }
 
+    public SynthesisRequest(CharSequence text, Bundle params) {
+        mText = text;
+        // Makes a copy of params.
+        mParams = new Bundle(params);
+    }
+
+    /**
+     * Gets the text which should be synthesized.
+     * @deprecated As of API level 20, replaced by {@link #getCharSequenceText}.
+     */
+    @Deprecated
+    public String getText() {
+        return mText.toString();
+    }
+
     /**
      * Gets the text which should be synthesized.
      */
-    public String getText() {
+    public CharSequence getCharSequenceText() {
         return mText;
     }
 
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 0d2b69b..457be22 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -593,7 +593,7 @@
     // too.
     private final boolean mUseFallback;
     private final Map<String, Uri> mEarcons;
-    private final Map<String, Uri> mUtterances;
+    private final Map<CharSequence, Uri> mUtterances;
     private final Bundle mParams = new Bundle();
     private final TtsEngines mEnginesHelper;
     private final String mPackageName;
@@ -644,7 +644,7 @@
         mUseFallback = useFallback;
 
         mEarcons = new HashMap<String, Uri>();
-        mUtterances = new HashMap<String, Uri>();
+        mUtterances = new HashMap<CharSequence, Uri>();
         mUtteranceProgressListener = null;
 
         mEnginesHelper = new TtsEngines(mContext);
@@ -825,6 +825,40 @@
     }
 
     /**
+     * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
+     * and a sound resource in a package. After a call to this method, subsequent calls to
+     * {@link #speak(String, int, HashMap)} will play the specified sound resource
+     * if it is available, or synthesize the text it is missing.
+     *
+     * @param text
+     *            The string of text. Example: <code>"south_south_east"</code>
+     *
+     * @param packagename
+     *            Pass the packagename of the application that contains the
+     *            resource. If the resource is in your own application (this is
+     *            the most common case), then put the packagename of your
+     *            application here.<br/>
+     *            Example: <b>"com.google.marvin.compass"</b><br/>
+     *            The packagename can be found in the AndroidManifest.xml of
+     *            your application.
+     *            <p>
+     *            <code>&lt;manifest xmlns:android=&quot;...&quot;
+     *      package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
+     *            </p>
+     *
+     * @param resourceId
+     *            Example: <code>R.raw.south_south_east</code>
+     *
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+     */
+    public int addSpeech(CharSequence text, String packagename, int resourceId) {
+        synchronized (mStartLock) {
+            mUtterances.put(text, makeResourceUri(packagename, resourceId));
+            return SUCCESS;
+        }
+    }
+
+    /**
      * Adds a mapping between a string of text and a sound file. Using this, it
      * is possible to add custom pronounciations for a string of text.
      * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
@@ -846,6 +880,28 @@
         }
     }
 
+    /**
+     * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
+     * Using this, it is possible to add custom pronounciations for a string of text.
+     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+     * will play the specified sound resource if it is available, or synthesize the text it is
+     * missing.
+     *
+     * @param text
+     *            The string of text. Example: <code>"south_south_east"</code>
+     * @param filename
+     *            The full path to the sound file (for example:
+     *            "/sdcard/mysounds/hello.wav")
+     *
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+     */
+    public int addSpeech(CharSequence text, String filename) {
+        synchronized (mStartLock) {
+            mUtterances.put(text, Uri.parse(filename));
+            return SUCCESS;
+        }
+    }
+
 
     /**
      * Adds a mapping between a string of text and a sound resource in a
@@ -910,6 +966,51 @@
     }
 
     /**
+     * Speaks the text using the specified queuing strategy and speech parameters, the text may
+     * be spanned with TtsSpans.
+     * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+     * requests and then returns. The synthesis might not have finished (or even started!) at the
+     * time when this method returns. In order to reliably detect errors during synthesis,
+     * we recommend setting an utterance progress listener (see
+     * {@link #setOnUtteranceProgressListener}) and using the
+     * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+     *
+     * @param text The string of text to be spoken. No longer than
+     *            {@link #getMaxSpeechInputLength()} characters.
+     * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+     * @param params Parameters for the request. Can be null.
+     *            Supported parameter names:
+     *            {@link Engine#KEY_PARAM_STREAM},
+     *            {@link Engine#KEY_PARAM_VOLUME},
+     *            {@link Engine#KEY_PARAM_PAN}.
+     *            Engine specific parameters may be passed in but the parameter keys
+     *            must be prefixed by the name of the engine they are intended for. For example
+     *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+     *            engine named "com.svox.pico" if it is being used.
+     * @param utteranceId An unique identifier for this request.
+     *
+     * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
+     */
+    public int speak(final CharSequence text,
+                     final int queueMode,
+                     final HashMap<String, String> params,
+                     final String utteranceId) {
+        return runAction(new Action<Integer>() {
+            @Override
+            public Integer run(ITextToSpeechService service) throws RemoteException {
+                Uri utteranceUri = mUtterances.get(text);
+                if (utteranceUri != null) {
+                    return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
+                            getParams(params), utteranceId);
+                } else {
+                    return service.speak(getCallerIdentity(), text, queueMode, getParams(params),
+                            utteranceId);
+                }
+            }
+        }, ERROR, "speak");
+    }
+
+    /**
      * Speaks the string using the specified queuing strategy and speech parameters.
      * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
      * requests and then returns. The synthesis might not have finished (or even started!) at the
@@ -933,20 +1034,50 @@
      *            engine named "com.svox.pico" if it is being used.
      *
      * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
+     * @deprecated As of API level 20, replaced by
+     *         {@link #speak(CharSequence, int, HashMap, String)}.
      */
+    @Deprecated
     public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
+        return speak(text, queueMode, params, params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+    }
+
+    /**
+     * Plays the earcon using the specified queueing mode and parameters.
+     * The earcon must already have been added with {@link #addEarcon(String, String)} or
+     * {@link #addEarcon(String, String, int)}.
+     * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+     * requests and then returns. The synthesis might not have finished (or even started!) at the
+     * time when this method returns. In order to reliably detect errors during synthesis,
+     * we recommend setting an utterance progress listener (see
+     * {@link #setOnUtteranceProgressListener}) and using the
+     * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+     *
+     * @param earcon The earcon that should be played
+     * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+     * @param params Parameters for the request. Can be null.
+     *            Supported parameter names:
+     *            {@link Engine#KEY_PARAM_STREAM},
+     *            Engine specific parameters may be passed in but the parameter keys
+     *            must be prefixed by the name of the engine they are intended for. For example
+     *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+     *            engine named "com.svox.pico" if it is being used.
+     *
+     * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
+     */
+    public int playEarcon(final String earcon, final int queueMode,
+            final HashMap<String, String> params, final String utteranceId) {
         return runAction(new Action<Integer>() {
             @Override
             public Integer run(ITextToSpeechService service) throws RemoteException {
-                Uri utteranceUri = mUtterances.get(text);
-                if (utteranceUri != null) {
-                    return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
-                            getParams(params));
-                } else {
-                    return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
+                Uri earconUri = mEarcons.get(earcon);
+                if (earconUri == null) {
+                    return ERROR;
                 }
+                return service.playAudio(getCallerIdentity(), earconUri, queueMode,
+                        getParams(params), utteranceId);
             }
-        }, ERROR, "speak");
+        }, ERROR, "playEarcon");
     }
 
     /**
@@ -972,20 +1103,44 @@
      *            engine named "com.svox.pico" if it is being used.
      *
      * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
+     * @deprecated As of API level 20, replaced by
+     *         {@link #playEarcon(String, int, HashMap, String)}.
      */
+    @Deprecated
     public int playEarcon(final String earcon, final int queueMode,
             final HashMap<String, String> params) {
+        return playEarcon(earcon, queueMode, params, params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+    }
+
+    /**
+     * Plays silence for the specified amount of time using the specified
+     * queue mode.
+     * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+     * requests and then returns. The synthesis might not have finished (or even started!) at the
+     * time when this method returns. In order to reliably detect errors during synthesis,
+     * we recommend setting an utterance progress listener (see
+     * {@link #setOnUtteranceProgressListener}) and using the
+     * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+     *
+     * @param durationInMs The duration of the silence.
+     * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+     * @param params Parameters for the request. Can be null.
+     *            Engine specific parameters may be passed in but the parameter keys
+     *            must be prefixed by the name of the engine they are intended for. For example
+     *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+     *            engine named "com.svox.pico" if it is being used.
+     * @param utteranceId An unique identifier for this request.
+     *
+     * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
+     */
+    public int playSilence(final long durationInMs, final int queueMode,
+            final HashMap<String, String> params, final String utteranceId) {
         return runAction(new Action<Integer>() {
             @Override
             public Integer run(ITextToSpeechService service) throws RemoteException {
-                Uri earconUri = mEarcons.get(earcon);
-                if (earconUri == null) {
-                    return ERROR;
-                }
-                return service.playAudio(getCallerIdentity(), earconUri, queueMode,
-                        getParams(params));
+                return service.playSilence(getCallerIdentity(), durationInMs, queueMode, utteranceId);
             }
-        }, ERROR, "playEarcon");
+        }, ERROR, "playSilence");
     }
 
     /**
@@ -1009,16 +1164,13 @@
      *            engine named "com.svox.pico" if it is being used.
      *
      * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
+     * @deprecated As of API level 20, replaced by
+     *         {@link #playEarcon(String, int, HashMap, String)}.
      */
+    @Deprecated
     public int playSilence(final long durationInMs, final int queueMode,
             final HashMap<String, String> params) {
-        return runAction(new Action<Integer>() {
-            @Override
-            public Integer run(ITextToSpeechService service) throws RemoteException {
-                return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
-                        params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
-            }
-        }, ERROR, "playSilence");
+        return playSilence(durationInMs, queueMode, params, params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
     }
 
     /**
@@ -1294,25 +1446,22 @@
      * requests and then returns. The synthesis might not have finished (or even started!) at the
      * time when this method returns. In order to reliably detect errors during synthesis,
      * we recommend setting an utterance progress listener (see
-     * {@link #setOnUtteranceProgressListener}) and using the
-     * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+     * {@link #setOnUtteranceProgressListener}).
      *
      * @param text The text that should be synthesized. No longer than
      *            {@link #getMaxSpeechInputLength()} characters.
      * @param params Parameters for the request. Can be null.
-     *            Supported parameter names:
-     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
      *            Engine specific parameters may be passed in but the parameter keys
      *            must be prefixed by the name of the engine they are intended for. For example
      *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
      *            engine named "com.svox.pico" if it is being used.
      * @param filename Absolute file filename to write the generated audio data to.It should be
      *            something like "/sdcard/myappsounds/mysound.wav".
-     *
+     * @param utteranceId An unique identifier for this request.
      * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
      */
-    public int synthesizeToFile(final String text, final HashMap<String, String> params,
-            final String filename) {
+    public int synthesizeToFile(final CharSequence text, final HashMap<String, String> params,
+            final String filename, final String utteranceId) {
         return runAction(new Action<Integer>() {
             @Override
             public Integer run(ITextToSpeechService service) throws RemoteException {
@@ -1329,7 +1478,7 @@
                             ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE);
                     returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
-                            fileDescriptor, getParams(params));
+                            fileDescriptor, getParams(params), utteranceId);
                     fileDescriptor.close();
                     return returnValue;
                 } catch (FileNotFoundException e) {
@@ -1343,6 +1492,36 @@
         }, ERROR, "synthesizeToFile");
     }
 
+    /**
+     * Synthesizes the given text to a file using the specified parameters.
+     * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+     * requests and then returns. The synthesis might not have finished (or even started!) at the
+     * time when this method returns. In order to reliably detect errors during synthesis,
+     * we recommend setting an utterance progress listener (see
+     * {@link #setOnUtteranceProgressListener}) and using the
+     * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+     *
+     * @param text The text that should be synthesized. No longer than
+     *            {@link #getMaxSpeechInputLength()} characters.
+     * @param params Parameters for the request. Can be null.
+     *            Supported parameter names:
+     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+     *            Engine specific parameters may be passed in but the parameter keys
+     *            must be prefixed by the name of the engine they are intended for. For example
+     *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+     *            engine named "com.svox.pico" if it is being used.
+     * @param filename Absolute file filename to write the generated audio data to.It should be
+     *            something like "/sdcard/myappsounds/mysound.wav".
+     *
+     * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
+     * @deprecated As of API level 20, replaced by
+     *         {@link #synthesizeToFile(CharSequence, HashMap, String, String)}.
+     */
+    public int synthesizeToFile(final String text, final HashMap<String, String> params,
+            final String filename) {
+        return synthesizeToFile(text, params, filename, params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+    }
+
     private Bundle getParams(HashMap<String, String> params) {
         if (params != null && !params.isEmpty()) {
             Bundle bundle = new Bundle(mParams);
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 5a3c5f7..017be93 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -637,11 +637,13 @@
      */
     private abstract class SpeechItemV1 extends UtteranceSpeechItem {
         protected final Bundle mParams;
+        protected final String mUtteranceId;
 
         SpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
-                Bundle params) {
+                Bundle params, String utteranceId) {
             super(callerIdentity, callerUid, callerPid);
             mParams = params;
+            mUtteranceId = utteranceId;
         }
 
         boolean hasLanguage() {
@@ -658,7 +660,7 @@
 
         @Override
         public String getUtteranceId() {
-            return getStringParam(mParams, Engine.KEY_PARAM_UTTERANCE_ID, null);
+            return mUtteranceId;
         }
 
         AudioOutputParams getAudioParams() {
@@ -668,7 +670,7 @@
 
     class SynthesisSpeechItemV1 extends SpeechItemV1 {
         // Never null.
-        private final String mText;
+        private final CharSequence mText;
         private final SynthesisRequest mSynthesisRequest;
         private final String[] mDefaultLocale;
         // Non null after synthesis has started, and all accesses
@@ -678,8 +680,8 @@
         private final int mCallerUid;
 
         public SynthesisSpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
-                Bundle params, String text) {
-            super(callerIdentity, callerUid, callerPid, params);
+                Bundle params, String utteranceId, CharSequence text) {
+            super(callerIdentity, callerUid, callerPid, params, utteranceId);
             mText = text;
             mCallerUid = callerUid;
             mSynthesisRequest = new SynthesisRequest(mText, mParams);
@@ -689,7 +691,7 @@
                     mPackageName);
         }
 
-        public String getText() {
+        public CharSequence getText() {
             return mText;
         }
 
@@ -774,8 +776,9 @@
         private final FileOutputStream mFileOutputStream;
 
         public SynthesisToFileOutputStreamSpeechItemV1(Object callerIdentity, int callerUid,
-                int callerPid, Bundle params, String text, FileOutputStream fileOutputStream) {
-            super(callerIdentity, callerUid, callerPid, params, text);
+                int callerPid, Bundle params, String utteranceId, CharSequence text,
+                FileOutputStream fileOutputStream) {
+            super(callerIdentity, callerUid, callerPid, params, utteranceId, text);
             mFileOutputStream = fileOutputStream;
         }
 
@@ -801,8 +804,8 @@
         private final AudioPlaybackQueueItem mItem;
 
         public AudioSpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
-                Bundle params, Uri uri) {
-            super(callerIdentity, callerUid, callerPid, params);
+                Bundle params, String utteranceId, Uri uri) {
+            super(callerIdentity, callerUid, callerPid, params, utteranceId);
             mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
                     TextToSpeechService.this, uri, getAudioParams());
         }
@@ -909,19 +912,20 @@
     // they can be used as message objects (which are tested for equality using ==).
     private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() {
         @Override
-        public int speak(IBinder caller, String text, int queueMode, Bundle params) {
+        public int speak(IBinder caller, CharSequence text, int queueMode, Bundle params,
+                String utteranceId) {
             if (!checkNonNull(caller, text, params)) {
                 return TextToSpeech.ERROR;
             }
 
             SpeechItem item = new SynthesisSpeechItemV1(caller,
-                    Binder.getCallingUid(), Binder.getCallingPid(), params, text);
+                    Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, text);
             return mSynthHandler.enqueueSpeechItem(queueMode, item);
         }
 
         @Override
-        public int synthesizeToFileDescriptor(IBinder caller, String text, ParcelFileDescriptor
-                fileDescriptor, Bundle params) {
+        public int synthesizeToFileDescriptor(IBinder caller, CharSequence text, ParcelFileDescriptor
+                fileDescriptor, Bundle params, String utteranceId) {
             if (!checkNonNull(caller, text, fileDescriptor, params)) {
                 return TextToSpeech.ERROR;
             }
@@ -933,19 +937,20 @@
                     fileDescriptor.detachFd());
 
             SpeechItem item = new SynthesisToFileOutputStreamSpeechItemV1(caller,
-                    Binder.getCallingUid(), Binder.getCallingPid(), params, text,
+                    Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, text,
                     new ParcelFileDescriptor.AutoCloseOutputStream(sameFileDescriptor));
             return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
         }
 
         @Override
-        public int playAudio(IBinder caller, Uri audioUri, int queueMode, Bundle params) {
+        public int playAudio(IBinder caller, Uri audioUri, int queueMode, Bundle params,
+                String utteranceId) {
             if (!checkNonNull(caller, audioUri, params)) {
                 return TextToSpeech.ERROR;
             }
 
             SpeechItem item = new AudioSpeechItemV1(caller,
-                    Binder.getCallingUid(), Binder.getCallingPid(), params, audioUri);
+                    Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, audioUri);
             return mSynthHandler.enqueueSpeechItem(queueMode, item);
         }