Merge change 2652

* changes:
  Move ContactsContract.java and SocialContract.java into android.providers
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 30b6733..afad48e 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -55,7 +55,6 @@
 #
 hostSources:= \
 	InetAddress.cpp \
-	Pipe.cpp \
 	Socket.cpp \
 	ZipEntry.cpp \
 	ZipFile.cpp
@@ -71,12 +70,7 @@
 # Use the futex based mutex and condition variable
 # implementation from android-arm because it's shared mem safe
 	LOCAL_SRC_FILES += \
-		futex_synchro.c \
-		executablepath_linux.cpp
-endif
-ifeq ($(HOST_OS),darwin)
-	LOCAL_SRC_FILES += \
-		executablepath_darwin.cpp
+		futex_synchro.c
 endif
 
 LOCAL_MODULE:= libutils
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
deleted file mode 100644
index 613906b..0000000
--- a/libs/utils/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-//
-// Unidirectional pipe.
-//
-
-#include <utils/Pipe.h>
-#include <utils/Log.h>
-
-#if defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-
-/*
- * Constructor.  Do little.
- */
-Pipe::Pipe(void)
-    : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
-      mWriteHandle(kInvalidHandle)
-{
-}
-
-/*
- * Destructor.  Use the system-appropriate close call.
- */
-Pipe::~Pipe(void)
-{
-#if defined(HAVE_WIN32_IPC)
-    if (mReadHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mReadHandle))
-            LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
-                mReadHandle);
-    }
-    if (mWriteHandle != kInvalidHandle) {
-        FlushFileBuffers((HANDLE)mWriteHandle);
-        if (!CloseHandle((HANDLE)mWriteHandle))
-            LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
-                mWriteHandle);
-    }
-#else
-    if (mReadHandle != kInvalidHandle) {
-        if (close((int) mReadHandle) != 0)
-            LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
-                (int) mReadHandle);
-    }
-    if (mWriteHandle != kInvalidHandle) {
-        if (close((int) mWriteHandle) != 0)
-            LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
-                (int) mWriteHandle);
-    }
-#endif
-}
-
-/*
- * Create the pipe.
- *
- * Use the POSIX stuff for everything but Windows.
- */
-bool Pipe::create(void)
-{
-    assert(mReadHandle == kInvalidHandle);
-    assert(mWriteHandle == kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    /* we use this across processes, so they need to be inheritable */
-    HANDLE handles[2];
-    SECURITY_ATTRIBUTES saAttr;
-
-    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
-    saAttr.bInheritHandle = TRUE;
-    saAttr.lpSecurityDescriptor = NULL;
-
-    if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
-        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
-        return false;
-    }
-    mReadHandle = (unsigned long) handles[0];
-    mWriteHandle = (unsigned long) handles[1];
-    return true;
-#else
-    int fds[2];
-
-    if (pipe(fds) != 0) {
-        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
-        return false;
-    }
-    mReadHandle = fds[0];
-    mWriteHandle = fds[1];
-    return true;
-#endif
-}
-
-/*
- * Create a "half pipe".  Please, no Segway riding.
- */
-bool Pipe::createReader(unsigned long handle)
-{
-    mReadHandle = handle;
-    assert(mWriteHandle == kInvalidHandle);
-    return true;
-}
-
-/*
- * Create a "half pipe" for writing.
- */
-bool Pipe::createWriter(unsigned long handle)
-{
-    mWriteHandle = handle;
-    assert(mReadHandle == kInvalidHandle);
-    return true;
-}
-
-/*
- * Return "true" if create() has been called successfully.
- */
-bool Pipe::isCreated(void)
-{
-    // one or the other should be open
-    return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
-}
-
-
-/*
- * Read data from the pipe.
- *
- * For Linux and Darwin, just call read().  For Windows, implement
- * non-blocking reads by calling PeekNamedPipe first.
- */
-int Pipe::read(void* buf, int count)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD totalBytesAvail = count;
-    DWORD bytesRead;
-
-    if (mReadNonBlocking) {
-        // use PeekNamedPipe to adjust read count expectations
-        if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
-                &totalBytesAvail, NULL))
-        {
-            LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
-            return -1;
-        }
-
-        if (totalBytesAvail == 0)
-            return 0;
-    }
-
-    if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
-            NULL))
-    {
-        DWORD err = GetLastError();
-        if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
-            return 0;
-        LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
-        return -1;
-    }
-
-    return (int) bytesRead;
-#else
-    int cc;
-    cc = ::read(mReadHandle, buf, count);
-    if (cc < 0 && errno == EAGAIN)
-        return 0;
-    return cc;
-#endif
-}
-
-/*
- * Write data to the pipe.
- *
- * POSIX systems are trivial, Windows uses a different call and doesn't
- * handle non-blocking writes.
- *
- * If we add non-blocking support here, we probably want to make it an
- * all-or-nothing write.
- *
- * DO NOT use LOG() here, we could be writing a log message.
- */
-int Pipe::write(const void* buf, int count)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD bytesWritten;
-
-    if (mWriteNonBlocking) {
-        // BUG: can't use PeekNamedPipe() to get the amount of space
-        // left.  Looks like we need to use "overlapped I/O" functions.
-        // I just don't care that much.
-    }
-
-    if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
-        // can't LOG, use stderr
-        fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
-        return -1;
-    }
-
-    return (int) bytesWritten;
-#else
-    int cc;
-    cc = ::write(mWriteHandle, buf, count);
-    if (cc < 0 && errno == EAGAIN)
-        return 0;
-    return cc;
-#endif
-}
-
-/*
- * Figure out if there is data available on the read fd.
- *
- * We return "true" on error because we want the caller to try to read
- * from the pipe.  They'll notice the read failure and do something
- * appropriate.
- */
-bool Pipe::readReady(void)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD totalBytesAvail;
-
-    if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
-            &totalBytesAvail, NULL))
-    {
-        LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
-        return true;
-    }
-
-    return (totalBytesAvail != 0);
-#else
-    errno = 0;
-    fd_set readfds;
-    struct timeval tv = { 0, 0 };
-    int cc;
-
-    FD_ZERO(&readfds);
-    FD_SET(mReadHandle, &readfds);
-
-    cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
-    if (cc < 0) {
-        LOG(LOG_ERROR, "pipe", "select() failed\n");
-        return true;
-    } else if (cc == 0) {
-        /* timed out, nothing available */
-        return false;
-    } else if (cc == 1) {
-        /* our fd is ready */
-        return true;
-    } else {
-        LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
-        return true;
-    }
-#endif
-}
-
-/*
- * Enable or disable non-blocking mode for the read descriptor.
- *
- * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
- * actually be in non-blocking mode.  If this matters -- i.e. you're not
- * using a select() call -- put a call to readReady() in front of the
- * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
- * Darwin.
- */
-bool Pipe::setReadNonBlocking(bool val)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    // nothing to do
-#else
-    int flags;
-
-    if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
-        LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
-        return false;
-    }
-    if (val)
-        flags |= O_NONBLOCK;
-    else
-        flags &= ~(O_NONBLOCK);
-    if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
-        LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
-        return false;
-    }
-#endif
-
-    mReadNonBlocking = val;
-    return true;
-}
-
-/*
- * Enable or disable non-blocking mode for the write descriptor.
- *
- * As with setReadNonBlocking(), this does not work on the Mac.
- */
-bool Pipe::setWriteNonBlocking(bool val)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    // nothing to do
-#else
-    int flags;
-
-    if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
-        LOG(LOG_WARN, "pipe",
-            "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
-            errno);
-        return false;
-    }
-    if (val)
-        flags |= O_NONBLOCK;
-    else
-        flags &= ~(O_NONBLOCK);
-    if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
-        LOG(LOG_WARN, "pipe",
-            "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
-            errno);
-        return false;
-    }
-#endif
-
-    mWriteNonBlocking = val;
-    return true;
-}
-
-/*
- * Specify whether a file descriptor can be inherited by a child process.
- * Under Linux this means setting the close-on-exec flag, under Windows
- * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
- */
-bool Pipe::disallowReadInherit(void)
-{
-    if (mReadHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
-        return false;
-#else
-    if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
-        return false;
-#endif
-    return true;
-}
-bool Pipe::disallowWriteInherit(void)
-{
-    if (mWriteHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
-        return false;
-#else
-    if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
-        return false;
-#endif
-    return true;
-}
-
-/*
- * Close read descriptor.
- */
-bool Pipe::closeRead(void)
-{
-    if (mReadHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (mReadHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mReadHandle)) {
-            LOG(LOG_WARN, "pipe", "failed closing read handle\n");
-            return false;
-        }
-    }
-#else
-    if (mReadHandle != kInvalidHandle) {
-        if (close((int) mReadHandle) != 0) {
-            LOG(LOG_WARN, "pipe", "failed closing read fd\n");
-            return false;
-        }
-    }
-#endif
-    mReadHandle = kInvalidHandle;
-    return true;
-}
-
-/*
- * Close write descriptor.
- */
-bool Pipe::closeWrite(void)
-{
-    if (mWriteHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (mWriteHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mWriteHandle)) {
-            LOG(LOG_WARN, "pipe", "failed closing write handle\n");
-            return false;
-        }
-    }
-#else
-    if (mWriteHandle != kInvalidHandle) {
-        if (close((int) mWriteHandle) != 0) {
-            LOG(LOG_WARN, "pipe", "failed closing write fd\n");
-            return false;
-        }
-    }
-#endif
-    mWriteHandle = kInvalidHandle;
-    return true;
-}
-
-/*
- * Get the read handle.
- */
-unsigned long Pipe::getReadHandle(void)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-    return mReadHandle;
-}
-
-/*
- * Get the write handle.
- */
-unsigned long Pipe::getWriteHandle(void)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-    return mWriteHandle;
-}
-
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
deleted file mode 100644
index 2e3c3a0..0000000
--- a/libs/utils/executablepath_darwin.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2008 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 <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-void executablepath(char s[PATH_MAX])
-{
-    ProcessSerialNumber psn;
-    GetCurrentProcess(&psn);
-    CFDictionaryRef dict;
-    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
-    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
-                CFSTR("CFBundleExecutable"));
-    CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
-}
-
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
deleted file mode 100644
index b8d2a3d..0000000
--- a/libs/utils/executablepath_linux.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2008 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 <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void executablepath(char exe[PATH_MAX])
-{
-    char proc[100];
-    sprintf(proc, "/proc/%d/exe", getpid());
-    
-    int err = readlink(proc, exe, PATH_MAX);
-}
-
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;
+    }
+
+}