Merge "Enabling multiple apps to use different speech synthesis engines and not interfere with one another."
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index bd19f9e..bbbeb3f 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -129,8 +129,8 @@
          * {@link TextToSpeech#synthesizeToFile(String, HashMap, String)} with the
          * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID} key.
          * @param utteranceId the identifier of the utterance.
-         */

-        public void onUtteranceCompleted(String utteranceId);

+         */
+        public void onUtteranceCompleted(String utteranceId);
     }
 
 
@@ -286,6 +286,10 @@
          */
         public static final String KEY_PARAM_VARIANT = "variant";
         /**
+         * {@hide}
+         */
+        public static final String KEY_PARAM_ENGINE = "engine";
+        /**
          * Parameter key to specify the audio stream type to be used when speaking text
          * or playing back a file.
          * @see TextToSpeech#speak(String, int, HashMap)
@@ -327,10 +331,16 @@
          * {@hide}
          */
         protected static final int PARAM_POSITION_UTTERANCE_ID = 10;
+
         /**
          * {@hide}
          */
-        protected static final int NB_CACHED_PARAMS = 6;
+        protected static final int PARAM_POSITION_ENGINE = 12;
+
+        /**
+         * {@hide}
+         */
+        protected static final int NB_CACHED_PARAMS = 7;
     }
 
     /**
@@ -373,6 +383,7 @@
         mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT;
         mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM;
         mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID;
+        mCachedParams[Engine.PARAM_POSITION_ENGINE] = Engine.KEY_PARAM_ENGINE;
 
         mCachedParams[Engine.PARAM_POSITION_RATE + 1] =
                 String.valueOf(Engine.DEFAULT_RATE);
@@ -381,10 +392,10 @@
         mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language();
         mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country();
         mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant();
-
         mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
                 String.valueOf(Engine.DEFAULT_STREAM);
         mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = "";
+        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = Engine.DEFAULT_SYNTH;
 
         initTts();
     }
@@ -684,6 +695,10 @@
                     if (extra != null) {
                         mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
+                    extra = params.get(Engine.KEY_PARAM_ENGINE);
+                    if (extra != null) {
+                        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra;
+                    }
                 }
                 result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
             } catch (RemoteException e) {
@@ -819,7 +834,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -894,7 +909,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -943,7 +958,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -990,7 +1005,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -1046,7 +1061,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -1064,7 +1079,7 @@
                 return null;
             }
             try {
-                String[] locStrings =  mITts.getLanguage();
+                String[] locStrings = mITts.getLanguage();
                 if ((locStrings != null) && (locStrings.length == 3)) {
                     return new Locale(locStrings[0], locStrings[1], locStrings[2]);
                 } else {
@@ -1131,7 +1146,7 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                return result;
             }
         }
     }
@@ -1166,6 +1181,10 @@
                     if (extra != null) {
                         mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
+                    extra = params.get(Engine.KEY_PARAM_ENGINE);
+                    if (extra != null) {
+                        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra;
+                    }
                 }
                 if (mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename)){
                     result = SUCCESS;
@@ -1214,19 +1233,19 @@
      *
      * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
-    public int setOnUtteranceCompletedListener(

-            final OnUtteranceCompletedListener listener) {

+    public int setOnUtteranceCompletedListener(
+            final OnUtteranceCompletedListener listener) {
         synchronized (mStartLock) {
             int result = ERROR;
             if (!mStarted) {
                 return result;
             }
             mITtscallback = new ITtsCallback.Stub() {
-                public void utteranceCompleted(String utteranceId) throws RemoteException {

-                    if (listener != null) {

-                        listener.onUtteranceCompleted(utteranceId);

-                    }

-                }

+                public void utteranceCompleted(String utteranceId) throws RemoteException {
+                    if (listener != null) {
+                        listener.onUtteranceCompleted(utteranceId);
+                    }
+                }
             };
             try {
                 result = mITts.registerCallback(mPackageName, mITtscallback);
@@ -1251,7 +1270,7 @@
             } finally {
                 return result;
             }
-        }

+        }
     }
 
     /**
@@ -1262,36 +1281,39 @@
      *
      * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
-    public int setEngineByPackageName(String enginePackageName) {

-        synchronized (mStartLock) {

-            int result = TextToSpeech.ERROR;

-            if (!mStarted) {

-                return result;

-            }

-            try {

-                result = mITts.setEngineByPackageName(enginePackageName);

-            } catch (RemoteException e) {

-                // TTS died; restart it.

-                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");

-                e.printStackTrace();

-                mStarted = false;

-                initTts();

-            } catch (NullPointerException e) {

-                // TTS died; restart it.

-                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");

-                e.printStackTrace();

-                mStarted = false;

-                initTts();

-            } catch (IllegalStateException e) {

-                // TTS died; restart it.

-                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");

-                e.printStackTrace();

-                mStarted = false;

-                initTts();

-            } finally {

-                return result;

-            }

-        }

+    public int setEngineByPackageName(String enginePackageName) {
+        synchronized (mStartLock) {
+            int result = TextToSpeech.ERROR;
+            if (!mStarted) {
+                return result;
+            }
+            try {
+                result = mITts.setEngineByPackageName(enginePackageName);
+                if (result == TextToSpeech.SUCCESS){
+                    mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
+                }
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");
+                e.printStackTrace();
+                mStarted = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");
+                e.printStackTrace();
+                mStarted = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");
+                e.printStackTrace();
+                mStarted = false;
+                initTts();
+            } finally {
+                return result;
+            }
+        }
     }
 
 }
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 23365c9..1efa5a3 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -744,6 +744,7 @@
                     String country = "";
                     String variant = "";
                     String speechRate = "";
+                    String engine = "";
                     if (speechItem.mParams != null){
                         for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
                             String param = speechItem.mParams.get(i);
@@ -765,12 +766,17 @@
                                     } catch (NumberFormatException e) {
                                         streamType = DEFAULT_STREAM_TYPE;
                                     }
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
+                                    engine = speechItem.mParams.get(i + 1);
                                 }
                             }
                         }
                     }
                     // Only do the synthesis if it has not been killed by a subsequent utterance.
                     if (mKillList.get(speechItem) == null) {
+                        if (engine.length() > 0) {
+                            setEngine(engine);
+                        }
                         if (language.length() > 0){
                             setLanguage("", language, country, variant);
                         }
@@ -825,6 +831,7 @@
                     String country = "";
                     String variant = "";
                     String speechRate = "";
+                    String engine = "";
                     if (speechItem.mParams != null){
                         for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
                             String param = speechItem.mParams.get(i);
@@ -839,12 +846,17 @@
                                     variant = speechItem.mParams.get(i+1);
                                 } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
                                     utteranceId = speechItem.mParams.get(i+1);
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
+                                    engine = speechItem.mParams.get(i + 1);
                                 }
                             }
                         }
                     }
                     // Only do the synthesis if it has not been killed by a subsequent utterance.
                     if (mKillList.get(speechItem) == null){
+                        if (engine.length() > 0) {
+                            setEngine(engine);
+                        }
                         if (language.length() > 0){
                             setLanguage("", language, country, variant);
                         }