Allow clients to extend the TTS UtteranceId class.

This change allows TTS clients to create (and use) classes derived from the
UtteranceId class. This allows to attach a custom data and methods that
can be reached later in callbacks that take the UtteranceId instance as
parameter.

Also, since we can't depend on the identityHashCode results being unique,
this change adds AtomicInteger to generate unique identifiers for UtteranceId
instances.

Bug: 8259486
Change-Id: Id1e9eabc890ec585a7f8570fd20e287dcda9a11d
diff --git a/api/current.txt b/api/current.txt
index 9b6ee47..2175da6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23954,10 +23954,9 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
-  public static final class TextToSpeechClient.UtteranceId {
+  public static class TextToSpeechClient.UtteranceId {
     ctor public TextToSpeechClient.UtteranceId();
-    ctor public TextToSpeechClient.UtteranceId(java.lang.String);
-    method public java.lang.String toUniqueString();
+    method public final java.lang.String toUniqueString();
   }
 
   public abstract class TextToSpeechService extends android.app.Service {
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 0d8d42c..c6a14f2 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -39,6 +39,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Synthesizes speech from text for immediate playback or to create a sound
@@ -292,7 +293,8 @@
          * @param msFromStart
          *            Miliseconds from the start of the synthesis.
          */
-        public void onSynthesisProgress(UtteranceId utteranceId, int charIndex, int msFromStart) {}
+        public void onSynthesisProgress(UtteranceId utteranceId, int charIndex,
+                int msFromStart) {}
     }
 
     /**
@@ -366,38 +368,28 @@
     }
 
     /** Unique synthesis request identifier. */
-    public static final class UtteranceId {
-        private final String mDescription;
+    public static class UtteranceId {
+        /** Unique identifier */
+        private final int id;
+
+        /** Unique identifier generator */
+        private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
         /**
          * Create new, unique UtteranceId instance.
          */
         public UtteranceId() {
-            mDescription = null;
-        }
-
-        /**
-         * Create new, unique UtteranceId instance.
-         *
-         * @param description Additional string, that will be appended to
-         * {@link #toUniqueString()} output, allowing easier identification of the utterance in
-         * callbacks.
-         */
-        public UtteranceId(String description) {
-            mDescription = description;
+            id = ID_GENERATOR.getAndIncrement();
         }
 
         /**
          * Returns a unique string associated with an instance of this object.
          *
-         * If you subclass {@link UtteranceId} make sure that output of this method is
-         * consistent across multiple calls and unique for the instance.
-         *
          * This string will be used to identify the synthesis request/utterance inside the
          * TTS service.
          */
-        public String toUniqueString() {
-            return mDescription == null ? "UtteranceId" + System.identityHashCode(this) :
-                    "UtteranceId" + System.identityHashCode(this) + ": " + mDescription;
+        public final String toUniqueString() {
+            return "UID" + id;
         }
     }
 
@@ -680,7 +672,8 @@
 
             public void onFallback(String utteranceIdStr) {
                 synchronized (mLock) {
-                    Pair<UtteranceId, RequestCallbacks> callbacks = getCallback(utteranceIdStr);
+                    Pair<UtteranceId, RequestCallbacks> callbacks = getCallback(
+                            utteranceIdStr);
                     callbacks.second.onSynthesisFallback(callbacks.first);
                 }
             };