auto import from //depot/cupcake/@135843
diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
new file mode 100644
index 0000000..bb19e92
--- /dev/null
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -0,0 +1,548 @@
+/*
+** Copyright 2006, 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.
+*/
+
+#define LOG_TAG "BT HSHFP"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+static jfieldID field_mAddress;
+static jfieldID field_mRfcommChannel;
+static jfieldID field_mTimeoutRemainingMs;
+
+typedef struct {
+    jstring address;
+    const char *c_address;
+    int rfcomm_channel;
+    int last_read_err;
+    int rfcomm_sock;
+    int rfcomm_connected; // -1 in progress, 0 not connected, 1 connected
+    int rfcomm_sock_flags;
+} native_data_t;
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+    return (native_data_t *)(env->GetIntField(object, field_mNativeData));
+}
+
+static const char CRLF[] = "\xd\xa";
+static const int CRLF_LEN = 2;
+
+static inline int write_error_check(int fd, const char* line, int len) {
+    int ret;
+    errno = 0;
+    ret = write(fd, line, len);
+    if (ret < 0) {
+        LOGE("%s: write() failed: %s (%d)", __FUNCTION__, strerror(errno),
+             errno);
+        return -1;
+    }
+    if (ret != len) {
+        LOGE("%s: write() only wrote %d of %d bytes", __FUNCTION__, ret, len);
+        return -1;
+    }
+    return 0;
+}
+
+static int send_line(int fd, const char* line) {
+    int nw;
+    int len = strlen(line);
+    int llen = len + CRLF_LEN * 2 + 1;
+    char *buffer = (char *)calloc(llen, sizeof(char));
+
+    snprintf(buffer, llen, "%s%s%s", CRLF, line, CRLF);
+
+    if (write_error_check(fd, buffer, llen - 1)) {
+        free(buffer);
+        return -1;
+    }
+    free(buffer);
+    return 0;
+}
+
+static const char* get_line(int fd, char *buf, int len, int timeout_ms,
+                            int *err) {
+    char *bufit=buf;
+    int fd_flags = fcntl(fd, F_GETFL, 0);
+    struct pollfd pfd;
+
+again:
+    *bufit = 0;
+    pfd.fd = fd;
+    pfd.events = POLLIN;
+    *err = errno = 0;
+    int ret = poll(&pfd, 1, timeout_ms);
+    if (ret < 0) {
+        LOGE("poll() error\n");
+        *err = errno;
+        return NULL;
+    }
+    if (ret == 0) {
+        return NULL;
+    }
+
+    if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+        LOGW("RFCOMM poll() returned  success (%d), "
+             "but with an unexpected revents bitmask: %#x\n", ret, pfd.revents);
+        errno = EIO;
+        *err = errno;
+        return NULL;
+    }
+
+    while ((int)(bufit - buf) < len)
+    {
+        errno = 0;
+        int rc = read(fd, bufit, 1);
+
+        if (!rc)
+            break;
+
+        if (rc < 0) {
+            if (errno == EBUSY) {
+                LOGI("read() error %s (%d): repeating read()...",
+                     strerror(errno), errno);
+                goto again;
+            }
+            *err = errno;
+            LOGE("read() error %s (%d)", strerror(errno), errno);
+            return NULL;
+        }
+
+
+        if (*bufit=='\xd') {
+            break;
+        }
+
+        if (*bufit=='\xa')
+            bufit = buf;
+        else
+            bufit++;
+    }
+
+    *bufit = '\x0';
+    LOG(LOG_INFO, "Bluetooth AT recv", buf);
+
+    return buf;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+    field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
+    field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
+    field_mRfcommChannel = get_field(env, clazz, "mRfcommChannel", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object,
+                                       jint socketFd) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+    if (NULL == nat) {
+        LOGE("%s: out of memory!", __FUNCTION__);
+        return;
+    }
+
+    env->SetIntField(object, field_mNativeData, (jint)nat);
+    nat->address =
+        (jstring)env->NewGlobalRef(env->GetObjectField(object,
+                                                       field_mAddress));
+    nat->c_address = env->GetStringUTFChars(nat->address, NULL);
+    nat->rfcomm_channel = env->GetIntField(object, field_mRfcommChannel);
+    nat->rfcomm_sock = socketFd;
+    nat->rfcomm_connected = socketFd >= 0;
+    if (nat->rfcomm_connected)
+        LOGI("%s: ALREADY CONNECTED!", __FUNCTION__);
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat =
+        (native_data_t *)env->GetIntField(object, field_mNativeData);
+    env->ReleaseStringUTFChars(nat->address, nat->c_address);
+    env->DeleteGlobalRef(nat->address);
+    if (nat)
+        free(nat);
+#endif
+}
+
+static jboolean connectNative(JNIEnv *env, jobject obj)
+{
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    int lm;
+    struct sockaddr_rc addr;
+    native_data_t *nat = get_native_data(env, obj);
+
+    nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+
+    if (nat->rfcomm_sock < 0) {
+        LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
+             strerror(errno));
+        return JNI_FALSE;
+    }
+
+    if (debug_no_encrypt()) {
+        lm = RFCOMM_LM_AUTH;
+    } else {
+        lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+    }
+
+    if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
+                sizeof(lm)) < 0) {
+        LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
+        close(nat->rfcomm_sock);
+        return JNI_FALSE;
+    }
+
+    memset(&addr, 0, sizeof(struct sockaddr_rc));
+    get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+    addr.rc_channel = nat->rfcomm_channel;
+    addr.rc_family = AF_BLUETOOTH;
+    nat->rfcomm_connected = 0;
+    while (nat->rfcomm_connected == 0) {
+        if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
+                      sizeof(addr)) < 0) {
+            if (errno == EINTR) continue;
+            LOGE("%s: connect() failed: %s\n", __FUNCTION__, strerror(errno));
+            close(nat->rfcomm_sock);
+            nat->rfcomm_sock = -1;
+            return JNI_FALSE;
+        } else {
+            nat->rfcomm_connected = 1;
+        }
+    }
+
+    return JNI_TRUE;
+#else
+    return JNI_FALSE;
+#endif
+}
+
+static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    struct sockaddr_rc addr;
+    native_data_t *nat = get_native_data(env, obj);
+
+    if (nat->rfcomm_connected) {
+        LOGV("RFCOMM socket is already connected or connection is in progress.");
+        return JNI_TRUE;
+    }
+
+    if (nat->rfcomm_sock < 0) {
+        int lm;
+
+        nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+        if (nat->rfcomm_sock < 0) {
+            LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
+                 strerror(errno));
+            return JNI_FALSE;
+        }
+
+        if (debug_no_encrypt()) {
+            lm = RFCOMM_LM_AUTH;
+        } else {
+            lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+        }
+
+        if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
+                    sizeof(lm)) < 0) {
+            LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
+            close(nat->rfcomm_sock);
+            return JNI_FALSE;
+        }
+        LOGI("Created RFCOMM socket fd %d.", nat->rfcomm_sock);
+    }
+
+    memset(&addr, 0, sizeof(struct sockaddr_rc));
+    get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+    addr.rc_channel = nat->rfcomm_channel;
+    addr.rc_family = AF_BLUETOOTH;
+    if (nat->rfcomm_sock_flags >= 0) {
+        nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
+        if (fcntl(nat->rfcomm_sock,
+                  F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
+            int rc;
+            nat->rfcomm_connected = 0;
+            errno = 0;
+            rc = connect(nat->rfcomm_sock,
+                        (struct sockaddr *)&addr,
+                         sizeof(addr));
+
+            if (rc >= 0) {
+                nat->rfcomm_connected = 1;
+                LOGI("async connect successful");
+                return JNI_TRUE;
+            }
+            else if (rc < 0) {
+                if (errno == EINPROGRESS || errno == EAGAIN)
+                {
+                    LOGI("async connect is in progress (%s)",
+                         strerror(errno));
+                    nat->rfcomm_connected = -1;
+                    return JNI_TRUE;
+                }
+                else
+                {
+                    LOGE("async connect error: %s (%d)", strerror(errno), errno);
+                    close(nat->rfcomm_sock);
+                    nat->rfcomm_sock = -1;
+                    return JNI_FALSE;
+                }
+            }
+        } // fcntl(nat->rfcomm_sock ...)
+    } // if (nat->rfcomm_sock_flags >= 0)
+#endif
+    return JNI_FALSE;
+}
+
+static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
+                                           jint timeout_ms) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    struct sockaddr_rc addr;
+    native_data_t *nat = get_native_data(env, obj);
+
+    env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
+
+    if (nat->rfcomm_connected > 0) {
+        LOGI("RFCOMM is already connected!");
+        return 1;
+    }
+
+    if (nat->rfcomm_sock >= 0 && nat->rfcomm_connected == 0) {
+        LOGI("Re-opening RFCOMM socket.");
+        close(nat->rfcomm_sock);
+        nat->rfcomm_sock = -1;
+    }
+    if (JNI_FALSE == connectAsyncNative(env, obj)) {
+        LOGI("Failed to re-open RFCOMM socket!");
+        return -1;
+    }
+
+    if (nat->rfcomm_sock >= 0) {
+        /* Do an asynchronous select() */
+        int n;
+        fd_set rset, wset;
+        struct timeval to;
+
+        FD_ZERO(&rset);
+        FD_ZERO(&wset);
+        FD_SET(nat->rfcomm_sock, &rset);
+        FD_SET(nat->rfcomm_sock, &wset);
+        if (timeout_ms >= 0) {
+            to.tv_sec = timeout_ms / 1000;
+            to.tv_usec = 1000 * (timeout_ms % 1000);
+        }
+        n = select(nat->rfcomm_sock + 1,
+                   &rset,
+                   &wset,
+                   NULL,
+                   (timeout_ms < 0 ? NULL : &to));
+
+        if (timeout_ms > 0) {
+            jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
+            LOGV("Remaining time %ldms", (long)remaining);
+            env->SetIntField(obj, field_mTimeoutRemainingMs,
+                             remaining);
+        }
+
+        if (n <= 0) {
+            if (n < 0)  {
+                LOGE("select() on RFCOMM socket: %s (%d)",
+                     strerror(errno),
+                     errno);
+                return -1;
+            }
+            return 0;
+        }
+        /* n must be equal to 1 and either rset or wset must have the
+           file descriptor set. */
+        LOGV("select() returned %d.", n);
+        if (FD_ISSET(nat->rfcomm_sock, &rset) ||
+            FD_ISSET(nat->rfcomm_sock, &wset))
+        {
+            /* A trial async read() will tell us if everything is OK. */
+            {
+                char ch;
+                errno = 0;
+                int nr = read(nat->rfcomm_sock, &ch, 1);
+                /* It should be that nr != 1 because we just opened a socket
+                   and we haven't sent anything over it for the other side to
+                   respond... but one can't be paranoid enough.
+                */
+                if (nr >= 0 || errno != EAGAIN) {
+                    LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
+                         strerror(errno),
+                         errno,
+                         nr);
+                    /* Clear the rfcomm_connected flag to cause this function
+                       to re-create the socket and re-attempt the connect()
+                       the next time it is called.
+                    */
+                    nat->rfcomm_connected = 0;
+                    /* Restore the blocking properties of the socket. */
+                    fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+                    close(nat->rfcomm_sock);
+                    nat->rfcomm_sock = -1;
+                    return -1;
+                }
+            }
+            /* Restore the blocking properties of the socket. */
+            fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+            LOGI("Successful RFCOMM socket connect.");
+            nat->rfcomm_connected = 1;
+            return 1;
+        }
+    }
+    else LOGE("RFCOMM socket file descriptor %d is bad!",
+              nat->rfcomm_sock);
+#endif
+    return -1;
+}
+
+static void disconnectNative(JNIEnv *env, jobject obj) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, obj);
+    if (nat->rfcomm_sock >= 0) {
+        close(nat->rfcomm_sock);
+        nat->rfcomm_sock = -1;
+        nat->rfcomm_connected = 0;
+    }
+#endif
+}
+
+static void pretty_log_urc(const char *urc) {
+    size_t i;
+    bool in_line_break = false;
+    char *buf = (char *)calloc(strlen(urc) + 1, sizeof(char));
+
+    strcpy(buf, urc);
+    for (i = 0; i < strlen(buf); i++) {
+        switch(buf[i]) {
+        case '\r':
+        case '\n':
+            in_line_break = true;
+            buf[i] = ' ';
+            break;
+        default:
+            if (in_line_break) {
+                in_line_break = false;
+                buf[i-1] = '\n';
+            }
+        }
+    }
+    LOG(LOG_INFO, "Bluetooth AT sent", buf);
+
+    free(buf);
+}
+
+static jboolean sendURCNative(JNIEnv *env, jobject obj, jstring urc) {
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, obj);
+    if (nat->rfcomm_connected) {
+        const char *c_urc = env->GetStringUTFChars(urc, NULL);
+        jboolean ret = send_line(nat->rfcomm_sock, c_urc) == 0 ? JNI_TRUE : JNI_FALSE;
+        if (ret == JNI_TRUE) pretty_log_urc(c_urc);
+        env->ReleaseStringUTFChars(urc, c_urc);
+        return ret;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jstring readNative(JNIEnv *env, jobject obj, jint timeout_ms) {
+#ifdef HAVE_BLUETOOTH
+    {
+        native_data_t *nat = get_native_data(env, obj);
+        if (nat->rfcomm_connected) {
+            char buf[128];
+            const char *ret = get_line(nat->rfcomm_sock,
+                                       buf, sizeof(buf),
+                                       timeout_ms,
+                                       &nat->last_read_err);
+            return ret ? env->NewStringUTF(ret) : NULL;
+        }
+        return NULL;
+    }
+#else
+    return NULL;
+#endif
+}
+
+static jint getLastReadStatusNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+    {
+        native_data_t *nat = get_native_data(env, obj);
+        if (nat->rfcomm_connected)
+            return (jint)nat->last_read_err;
+        return 0;
+    }
+#else
+    return 0;
+#endif
+}
+
+static JNINativeMethod sMethods[] = {
+     /* name, signature, funcPtr */
+    {"classInitNative", "()V", (void*)classInitNative},
+    {"initializeNativeDataNative", "(I)V", (void *)initializeNativeDataNative},
+    {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+    {"connectNative", "()Z", (void *)connectNative},
+    {"connectAsyncNative", "()Z", (void *)connectAsyncNative},
+    {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
+    {"disconnectNative", "()V", (void *)disconnectNative},
+    {"sendURCNative", "(Ljava/lang/String;)Z", (void *)sendURCNative},
+    {"readNative", "(I)Ljava/lang/String;", (void *)readNative},
+    {"getLastReadStatusNative", "()I", (void *)getLastReadStatusNative},
+};
+
+int register_android_bluetooth_HeadsetBase(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+            "android/bluetooth/HeadsetBase", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */