auto import from //depot/cupcake/@135843
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
new file mode 100755
index 0000000..7f87d80
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -0,0 +1,553 @@
+/*
+** 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 "BluetoothAudioGateway.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#define USE_ACCEPT_DIRECTLY (0)
+#define USE_SELECT (0) /* 1 for select(), 0 for poll(); used only when
+                          USE_ACCEPT_DIRECTLY == 0 */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <ctype.h>
+
+#if USE_SELECT
+#include <sys/select.h>
+#else
+#include <sys/poll.h>
+#endif
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+    /* in */
+static jfieldID field_mHandsfreeAgRfcommChannel;
+static jfieldID field_mHeadsetAgRfcommChannel;
+    /* out */
+static jfieldID field_mTimeoutRemainingMs; /* out */
+
+static jfieldID field_mConnectingHeadsetAddress;
+static jfieldID field_mConnectingHeadsetRfcommChannel; /* -1 when not connected */
+static jfieldID field_mConnectingHeadsetSocketFd;
+
+static jfieldID field_mConnectingHandsfreeAddress;
+static jfieldID field_mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
+static jfieldID field_mConnectingHandsfreeSocketFd;
+
+
+typedef struct {
+    int hcidev;
+    int hf_ag_rfcomm_channel;
+    int hs_ag_rfcomm_channel;
+    int hf_ag_rfcomm_sock;
+    int hs_ag_rfcomm_sock;
+} 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 int setup_listening_socket(int dev, int channel);
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+    /* in */
+    field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+    field_mHandsfreeAgRfcommChannel = 
+        get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
+    field_mHeadsetAgRfcommChannel = 
+        get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
+
+    /* out */
+    field_mConnectingHeadsetAddress = 
+        get_field(env, clazz, 
+                  "mConnectingHeadsetAddress", "Ljava/lang/String;");
+    field_mConnectingHeadsetRfcommChannel = 
+        get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
+    field_mConnectingHeadsetSocketFd = 
+        get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
+
+    field_mConnectingHandsfreeAddress = 
+        get_field(env, clazz, 
+                  "mConnectingHandsfreeAddress", "Ljava/lang/String;");
+    field_mConnectingHandsfreeRfcommChannel = 
+        get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
+    field_mConnectingHandsfreeSocketFd = 
+        get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
+
+    field_mTimeoutRemainingMs = 
+        get_field(env, clazz, "mTimeoutRemainingMs", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+    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;
+    }
+
+    nat->hcidev = BLUETOOTH_ADAPTER_HCI_NUM;
+
+    env->SetIntField(object, field_mNativeData, (jint)nat);
+    nat->hf_ag_rfcomm_channel =
+        env->GetIntField(object, field_mHandsfreeAgRfcommChannel);
+    nat->hs_ag_rfcomm_channel =
+        env->GetIntField(object, field_mHeadsetAgRfcommChannel);
+    LOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
+    LOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
+
+    /* Set the default values of these to -1. */
+    env->SetIntField(object, field_mConnectingHeadsetRfcommChannel, -1);
+    env->SetIntField(object, field_mConnectingHandsfreeRfcommChannel, -1);
+
+    nat->hf_ag_rfcomm_sock = -1;
+    nat->hs_ag_rfcomm_sock = -1;
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, object);
+    if (nat) {
+        free(nat);
+    }
+#endif
+}
+
+#ifdef HAVE_BLUETOOTH
+
+#if USE_ACCEPT_DIRECTLY==0
+static int set_nb(int sk, bool nb) {
+    int flags = fcntl(sk, F_GETFL);
+    if (flags < 0) {
+        LOGE("Can't get socket flags with fcntl(): %s (%d)", 
+             strerror(errno), errno);
+        close(sk);
+        return -1;
+    }
+    flags &= ~O_NONBLOCK;
+    if (nb) flags |= O_NONBLOCK;
+    int status = fcntl(sk, F_SETFL, flags);
+    if (status < 0) {
+        LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
+             strerror(errno), errno);
+        close(sk);
+        return -1;
+    }
+    return 0;
+}
+#endif /*USE_ACCEPT_DIRECTLY==0*/
+
+static int do_accept(JNIEnv* env, jobject object, int ag_fd,
+                     jfieldID out_fd,
+                     jfieldID out_address,
+                     jfieldID out_channel) {
+
+#if USE_ACCEPT_DIRECTLY==0
+    if (set_nb(ag_fd, true) < 0)
+        return -1;
+#endif
+
+    struct sockaddr_rc raddr;
+    int alen = sizeof(raddr);
+    int nsk = accept(ag_fd, (struct sockaddr *) &raddr, &alen);
+    if (nsk < 0) {
+        LOGE("Error on accept from socket fd %d: %s (%d).",
+             ag_fd,
+             strerror(errno),
+             errno);
+#if USE_ACCEPT_DIRECTLY==0
+        set_nb(ag_fd, false);
+#endif
+        return -1;
+    }
+
+    env->SetIntField(object, out_fd, nsk);
+    env->SetIntField(object, out_channel, raddr.rc_channel);
+
+    char addr[BTADDR_SIZE];
+    get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
+    env->SetObjectField(object, out_address, env->NewStringUTF(addr));
+
+    LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
+         ag_fd,
+         nsk,
+         addr,
+         raddr.rc_channel);
+#if USE_ACCEPT_DIRECTLY==0
+    set_nb(ag_fd, false);
+#endif
+    return 0;
+}
+
+#if USE_SELECT
+static inline int on_accept_set_fields(JNIEnv* env, jobject object,
+                                       fd_set *rset, int ag_fd,
+                                       jfieldID out_fd,
+                                       jfieldID out_address,
+                                       jfieldID out_channel) {
+
+    env->SetIntField(object, out_channel, -1);
+
+    if (ag_fd >= 0 && FD_ISSET(ag_fd, &rset)) {
+        return do_accept(env, object, ag_fd,
+                         out_fd, out_address, out_channel);
+    }
+    else {
+        LOGI("fd = %d, FD_ISSET() = %d",
+             ag_fd,
+             FD_ISSET(ag_fd, &rset));
+        if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
+            LOGE("WTF???");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+#endif
+#endif /* HAVE_BLUETOOTH */
+
+static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
+                                              jint timeout_ms) {
+//    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+    env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
+
+    int n = 0;
+    native_data_t *nat = get_native_data(env, object);
+#if USE_ACCEPT_DIRECTLY
+    if (nat->hf_ag_rfcomm_channel > 0) {
+        LOGI("Setting HF AG server socket to RFCOMM port %d!", 
+             nat->hf_ag_rfcomm_channel);
+        struct timeval tv;
+        int len = sizeof(tv);
+        if (getsockopt(nat->hf_ag_rfcomm_channel, 
+                       SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
+            LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
+                 nat->hf_ag_rfcomm_channel,
+                 strerror(errno),
+                 errno);
+            return JNI_FALSE;
+        }
+        LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!", 
+             (int)tv.tv_sec, (int)tv.tv_usec);
+        if (timeout_ms >= 0) {
+            tv.tv_sec = timeout_ms / 1000;
+            tv.tv_usec = 1000 * (timeout_ms % 1000);
+            if (setsockopt(nat->hf_ag_rfcomm_channel, 
+                           SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+                LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
+                     nat->hf_ag_rfcomm_channel,
+                     strerror(errno),
+                     errno);
+                return JNI_FALSE;
+            }
+            LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!", 
+                 (int)tv.tv_sec, (int)tv.tv_usec);
+        }
+
+        if (!do_accept(env, object, nat->hf_ag_rfcomm_sock, 
+                       field_mConnectingHandsfreeSocketFd,
+                       field_mConnectingHandsfreeAddress,
+                       field_mConnectingHandsfreeRfcommChannel))
+        {
+            env->SetIntField(object, field_mTimeoutRemainingMs, 0);
+            return JNI_TRUE;
+        }
+        return JNI_FALSE;
+    }
+#else
+#if USE_SELECT
+    fd_set rset;
+    FD_ZERO(&rset);
+    int cnt = 0;
+    if (nat->hf_ag_rfcomm_channel > 0) {
+        LOGI("Setting HF AG server socket to RFCOMM port %d!", 
+             nat->hf_ag_rfcomm_channel);
+        cnt++;
+        FD_SET(nat->hf_ag_rfcomm_sock, &rset);
+    }
+    if (nat->hs_ag_rfcomm_channel > 0) {
+        LOGI("Setting HS AG server socket to RFCOMM port %d!", 
+             nat->hs_ag_rfcomm_channel);
+        cnt++;
+        FD_SET(nat->hs_ag_rfcomm_sock, &rset);
+    }
+    if (cnt == 0) {
+        LOGE("Neither HF nor HS listening sockets are open!");
+        return JNI_FALSE;
+    }
+
+    struct timeval to;
+    if (timeout_ms >= 0) {
+        to.tv_sec = timeout_ms / 1000;
+        to.tv_usec = 1000 * (timeout_ms % 1000);
+    }
+    n = select(MAX(nat->hf_ag_rfcomm_sock, 
+                       nat->hs_ag_rfcomm_sock) + 1,
+                   &rset,
+                   NULL,
+                   NULL,
+                   (timeout_ms < 0 ? NULL : &to));
+    if (timeout_ms > 0) {
+        jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
+        LOGI("Remaining time %ldms", (long)remaining);
+        env->SetIntField(object, field_mTimeoutRemainingMs,
+                         remaining);
+    }
+
+    LOGI("listening select() returned %d", n);
+
+    if (n <= 0) {
+        if (n < 0)  {
+            LOGE("listening select() on RFCOMM sockets: %s (%d)",
+                 strerror(errno),
+                 errno);
+        }
+        return JNI_FALSE;
+    }
+
+    n = on_accept_set_fields(env, object, 
+                             &rset, nat->hf_ag_rfcomm_sock,
+                             field_mConnectingHandsfreeSocketFd,
+                             field_mConnectingHandsfreeAddress,
+                             field_mConnectingHandsfreeRfcommChannel);
+
+    n += on_accept_set_fields(env, object,
+                              &rset, nat->hs_ag_rfcomm_sock,
+                              field_mConnectingHeadsetSocketFd,
+                              field_mConnectingHeadsetAddress,
+                              field_mConnectingHeadsetRfcommChannel);
+
+    return !n ? JNI_TRUE : JNI_FALSE;
+#else
+    struct pollfd fds[2];
+    int cnt = 0;
+    if (nat->hf_ag_rfcomm_channel > 0) {
+//        LOGI("Setting HF AG server socket %d to RFCOMM port %d!", 
+//             nat->hf_ag_rfcomm_sock,
+//             nat->hf_ag_rfcomm_channel);
+        fds[cnt].fd = nat->hf_ag_rfcomm_sock;
+        fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
+        cnt++;
+    }
+    if (nat->hs_ag_rfcomm_channel > 0) {
+//        LOGI("Setting HS AG server socket %d to RFCOMM port %d!", 
+//             nat->hs_ag_rfcomm_sock,
+//             nat->hs_ag_rfcomm_channel);
+        fds[cnt].fd = nat->hs_ag_rfcomm_sock;
+        fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
+        cnt++;
+    }
+    if (cnt == 0) {
+        LOGE("Neither HF nor HS listening sockets are open!");
+        return JNI_FALSE;
+    }
+    n = poll(fds, cnt, timeout_ms);
+    if (n <= 0) {
+        if (n < 0)  {
+            LOGE("listening poll() on RFCOMM sockets: %s (%d)",
+                 strerror(errno),
+                 errno);
+        }
+        else {
+            env->SetIntField(object, field_mTimeoutRemainingMs, 0);
+//            LOGI("listening poll() on RFCOMM socket timed out");
+        }
+        return JNI_FALSE;
+    }
+
+    //LOGI("listening poll() on RFCOMM socket returned %d", n);
+    int err = 0;
+    for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
+        //LOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
+        if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
+            if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
+                LOGI("Accepting HF connection.\n");
+                err += do_accept(env, object, fds[cnt].fd, 
+                               field_mConnectingHandsfreeSocketFd,
+                               field_mConnectingHandsfreeAddress,
+                               field_mConnectingHandsfreeRfcommChannel);
+                n--;
+            }
+        }
+        else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
+            if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
+                LOGI("Accepting HS connection.\n");
+                err += do_accept(env, object, fds[cnt].fd, 
+                               field_mConnectingHeadsetSocketFd,
+                               field_mConnectingHeadsetAddress,
+                               field_mConnectingHeadsetRfcommChannel);
+                n--;
+            }
+        }
+    } /* for */
+
+    if (n != 0) {
+        LOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
+        return JNI_FALSE;
+    }
+
+    return !err ? JNI_TRUE : JNI_FALSE;
+#endif /* USE_SELECT */
+#endif /* USE_ACCEPT_DIRECTLY */
+#else
+    return JNI_FALSE;
+#endif /* HAVE_BLUETOOTH */
+}
+
+static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, object);
+
+    nat->hf_ag_rfcomm_sock =
+        setup_listening_socket(nat->hcidev, nat->hf_ag_rfcomm_channel);
+    if (nat->hf_ag_rfcomm_sock < 0)
+        return JNI_FALSE;
+
+    nat->hs_ag_rfcomm_sock =
+        setup_listening_socket(nat->hcidev, nat->hs_ag_rfcomm_channel);
+    if (nat->hs_ag_rfcomm_sock < 0) {
+        close(nat->hf_ag_rfcomm_sock);
+        nat->hf_ag_rfcomm_sock = -1;
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+#else
+    return JNI_FALSE;
+#endif /* HAVE_BLUETOOTH */
+}
+
+#ifdef HAVE_BLUETOOTH
+static int setup_listening_socket(int dev, int channel) {
+    struct sockaddr_rc laddr;
+    int sk, lm;
+
+    sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+    if (sk < 0) {
+        LOGE("Can't create RFCOMM socket");
+        return -1;
+    }
+
+    if (debug_no_encrypt()) {
+        lm = RFCOMM_LM_AUTH;
+    } else {
+        lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+    }
+
+	if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+		LOGE("Can't set RFCOMM link mode");
+		close(sk);
+		return -1;
+	}
+
+    laddr.rc_family = AF_BLUETOOTH;
+    bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
+    laddr.rc_channel = channel;
+
+	if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+		LOGE("Can't bind RFCOMM socket");
+		close(sk);
+		return -1;
+	}
+
+    listen(sk, 10);
+    return sk;
+}
+#endif /* HAVE_BLUETOOTH */
+
+/*
+    private native void tearDownListeningSocketsNative();
+*/
+static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, object);
+
+    if (nat->hf_ag_rfcomm_sock > 0) {
+        if (close(nat->hf_ag_rfcomm_sock) < 0) {
+            LOGE("Could not close HF server socket: %s (%d)\n",
+                 strerror(errno), errno);
+        }
+        nat->hf_ag_rfcomm_sock = -1;
+    }
+    if (nat->hs_ag_rfcomm_sock > 0) {
+        if (close(nat->hs_ag_rfcomm_sock) < 0) {
+            LOGE("Could not close HS server socket: %s (%d)\n",
+                 strerror(errno), errno);
+        }
+        nat->hs_ag_rfcomm_sock = -1;
+    }
+#endif /* HAVE_BLUETOOTH */
+}
+
+static JNINativeMethod sMethods[] = {
+     /* name, signature, funcPtr */
+
+    {"classInitNative", "()V", (void*)classInitNative},
+    {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+    {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+
+    {"setUpListeningSocketsNative", "()Z", (void *)setUpListeningSocketsNative},
+    {"tearDownListeningSocketsNative", "()V", (void *)tearDownListeningSocketsNative},
+    {"waitForHandsfreeConnectNative", "(I)Z", (void *)waitForHandsfreeConnectNative},
+};
+
+int register_android_bluetooth_BluetoothAudioGateway(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+            "android/bluetooth/BluetoothAudioGateway", sMethods,
+            NELEM(sMethods));
+}
+
+} /* namespace android */