Merge change 2548 into donut

* changes:
  Fix a bug in AppSecurityPermissions where it wouldn't display permissions used by an app if it uses a shared user id. Remove the else clause and always get the list of requested permissions first before adding the permissions obtained via the shared user id. Also change an if condition and comments for better readability
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 06f3820..bf62995 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -53,7 +53,8 @@
     TTS_FEATURE_UNSUPPORTED     = -2,
     TTS_VALUE_INVALID           = -3,
     TTS_PROPERTY_UNSUPPORTED    = -4,
-    TTS_PROPERTY_SIZE_TOO_SMALL = -5
+    TTS_PROPERTY_SIZE_TOO_SMALL = -5,
+    TTS_MISSING_RESOURCES       = -6
 };
 
 class TtsEngine
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 13e457f..324111b 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -817,19 +817,22 @@
         {
             AutoMutex lock(mHardwareLock);
             if (mForcedSpeakerCount++ == 0) {
-                mRouteRestoreTime = 0;
-                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
-                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
-                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
-                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
-                    usleep(mHardwareMixerThread->latency()*1000);
-                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
-                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
-                    mHardwareStatus = AUDIO_HW_IDLE;
-                    // delay track start so that audio hardware has time to siwtch routes
-                    usleep(kStartSleepTime);
+                if (mForcedRoute == 0) {
+                    mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                    LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
+                    if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                        LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                        mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                        usleep(mHardwareMixerThread->latency()*1000);
+                        mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                        mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                        mHardwareStatus = AUDIO_HW_IDLE;
+                        // delay track start so that audio hardware has time to siwtch routes
+                        usleep(kStartSleepTime);
+                    }
                 }
                 mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+                mRouteRestoreTime = 0;
             }
             LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
         }
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index e844350..397ddc8 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -114,7 +114,9 @@
     }
 
     if (mBitsMemory==0 || mSurface.data==0) {
-        LOGE("not enough memory for layer bitmap size=%u", size);
+        LOGE("not enough memory for layer bitmap "
+             "size=%u (w=%d, h=%d, stride=%d, format=%d)",
+             size, int(w), int(h), int(stride), int(format));
         allocator->dump("LayerBitmap");
         mSurface.data = 0;
         mSize = -1U;
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;
+    }
+
+}