Merge change 2593 into donut

* changes:
  Bug fixes and performance improvements
diff --git a/include/ui/Point.h b/include/ui/Point.h
index dbbad1e..1653120 100644
--- a/include/ui/Point.h
+++ b/include/ui/Point.h
@@ -31,12 +31,9 @@
     // because we want the compiler generated versions
 
     // Default constructor doesn't initialize the Point
-    inline Point()
-    {
+    inline Point() {
     }
-
-    inline Point(int _x, int _y) : x(_x), y(_y)
-    {
+    inline Point(int x, int y) : x(x), y(y) {
     }
 
     inline bool operator == (const Point& rhs) const {
@@ -57,8 +54,8 @@
     }
 
     inline Point& operator - () {
-        x=-x;
-        y=-y;
+        x = -x;
+        y = -y;
         return *this;
     }
     
@@ -73,11 +70,13 @@
         return *this;
     }
     
-    Point operator + (const Point& rhs) const {
-        return Point(x+rhs.x, y+rhs.y);
+    const Point operator + (const Point& rhs) const {
+        const Point result(x+rhs.x, y+rhs.y);
+        return result;
     }
-    Point operator - (const Point& rhs) const {
-        return Point(x-rhs.x, y-rhs.y);
+    const Point operator - (const Point& rhs) const {
+        const Point result(x-rhs.x, y-rhs.y);
+        return result;
     }    
 };
 
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index d232847..da72944 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -33,23 +33,16 @@
     // we don't provide copy-ctor and operator= on purpose
     // because we want the compiler generated versions
 
-    inline Rect()
-    {
+    inline Rect() {
     }
-
     inline Rect(int w, int h)
-        : left(0), top(0), right(w), bottom(h)
-    {
+        : left(0), top(0), right(w), bottom(h) {
     }
-
     inline Rect(int l, int t, int r, int b)
-        : left(l), top(t), right(r), bottom(b)
-    {
+        : left(l), top(t), right(r), bottom(b) {
     }
-
     inline Rect(const Point& lt, const Point& rb) 
-        : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y)
-    {
+        : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {
     }
 
     void makeInvalid();
@@ -78,21 +71,22 @@
         return bottom-top;
     }
 
-    // returns left-top Point non-const reference, can be assigned
-    inline Point& leftTop() {
-        return reinterpret_cast<Point&>(left);
+    void setLeftTop(const Point& lt) {
+        left = lt.x;
+        top  = lt.y;
     }
-    // returns right bottom non-const reference, can be assigned
-    inline Point& rightBottom() {
-        return reinterpret_cast<Point&>(right);
+
+    void setRightBottom(const Point& rb) {
+        right = rb.x;
+        bottom  = rb.y;
     }
     
     // the following 4 functions return the 4 corners of the rect as Point
-    inline const Point& leftTop() const {
-        return reinterpret_cast<const Point&>(left);
+    Point leftTop() const {
+        return Point(left, top);
     }
-    inline const Point& rightBottom() const {
-        return reinterpret_cast<const Point&>(right);
+    Point rightBottom() const {
+        return Point(right, bottom);
     }
     Point rightTop() const {
         return Point(right, top);
@@ -133,8 +127,8 @@
     Rect& operator -= (const Point& rhs) {
         return offsetBy(-rhs.x, -rhs.y);
     }
-    Rect operator + (const Point& rhs) const;
-    Rect operator - (const Point& rhs) const;
+    const Rect operator + (const Point& rhs) const;
+    const Rect operator - (const Point& rhs) const;
 
     void translate(int dx, int dy) { // legacy, don't use.
         offsetBy(dx, dy);
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index e4f4aad..13e457f 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1553,7 +1553,6 @@
 AudioFlinger::MixerThread::TrackBase::TrackBase(
             const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
-            int streamType,
             uint32_t sampleRate,
             int format,
             int channelCount,
@@ -1563,7 +1562,6 @@
     :   RefBase(),
         mMixerThread(mixerThread),
         mClient(client),
-        mStreamType(streamType),
         mFrameCount(0),
         mState(IDLE),
         mClientTid(-1),
@@ -1713,12 +1711,13 @@
             int channelCount,
             int frameCount,
             const sp<IMemory>& sharedBuffer)
-    :   TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+    :   TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
     mMute = false;
     mSharedBuffer = sharedBuffer;
+    mStreamType = streamType;
 }
 
 AudioFlinger::MixerThread::Track::~Track()
@@ -1902,15 +1901,15 @@
 AudioFlinger::MixerThread::RecordTrack::RecordTrack(
             const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
-            int streamType,
+            int inputSource,
             uint32_t sampleRate,
             int format,
             int channelCount,
             int frameCount,
             uint32_t flags)
-    :   TrackBase(mixerThread, client, streamType, sampleRate, format,
+    :   TrackBase(mixerThread, client, sampleRate, format,
                   channelCount, frameCount, flags, 0),
-        mOverflow(false)
+        mOverflow(false), mInputSource(inputSource)
 {
 }
 
@@ -2235,7 +2234,7 @@
 
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
-        int streamType,
+        int inputSource,
         uint32_t sampleRate,
         int format,
         int channelCount,
@@ -2258,7 +2257,7 @@
         goto Exit;
     }
 
-    if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+    if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) {
         LOGE("invalid stream type");
         lStatus = BAD_VALUE;
         goto Exit;
@@ -2301,7 +2300,7 @@
         frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
     
         // create new record track. The record track uses one track in mHardwareMixerThread by convention.
-        recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+        recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate,
                                                    format, channelCount, frameCount, flags);
     }
     if (recordTrack->getCblk() == NULL) {
@@ -2408,7 +2407,7 @@
                 LOGV("AudioRecordThread: loop starting");
                 if (mRecordTrack != 0) {
                     input = mAudioHardware->openInputStream(
-                                    mRecordTrack->type(),
+                                    mRecordTrack->inputSource(),
                                     mRecordTrack->format(), 
                                     mRecordTrack->channelCount(), 
                                     mRecordTrack->sampleRate(), 
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index c7ca9ec..8e47b29 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -139,7 +139,7 @@
     // record interface
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int streamType,
+                                int inputSource,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -232,7 +232,6 @@
 
                                 TrackBase(const sp<MixerThread>& mixerThread,
                                         const sp<Client>& client,
-                                        int streamType,
                                         uint32_t sampleRate,
                                         int format,
                                         int channelCount,
@@ -260,10 +259,6 @@
                 return mCblk;
             }
 
-            int type() const {
-                return mStreamType;
-            }
-
             int format() const {
                 return mFormat;
             }
@@ -293,7 +288,6 @@
             sp<Client>          mClient;
             sp<IMemory>         mCblkMemory;
             audio_track_cblk_t* mCblk;
-            int                 mStreamType;
             void*               mBuffer;
             void*               mBufferEnd;
             uint32_t            mFrameCount;
@@ -328,6 +322,11 @@
                     void        mute(bool);
                     void        setVolume(float left, float right);
 
+                    int type() const {
+                        return mStreamType;
+                    }
+
+
         protected:
             friend class MixerThread;
             friend class AudioFlinger;
@@ -364,6 +363,7 @@
             int8_t              mRetryCount;
             sp<IMemory>         mSharedBuffer;
             bool                mResetDone;
+            int                 mStreamType;
         };  // end of Track
 
         // record track
@@ -371,7 +371,7 @@
         public:
                                 RecordTrack(const sp<MixerThread>& mixerThread,
                                         const sp<Client>& client,
-                                        int streamType,
+                                        int inputSource,
                                         uint32_t sampleRate,
                                         int format,
                                         int channelCount,
@@ -385,6 +385,8 @@
                     bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
                     bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
 
+                    int         inputSource() const { return mInputSource; }
+
         private:
             friend class AudioFlinger;
             friend class AudioFlinger::RecordHandle;
@@ -397,6 +399,7 @@
             virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
 
             bool                mOverflow;
+            int                 mInputSource;
         };
 
         // playback track
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index a97c0bc..1e159b8 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -98,8 +98,8 @@
         status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
     // check for valid input source
-    if ((inputSource != AudioRecord::DEFAULT_INPUT) &&
-            (inputSource != AudioRecord::MIC_INPUT)) {
+    if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
+        (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
         return 0;
     }
 
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index c61e6e6..0ab4c60 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -61,8 +61,8 @@
         status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
     // check for valid input source
-    if ((inputSource != AudioRecord::DEFAULT_INPUT) &&
-            (inputSource != AudioRecord::MIC_INPUT)) {
+    if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
+        (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
         return 0;
     }
 
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index f944357..b3b2104 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -20,7 +20,6 @@
 	LayerState.cpp \
 	Overlay.cpp \
 	PixelFormat.cpp \
-	Point.cpp \
 	Rect.cpp \
 	Region.cpp \
 	Surface.cpp \
diff --git a/libs/ui/Point.cpp b/libs/ui/Point.cpp
deleted file mode 100644
index 438d49f..0000000
--- a/libs/ui/Point.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- *  Point.cpp
- *  Android
- *
- *  Created on 11/16/2006.
- *  Copyright 2005 The Android Open Source Project
- *
- */
-
-#include <ui/Point.h>
-
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 99e68bb..66b9576 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -1,21 +1,28 @@
 /*
- *  Rect.cpp
- *  Android
+ * Copyright (C) 2009 The Android Open Source Project
  *
- *  Created on 10/14/05.
- *  Copyright 2005 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.
  */
 
 #include <ui/Rect.h>
 
 namespace android {
 
-inline int min(int a, int b) {
+static inline int min(int a, int b) {
     return (a<b) ? a : b;
 }
 
-inline int max(int a, int b) {
+static inline int max(int a, int b) {
     return (a>b) ? a : b;
 }
 
@@ -64,14 +71,16 @@
     return *this;
 }
 
-Rect Rect::operator + (const Point& rhs) const
+const Rect Rect::operator + (const Point& rhs) const
 {
-    return Rect(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y); 
+    const Rect result(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y);
+    return result;
 }
 
-Rect Rect::operator - (const Point& rhs) const
+const Rect Rect::operator - (const Point& rhs) const
 {
-    return Rect(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y); 
+    const Rect result(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y);
+    return result;
 }
 
 bool Rect::intersect(const Rect& with, Rect* result) const
diff --git a/tts/java/android/tts/Tts.java b/tts/java/android/tts/Tts.java
new file mode 100755
index 0000000..6c8b36d
--- /dev/null
+++ b/tts/java/android/tts/Tts.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.tts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ * Synthesizes speech from text. This abstracts away the complexities of using
+ * the TTS service such as setting up the IBinder connection and handling
+ * RemoteExceptions, etc.
+ *
+ * The TTS should always be safe the use; if the user does not have the
+ * necessary TTS apk installed, the behavior is that all calls to the TTS act as
+ * no-ops.
+ *
+ */
+//FIXME #TTS# review + complete javadoc
+public class Tts {
+
+
+    /**
+     * Called when the TTS has initialized
+     *
+     * The InitListener must implement the onInit function. onInit is passed the
+     * version number of the TTS library that the user has installed; since this
+     * is called when the TTS has started, it is a good time to make sure that
+     * the user's TTS library is up to date.
+     */
+    public interface OnInitListener {
+        public void onInit(int version);
+    }
+
+    /**
+     * Called when the TTS has finished speaking by itself (speaking
+     * finished without being canceled).
+     *
+     */
+    public interface OnSpeechCompletedListener {
+        public void onSpeechCompleted();
+    }
+
+    /**
+     * Connection needed for the TTS
+     */
+    private ServiceConnection serviceConnection;
+
+    private ITts itts = null;
+    private Context ctx = null;
+    private OnInitListener cb = null;
+    private int version = -1;
+    private boolean started = false;
+    private final Object startLock = new Object();
+    private boolean showInstaller = false;
+    private ITtsCallback ittscallback;
+    private OnSpeechCompletedListener speechCompletedCallback = null;
+
+
+    /**
+     * The constructor for the TTS.
+     *
+     * @param context
+     *            The context
+     * @param callback
+     *            The InitListener that should be called when the TTS has
+     *            initialized successfully.
+     * @param displayInstallMessage
+     *            Boolean indicating whether or not an installation prompt
+     *            should be displayed to users who do not have the TTS library.
+     *            If this is true, a generic alert asking the user to install
+     *            the TTS will be used. If you wish to specify the exact message
+     *            of that prompt, please use TTS(Context context, InitListener
+     *            callback, TTSVersionAlert alert) as the constructor instead.
+     */
+    public Tts(Context context, OnInitListener callback,
+                boolean displayInstallMessage) {
+        showInstaller = displayInstallMessage;
+        ctx = context;
+        cb = callback;
+        if (dataFilesCheck()) {
+            initTts();
+        }
+    }
+
+    /**
+     * The constructor for the TTS.
+     *
+     * @param context
+     *            The context
+     * @param callback
+     *            The InitListener that should be called when the TTS has
+     *            initialized successfully.
+     */
+    public Tts(Context context, OnInitListener callback) {
+        // FIXME #TTS# support TtsVersionAlert
+        //     showInstaller = true;
+        //     versionAlert = alert;
+        ctx = context;
+        cb = callback;
+        if (dataFilesCheck()) {
+            initTts();
+        }
+    }
+
+
+    public void setOnSpeechCompletedListener(
+            final OnSpeechCompletedListener listener) {
+        speechCompletedCallback = listener;
+    }
+
+
+    private boolean dataFilesCheck() {
+        // FIXME #TTS# config manager will be in settings
+        Log.i("TTS_FIXME", "FIXME in Tts: config manager will be in settings");
+        // FIXME #TTS# implement checking of the correct installation of
+        //             the data files.
+
+        return true;
+    }
+
+
+    private void initTts() {
+        started = false;
+
+        // Initialize the TTS, run the callback after the binding is successful
+        serviceConnection = new ServiceConnection() {
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                synchronized(startLock) {
+                    itts = ITts.Stub.asInterface(service);
+                    try {
+                        ittscallback = new ITtsCallback.Stub() {
+                            //@Override
+                            public void markReached(String mark)
+                            throws RemoteException {
+                                if (speechCompletedCallback != null) {
+                                    speechCompletedCallback.onSpeechCompleted();
+                                }
+                            }
+                        };
+                        itts.registerCallback(ittscallback);
+
+                    } catch (RemoteException e) {
+                        initTts();
+                        return;
+                    }
+
+                    started = true;
+                    // The callback can become null if the Android OS decides to
+                    // restart the TTS process as well as whatever is using it.
+                    // In such cases, do nothing - the error handling from the
+                    // speaking calls will kick in and force a proper restart of
+                    // the TTS.
+                    if (cb != null) {
+                        cb.onInit(version);
+                    }
+                }
+            }
+
+            public void onServiceDisconnected(ComponentName name) {
+                synchronized(startLock) {
+                    itts = null;
+                    cb = null;
+                    started = false;
+                }
+            }
+        };
+
+        Intent intent = new Intent("android.intent.action.USE_TTS");
+        intent.addCategory("android.intent.category.TTS");
+        // Binding will fail only if the TTS doesn't exist;
+        // the TTSVersionAlert will give users a chance to install
+        // the needed TTS.
+        if (!ctx.bindService(intent, serviceConnection,
+                Context.BIND_AUTO_CREATE)) {
+            if (showInstaller) {
+                // FIXME #TTS# show version alert
+            }
+        }
+    }
+
+
+    /**
+     * Shuts down the TTS. It is good practice to call this in the onDestroy
+     * method of the Activity that is using the TTS so that the TTS is stopped
+     * cleanly.
+     */
+    public void shutdown() {
+        try {
+            ctx.unbindService(serviceConnection);
+        } catch (IllegalArgumentException e) {
+            // Do nothing and fail silently since an error here indicates that
+            // binding never succeeded in the first place.
+        }
+    }
+
+
+    /**
+     * Adds a mapping between a string of text and a sound resource in a
+     * package.
+     *
+     * @see #TTS.speak(String text, int queueMode, String[] params)
+     *
+     * @param text
+     *            Example: <b><code>"south_south_east"</code></b><br/>
+     *
+     * @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: <b><code>R.raw.south_south_east</code></b>
+     */
+    public void addSpeech(String text, String packagename, int resourceId) {
+        synchronized(startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.addSpeech(text, packagename, resourceId);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Adds a mapping between a string of text and a sound file. Using this, it
+     * is possible to add custom pronounciations for text.
+     *
+     * @param text
+     *            The string of text
+     * @param filename
+     *            The full path to the sound file (for example:
+     *            "/sdcard/mysounds/hello.wav")
+     */
+    public void addSpeech(String text, String filename) {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.addSpeechFile(text, filename);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Speaks the string using the specified queuing strategy and speech
+     * parameters. Note that the speech parameters are not universally supported
+     * by all engines and will be treated as a hint. The TTS library will try to
+     * fulfill these parameters as much as possible, but there is no guarantee
+     * that the voice used will have the properties specified.
+     *
+     * @param text
+     *            The string of text to be spoken.
+     * @param queueMode
+     *            The queuing strategy to use. Use 0 for no queuing, and 1 for
+     *            queuing.
+     * @param params
+     *            The array of speech parameters to be used. Currently, only
+     *            params[0] is defined - it is for setting the type of voice if
+     *            the engine allows it. Possible values are "VOICE_MALE",
+     *            "VOICE_FEMALE", and "VOICE_ROBOT". Note that right now only
+     *            the pre-recorded voice has this support - this setting has no
+     *            effect on eSpeak.
+     */
+    public void speak(String text, int queueMode, String[] params) {
+        synchronized (startLock) {
+            Log.i("TTS received: ", text);
+            if (!started) {
+                return;
+            }
+            try {
+                itts.speak(text, queueMode, params);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Plays the earcon using the specified queueing mode and parameters.
+     *
+     * @param earcon
+     *            The earcon that should be played
+     * @param queueMode
+     *            0 for no queue (interrupts all previous utterances), 1 for
+     *            queued
+     * @param params
+     *            An ArrayList of parameters.
+     */
+    public void playEarcon(String earcon, int queueMode, String[] params) {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.playEarcon(earcon, queueMode, params);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Returns whether or not the TTS is busy speaking.
+     *
+     * @return Whether or not the TTS is busy speaking.
+     */
+    public boolean isSpeaking() {
+        synchronized (startLock) {
+            if (!started) {
+                return false;
+            }
+            try {
+                return itts.isSpeaking();
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+            return false;
+        }
+    }
+
+
+    /**
+     * Stops speech from the TTS.
+     */
+    public void stop() {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.stop();
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Returns the version number of the TTS library that the user has
+     * installed.
+     *
+     * @return The version number of the TTS library that the user has
+     *         installed.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+
+    /**
+     * Sets the TTS engine to be used.
+     *
+     * @param selectedEngine
+     *            The TTS engine that should be used.
+     */
+    public void setEngine(String engineName, String[] requestedLanguages, int strictness) {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.setEngine(engineName, requestedLanguages, strictness);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Sets the speech rate for the TTS engine.
+     *
+     * Note that the speech rate is not universally supported by all engines and
+     * will be treated as a hint. The TTS library will try to use the specified
+     * speech rate, but there is no guarantee.
+     *
+     * Currently, this will change the speech rate for the espeak engine, but it
+     * has no effect on any pre-recorded speech.
+     *
+     * @param speechRate
+     *            The speech rate for the TTS engine.
+     */
+    public void setSpeechRate(int speechRate) {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.setSpeechRate(speechRate);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Sets the language for the TTS engine.
+     *
+     * Note that the language is not universally supported by all engines and
+     * will be treated as a hint. The TTS library will try to use the specified
+     * language, but there is no guarantee.
+     *
+     * Currently, this will change the language for the espeak engine, but it
+     * has no effect on any pre-recorded speech.
+     *
+     * @param language
+     *            The language to be used. The languages are specified by their
+     *            IETF language tags as defined by BCP 47. This is the same
+     *            standard used for the lang attribute in HTML. See:
+     *            http://en.wikipedia.org/wiki/IETF_language_tag
+     */
+    public void setLanguage(String language) {
+        synchronized (startLock) {
+            if (!started) {
+                return;
+            }
+            try {
+                itts.setLanguage(language);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+        }
+    }
+
+
+    /**
+     * Speaks the given text using the specified queueing mode and parameters.
+     *
+     * @param text
+     *            The String of text that should be synthesized
+     * @param params
+     *            An ArrayList of parameters. The first element of this array
+     *            controls the type of voice to use.
+     * @param filename
+     *            The string that gives the full output filename; it should be
+     *            something like "/sdcard/myappsounds/mysound.wav".
+     * @return A boolean that indicates if the synthesis succeeded
+     */
+    public boolean synthesizeToFile(String text, String[] params,
+            String filename) {
+        synchronized (startLock) {
+            if (!started) {
+                return false;
+            }
+            try {
+                return itts.synthesizeToFile(text, params, filename);
+            } catch (RemoteException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (NullPointerException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            } catch (IllegalStateException e) {
+                // TTS died; restart it.
+                started = false;
+                initTts();
+            }
+            return false;
+        }
+    }
+
+
+    /**
+     * Displays an alert that prompts users to install the TTS engine.
+     * This is useful if the application expects a newer version
+     * of the TTS than what the user has.
+     */
+    public void showVersionAlert() {
+        if (!started) {
+            return;
+        }
+        // FIXME #TTS# implement show version alert
+    }
+
+
+    /**
+     * Checks if the TTS service is installed or not
+     *
+     * @return A boolean that indicates whether the TTS service is installed
+     */
+    // TODO: TTS Service itself will always be installed. Factor this out
+    // (may need to add another method to see if there are any working
+    // TTS engines on the device).
+    public static boolean isInstalled(Context ctx) {
+        PackageManager pm = ctx.getPackageManager();
+        Intent intent = new Intent("android.intent.action.USE_TTS");
+        intent.addCategory("android.intent.category.TTS");
+        ResolveInfo info = pm.resolveService(intent, 0);
+        if (info == null) {
+            return false;
+        }
+        return true;
+    }
+
+}