Merge "deleted ScoSocket.java and android_bluetooth_ScoSocket.cpp"
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
deleted file mode 100644
index b65a99a..0000000
--- a/core/java/android/bluetooth/ScoSocket.java
+++ /dev/null
@@ -1,206 +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.
- */
-
-package android.bluetooth;
-
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.util.Log;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * Simple SCO Socket.
- * Currently in Android, there is no support for sending data over a SCO
- * socket - this is managed by the hardware link to the Bluetooth Chip. This
- * class is instead intended for management of the SCO socket lifetime, 
- * and is tailored for use with the headset / handsfree profiles.
- * @hide
- */
-public class ScoSocket {
-    private static final String TAG = "ScoSocket";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;  // even more logging
-
-    public static final int STATE_READY = 1;    // Ready for use. No threads or sockets
-    public static final int STATE_ACCEPT = 2;   // accept() thread running
-    public static final int STATE_CONNECTING = 3;  // connect() thread running
-    public static final int STATE_CONNECTED = 4;   // connected, waiting for close()
-    public static final int STATE_CLOSED = 5;   // was connected, now closed.
-
-    private int mState;
-    private int mNativeData;
-    private Handler mHandler;
-    private int mAcceptedCode;
-    private int mConnectedCode;
-    private int mClosedCode;
-
-    private WakeLock mWakeLock;  // held while in STATE_CONNECTING
-
-    static {
-        classInitNative();
-    }
-    private native static void classInitNative();
-
-    public ScoSocket(PowerManager pm, Handler handler, int acceptedCode, int connectedCode,
-                     int closedCode) {
-        initNative();
-        mState = STATE_READY;
-        mHandler = handler;
-        mAcceptedCode = acceptedCode;
-        mConnectedCode = connectedCode;
-        mClosedCode = closedCode;
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ScoSocket");
-        mWakeLock.setReferenceCounted(false);
-        if (VDBG) log(this + " SCO OBJECT CTOR");
-    }
-    private native void initNative();
-
-    protected void finalize() throws Throwable {
-        try {
-            if (VDBG) log(this + " SCO OBJECT DTOR");
-            destroyNative();
-            releaseWakeLockNow();
-        } finally {
-            super.finalize();
-        }
-    }
-    private native void destroyNative();
-
-    /** Connect this SCO socket to the given BT address.
-     *  Does not block.
-     */
-    public synchronized boolean connect(String address, String name) {
-        if (DBG) log("connect() " + this);
-        if (mState != STATE_READY) {
-            if (DBG) log("connect(): Bad state");
-            return false;
-        }
-        acquireWakeLock();
-        if (connectNative(address, name)) {
-            mState = STATE_CONNECTING;
-            return true;
-        } else {
-            mState = STATE_CLOSED;
-            releaseWakeLockNow();
-            return false;
-        }
-    }
-    private native boolean connectNative(String address, String name);
-
-    /** Accept incoming SCO connections.
-     *  Does not block.
-     */
-    public synchronized boolean accept() {
-        if (VDBG) log("accept() " + this);
-        if (mState != STATE_READY) {
-            if (DBG) log("Bad state");
-            return false;
-        }
-        if (acceptNative()) {
-            mState = STATE_ACCEPT;
-            return true;
-        } else {
-            mState = STATE_CLOSED;
-            return false;
-        }
-    }
-    private native boolean acceptNative();
-
-    public synchronized void close() {
-        if (DBG) log(this + " SCO OBJECT close() mState = " + mState);
-        acquireWakeLock();
-        mState = STATE_CLOSED;
-        closeNative();
-        releaseWakeLock();
-    }
-    private native void closeNative();
-
-    public synchronized int getState() {
-        return mState;
-    }
-
-    private synchronized void onConnected(int result) {
-        if (VDBG) log(this + " onConnected() mState = " + mState + " " + this);
-        if (mState != STATE_CONNECTING) {
-            if (DBG) log("Strange state, closing " + mState + " " + this);
-            return;
-        }
-        if (result >= 0) {
-            mState = STATE_CONNECTED;
-        } else {
-            mState = STATE_CLOSED;
-        }
-        mHandler.obtainMessage(mConnectedCode, mState, -1, this).sendToTarget();
-        releaseWakeLockNow();
-    }
-
-    private synchronized void onAccepted(int result) {
-        if (VDBG) log("onAccepted() " + this);
-        if (mState != STATE_ACCEPT) {
-            if (DBG) log("Strange state " + this);
-            return;
-        }
-        if (result >= 0) {
-            mState = STATE_CONNECTED;
-        } else {
-            mState = STATE_CLOSED;
-        }
-        mHandler.obtainMessage(mAcceptedCode, mState, -1, this).sendToTarget();
-    }
-
-    private synchronized void onClosed() {
-        if (DBG) log("onClosed() " + this);
-        if (mState != STATE_CLOSED) {
-            mState = STATE_CLOSED;
-            mHandler.obtainMessage(mClosedCode, mState, -1, this).sendToTarget();
-            releaseWakeLock();
-        }
-    }
-
-    private void acquireWakeLock() {
-        if (!mWakeLock.isHeld()) {
-            mWakeLock.acquire();
-            if (VDBG) log("mWakeLock.acquire() " + this);
-        }
-    }
-
-    private void releaseWakeLock() {
-        if (mWakeLock.isHeld()) {
-            // Keep apps processor awake for a further 2 seconds.
-            // This is a hack to resolve issue http://b/1616263 - in which
-            // we are left in a 80 mA power state when remotely terminating a
-            // call while connected to BT headset "HTC BH S100 " with A2DP and
-            // HFP profiles.
-            if (VDBG) log("mWakeLock.release() in 2 sec" + this);
-            mWakeLock.acquire(2000);
-        }
-    }
-
-    private void releaseWakeLockNow() {
-        if (mWakeLock.isHeld()) {
-            if (VDBG) log("mWakeLock.release() now" + this);
-            mWakeLock.release();
-        }
-    }
-
-    private void log(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
deleted file mode 100644
index 94e4409..0000000
--- a/core/jni/android_bluetooth_ScoSocket.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
-** Copyright 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.
-*/
-
-#define LOG_TAG "bluetooth_ScoSocket.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"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-
-#define MAX_LINE 255
-
-/*
- * Defines the module strings used in the blacklist file.
- * These are used by consumers of the blacklist file to see if the line is
- * used by that module.
- */
-#define SCO_BLACKLIST_MODULE_NAME "scoSocket"
-
-
-/* Define the type strings used in the blacklist file. */
-#define BLACKLIST_BY_NAME "name"
-#define BLACKLIST_BY_PARTIAL_NAME "partial_name"
-#define BLACKLIST_BY_OUI "vendor_oui"
-
-#endif
-
-/* Ideally, blocking I/O on a SCO socket would return when another thread
- * calls close(). However it does not right now, in fact close() on a SCO
- * socket has strange behavior (returns a bogus value) when other threads
- * are performing blocking I/O on that socket. So, to workaround, we always
- * call close() from the same thread that does blocking I/O. This requires the
- * use of a socketpair to signal the blocking I/O to abort.
- *
- * Unfortunately I don't know a way to abort connect() yet, but at least this
- * times out after the BT page timeout (10 seconds currently), so the thread
- * will die eventually. The fact that the thread can outlive
- * the Java object forces us to use a mutex in destoryNative().
- *
- * The JNI API is entirely async.
- *
- * Also note this class deals only with SCO connections, not with data
- * transmission.
- */
-namespace android {
-#ifdef HAVE_BLUETOOTH
-
-static JavaVM *jvm;
-static jfieldID field_mNativeData;
-static jmethodID method_onAccepted;
-static jmethodID method_onConnected;
-static jmethodID method_onClosed;
-
-struct thread_data_t;
-static void *work_thread(void *arg);
-static int connect_work(const char *address, uint16_t sco_pkt_type);
-static int accept_work(int signal_sk);
-static void wait_for_close(int sk, int signal_sk);
-static void closeNative(JNIEnv *env, jobject object);
-
-static void parseBlacklist(void);
-static uint16_t getScoType(char *address, const char *name);
-
-#define COMPARE_STRING(key, s) (!strncmp(key, s, strlen(s)))
-
-/* Blacklist data */
-typedef struct scoBlacklist {
-    int fieldType;
-    char *value;
-    uint16_t scoType;
-    struct scoBlacklist *next;
-} scoBlacklist_t;
-
-#define BL_TYPE_NAME 1   // Field type is name string
-
-static scoBlacklist_t *blacklist = NULL;
-
-/* shared native data - protected by mutex */
-typedef struct {
-    pthread_mutex_t mutex;
-    int signal_sk;        // socket to signal blocked I/O to unblock
-    jobject object;       // JNI global ref to the Java object
-    thread_data_t *thread_data;  // pointer to thread local data
-                                 // max 1 thread per sco socket
-} native_data_t;
-
-/* thread local data */
-struct thread_data_t {
-    native_data_t *nat;
-    bool is_accept;        // accept (listening) or connect (outgoing) thread
-    int signal_sk;         // socket for thread to listen for unblock signal
-    char address[BTADDR_SIZE];  // BT addres as string
-    uint16_t sco_pkt_type;   // SCO packet types supported
-};
-
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
-    return (native_data_t *)(env->GetIntField(object, field_mNativeData));
-}
-
-static uint16_t str2scoType (char *key) {
-    LOGV("%s: key = %s", __FUNCTION__, key);
-    if (COMPARE_STRING(key, "ESCO_HV1"))
-        return ESCO_HV1;
-    if (COMPARE_STRING(key, "ESCO_HV2"))
-        return ESCO_HV2;
-    if (COMPARE_STRING(key, "ESCO_HV3"))
-        return ESCO_HV3;
-    if (COMPARE_STRING(key, "ESCO_EV3"))
-        return ESCO_EV3;
-    if (COMPARE_STRING(key, "ESCO_EV4"))
-        return ESCO_EV4;
-    if (COMPARE_STRING(key, "ESCO_EV5"))
-        return ESCO_EV5;
-    if (COMPARE_STRING(key, "ESCO_2EV3"))
-        return ESCO_2EV3;
-    if (COMPARE_STRING(key, "ESCO_3EV3"))
-        return ESCO_3EV3;
-    if (COMPARE_STRING(key, "ESCO_2EV5"))
-        return ESCO_2EV5;
-    if (COMPARE_STRING(key, "ESCO_3EV5"))
-        return ESCO_3EV5;
-    if (COMPARE_STRING(key, "SCO_ESCO_MASK"))
-        return SCO_ESCO_MASK;
-    if (COMPARE_STRING(key, "EDR_ESCO_MASK"))
-        return EDR_ESCO_MASK;
-    if (COMPARE_STRING(key, "ALL_ESCO_MASK"))
-        return ALL_ESCO_MASK;
-    LOGE("Unknown SCO Type (%s) skipping",key);
-    return 0;
-}
-
-static void parseBlacklist(void) {
-    const char *filename = "/etc/bluetooth/blacklist.conf";
-    char line[MAX_LINE];
-    scoBlacklist_t *list = NULL;
-    scoBlacklist_t *newelem;
-
-    LOGV(__FUNCTION__);
-
-    /* Open file */
-    FILE *fp = fopen(filename, "r");
-    if(!fp) {
-        LOGE("Error(%s)opening blacklist file", strerror(errno));
-        return;
-    }
-
-    while (fgets(line, MAX_LINE, fp) != NULL) {
-        if ((COMPARE_STRING(line, "//")) || (!strcmp(line, "")))
-            continue;
-        char *module = strtok(line,":");
-        if (COMPARE_STRING(module, SCO_BLACKLIST_MODULE_NAME)) {
-            newelem = (scoBlacklist_t *)calloc(1, sizeof(scoBlacklist_t));
-            if (newelem == NULL) {
-                LOGE("%s: out of memory!", __FUNCTION__);
-                return;
-            }
-            // parse line
-            char *type = strtok(NULL, ",");
-            char *valueList = strtok(NULL, ",");
-            char *paramList = strtok(NULL, ",");
-            if (COMPARE_STRING(type, BLACKLIST_BY_NAME)) {
-                // Extract Name from Value list
-                newelem->fieldType = BL_TYPE_NAME;
-                newelem->value = (char *)calloc(1, strlen(valueList));
-                if (newelem->value == NULL) {
-                    LOGE("%s: out of memory!", __FUNCTION__);
-                    continue;
-                }
-                valueList++;  // Skip open quote
-                strncpy(newelem->value, valueList, strlen(valueList) - 1);
-
-                // Get Sco Settings from Parameters
-                char *param = strtok(paramList, ";");
-                uint16_t scoTypes = 0;
-                while (param != NULL) {
-                    uint16_t sco;
-                    if (param[0] == '-') {
-                        param++;
-                        sco = str2scoType(param);
-                        if (sco != 0)
-                            scoTypes &= ~sco;
-                    } else if (param[0] == '+') {
-                        param++;
-                        sco = str2scoType(param);
-                        if (sco != 0)
-                            scoTypes |= sco;
-                    } else if (param[0] == '=') {
-                        param++;
-                        sco = str2scoType(param);
-                        if (sco != 0)
-                            scoTypes = sco;
-                    } else {
-                        LOGE("Invalid SCO type must be =, + or -");
-                    }
-                    param = strtok(NULL, ";");
-                }
-                newelem->scoType = scoTypes;
-            } else {
-                LOGE("Unknown SCO type entry in Blacklist file");
-                continue;
-            }
-            if (list) {
-                list->next = newelem;
-                list = newelem;
-            } else {
-                blacklist = list = newelem;
-            }
-            LOGI("Entry name = %s ScoTypes = 0x%x", newelem->value,
-                 newelem->scoType);
-        }
-    }
-    fclose(fp);
-    return;
-}
-static uint16_t getScoType(char *address, const char *name) {
-    uint16_t ret = 0;
-    scoBlacklist_t *list = blacklist;
-
-    while (list != NULL) {
-        if (list->fieldType == BL_TYPE_NAME) {
-            if (COMPARE_STRING(name, list->value)) {
-                ret = list->scoType;
-                break;
-            }
-        }
-        list = list->next;
-    }
-    LOGI("%s %s - 0x%x",  __FUNCTION__, name, ret);
-    return ret;
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-    if (env->GetJavaVM(&jvm) < 0) {
-        LOGE("Could not get handle to the VM");
-    }
-    field_mNativeData = get_field(env, clazz, "mNativeData", "I");
-    method_onAccepted = env->GetMethodID(clazz, "onAccepted", "(I)V");
-    method_onConnected = env->GetMethodID(clazz, "onConnected", "(I)V");
-    method_onClosed = env->GetMethodID(clazz, "onClosed", "()V");
-
-    /* Read the blacklist file in here */
-    parseBlacklist();
-#endif
-}
-
-/* Returns false if a serious error occured */
-static jboolean initNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-
-    native_data_t *nat = (native_data_t *) calloc(1, sizeof(native_data_t));
-    if (nat == NULL) {
-        LOGE("%s: out of memory!", __FUNCTION__);
-        return JNI_FALSE;
-    }
-
-    pthread_mutex_init(&nat->mutex, NULL);
-    env->SetIntField(object, field_mNativeData, (jint)nat);
-    nat->signal_sk = -1;
-    nat->object = NULL;
-    nat->thread_data = NULL;
-
-#endif
-    return JNI_TRUE;
-}
-
-static void destroyNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-    native_data_t *nat = get_native_data(env, object);
-    
-    closeNative(env, object);
-    
-    pthread_mutex_lock(&nat->mutex);
-    if (nat->thread_data != NULL) {
-        nat->thread_data->nat = NULL;
-    }
-    pthread_mutex_unlock(&nat->mutex);
-    pthread_mutex_destroy(&nat->mutex);
-
-    free(nat);
-#endif
-}
-
-static jboolean acceptNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-    native_data_t *nat = get_native_data(env, object);
-    int signal_sks[2];
-    pthread_t thread;
-    struct thread_data_t *data = NULL;
-
-    pthread_mutex_lock(&nat->mutex);
-    if (nat->signal_sk != -1) {
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-
-    // setup socketpair to pass messages between threads
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sks) < 0) {
-        LOGE("%s: socketpair() failed: %s", __FUNCTION__, strerror(errno));
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-    nat->signal_sk = signal_sks[0];
-    nat->object = env->NewGlobalRef(object);
-
-    data = (thread_data_t *)calloc(1, sizeof(thread_data_t));
-    if (data == NULL) {
-        LOGE("%s: out of memory", __FUNCTION__);
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-    nat->thread_data = data;
-    pthread_mutex_unlock(&nat->mutex);
-
-    data->signal_sk = signal_sks[1];
-    data->nat = nat;
-    data->is_accept = true;
-
-    if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
-        LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
-        return JNI_FALSE;
-    }
-    return JNI_TRUE;
-
-#endif
-    return JNI_FALSE;
-}
-
-static jboolean connectNative(JNIEnv *env, jobject object, jstring address,
-        jstring name) {
-
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-    native_data_t *nat = get_native_data(env, object);
-    int signal_sks[2];
-    pthread_t thread;
-    struct thread_data_t *data;
-    const char *c_address;
-    const char *c_name;
-
-    pthread_mutex_lock(&nat->mutex);
-    if (nat->signal_sk != -1) {
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-
-    // setup socketpair to pass messages between threads
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sks) < 0) {
-        LOGE("%s: socketpair() failed: %s\n", __FUNCTION__, strerror(errno));
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-    nat->signal_sk = signal_sks[0];
-    nat->object = env->NewGlobalRef(object);
-
-    data = (thread_data_t *)calloc(1, sizeof(thread_data_t));
-    if (data == NULL) {
-        LOGE("%s: out of memory", __FUNCTION__);
-        pthread_mutex_unlock(&nat->mutex);
-        return JNI_FALSE;
-    }
-    pthread_mutex_unlock(&nat->mutex);
-
-    data->signal_sk = signal_sks[1];
-    data->nat = nat;
-    c_address = env->GetStringUTFChars(address, NULL);
-    strlcpy(data->address, c_address, BTADDR_SIZE);
-    env->ReleaseStringUTFChars(address, c_address);
-    data->is_accept = false;
-
-    if (name == NULL) {
-        LOGE("%s: Null pointer passed in for device name", __FUNCTION__);
-        data->sco_pkt_type = 0;
-    } else {
-        c_name = env->GetStringUTFChars(name, NULL);
-        /* See if this device is in the black list */
-        data->sco_pkt_type = getScoType(data->address, c_name);
-        env->ReleaseStringUTFChars(name, c_name);
-    }
-    if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
-        LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
-        return JNI_FALSE;
-    }
-    return JNI_TRUE;
-
-#endif
-    return JNI_FALSE;
-}
-
-static void closeNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-    native_data_t *nat = get_native_data(env, object);
-    int signal_sk;
-
-    pthread_mutex_lock(&nat->mutex);
-    signal_sk = nat->signal_sk;
-    nat->signal_sk = -1;
-    env->DeleteGlobalRef(nat->object);
-    nat->object = NULL;
-    pthread_mutex_unlock(&nat->mutex);
-
-    if (signal_sk >= 0) {
-        LOGV("%s: signal_sk = %d", __FUNCTION__, signal_sk);
-        unsigned char dummy;
-        write(signal_sk, &dummy, sizeof(dummy));
-        close(signal_sk);
-    }
-#endif
-}
-
-#ifdef HAVE_BLUETOOTH
-/* thread entry point */
-static void *work_thread(void *arg) {
-    JNIEnv* env;
-    thread_data_t *data = (thread_data_t *)arg;
-    int sk;
-
-    LOGV(__FUNCTION__);
-    if (jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
-        LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
-        return NULL;
-    }
-
-    /* connect the SCO socket */
-    if (data->is_accept) {
-        LOGV("SCO OBJECT %p ACCEPT #####", data->nat->object);
-        sk = accept_work(data->signal_sk);
-        LOGV("SCO OBJECT %p END ACCEPT *****", data->nat->object);
-    } else {
-        sk = connect_work(data->address, data->sco_pkt_type);
-    }
-
-    /* callback with connection result */
-    if (data->nat == NULL) {
-        LOGV("%s: object destroyed!", __FUNCTION__);
-        goto done;
-    }
-    pthread_mutex_lock(&data->nat->mutex);
-    if (data->nat->object == NULL) {
-        pthread_mutex_unlock(&data->nat->mutex);
-        LOGV("%s: callback cancelled", __FUNCTION__);
-        goto done;
-    }
-    if (data->is_accept) {
-        env->CallVoidMethod(data->nat->object, method_onAccepted, sk);
-    } else {
-        env->CallVoidMethod(data->nat->object, method_onConnected, sk);
-    }
-    pthread_mutex_unlock(&data->nat->mutex);
-
-    if (sk < 0) {
-        goto done;
-    }
-
-    LOGV("SCO OBJECT %p %d CONNECTED +++ (%s)", data->nat->object, sk,
-         data->is_accept ? "in" : "out");
-
-    /* wait for the socket to close */
-    LOGV("wait_for_close()...");
-    wait_for_close(sk, data->signal_sk);
-    LOGV("wait_for_close() returned");
-
-    /* callback with close result */
-    if (data->nat == NULL) {
-        LOGV("%s: object destroyed!", __FUNCTION__);
-        goto done;
-    }
-    pthread_mutex_lock(&data->nat->mutex);
-    if (data->nat->object == NULL) {
-        LOGV("%s: callback cancelled", __FUNCTION__);
-    } else {
-        env->CallVoidMethod(data->nat->object, method_onClosed);
-    }
-    pthread_mutex_unlock(&data->nat->mutex);
-
-done:
-    if (sk >= 0) {
-        close(sk);
-        LOGV("SCO OBJECT %p %d CLOSED --- (%s)", data->nat->object, sk, data->is_accept ? "in" : "out");
-    }
-    if (data->signal_sk >= 0) {
-        close(data->signal_sk);
-    }
-    LOGV("SCO socket closed");
-
-    if (data->nat != NULL) {
-        pthread_mutex_lock(&data->nat->mutex);
-        env->DeleteGlobalRef(data->nat->object);
-        data->nat->object = NULL;
-        data->nat->thread_data = NULL;
-        pthread_mutex_unlock(&data->nat->mutex);
-    }
-
-    free(data);
-    if (jvm->DetachCurrentThread() != JNI_OK) {
-        LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
-    }
-
-    LOGV("work_thread() done");
-    return NULL;
-}
-
-static int accept_work(int signal_sk) {
-    LOGV(__FUNCTION__);
-    int sk;
-    int nsk;
-    int addr_sz;
-    int max_fd;
-    fd_set fds;
-    struct sockaddr_sco addr;
-
-    sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
-    if (sk < 0) {
-        LOGE("%s socket() failed: %s", __FUNCTION__, strerror(errno));
-        return -1;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sco_family = AF_BLUETOOTH;
-    memcpy(&addr.sco_bdaddr, BDADDR_ANY, sizeof(bdaddr_t));
-    if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        LOGE("%s bind() failed: %s", __FUNCTION__, strerror(errno));
-        goto error;
-    }
-
-    if (listen(sk, 1)) {
-        LOGE("%s: listen() failed: %s", __FUNCTION__, strerror(errno));
-        goto error;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr_sz = sizeof(addr);
-
-    FD_ZERO(&fds);
-    FD_SET(sk, &fds);
-    FD_SET(signal_sk, &fds);
-
-    max_fd = (sk > signal_sk) ? sk : signal_sk;
-    LOGI("Listening SCO socket...");
-    while (select(max_fd + 1, &fds, NULL, NULL, NULL) < 0) {
-        if (errno != EINTR) {
-            LOGE("%s: select() failed: %s", __FUNCTION__, strerror(errno));
-            goto error;
-        }
-        LOGV("%s: select() EINTR, retrying", __FUNCTION__);
-    }
-    LOGV("select() returned");
-    if (FD_ISSET(signal_sk, &fds)) {
-        // signal to cancel listening
-        LOGV("cancelled listening socket, closing");
-        goto error;
-    }
-    if (!FD_ISSET(sk, &fds)) {
-        LOGE("error: select() returned >= 0 with no fds set");
-        goto error;
-    }
-
-    nsk = accept(sk, (struct sockaddr *)&addr, &addr_sz);
-    if (nsk < 0) {
-        LOGE("%s: accept() failed: %s", __FUNCTION__, strerror(errno));
-        goto error;
-    }
-    LOGI("Connected SCO socket (incoming)");
-    close(sk);  // The listening socket
-
-    return nsk;
-
-error:
-    close(sk);
-
-    return -1;
-}
-
-static int connect_work(const char *address, uint16_t sco_pkt_type) {
-    LOGV(__FUNCTION__);
-    struct sockaddr_sco addr;
-    int sk = -1;
-
-    sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
-    if (sk < 0) {
-        LOGE("%s: socket() failed: %s", __FUNCTION__, strerror(errno));
-        return -1;
-    }
-
-    /* Bind to local address */
-    memset(&addr, 0, sizeof(addr));
-    addr.sco_family = AF_BLUETOOTH;
-    memcpy(&addr.sco_bdaddr, BDADDR_ANY, sizeof(bdaddr_t));
-    if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        LOGE("%s: bind() failed: %s", __FUNCTION__, strerror(errno));
-        goto error;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sco_family = AF_BLUETOOTH;
-    get_bdaddr(address, &addr.sco_bdaddr);
-    addr.sco_pkt_type = sco_pkt_type;
-    LOGI("Connecting to socket");
-    while (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-        if (errno != EINTR) {
-            LOGE("%s: connect() failed: %s", __FUNCTION__, strerror(errno));
-            goto error;
-        }
-        LOGV("%s: connect() EINTR, retrying", __FUNCTION__);
-    }
-    LOGI("SCO socket connected (outgoing)");
-
-    return sk;
-
-error:
-    if (sk >= 0) close(sk);
-    return -1;
-}
-
-static void wait_for_close(int sk, int signal_sk) {
-    LOGV(__FUNCTION__);
-    pollfd p[2];
-
-    memset(p, 0, 2 * sizeof(pollfd));
-    p[0].fd = sk;
-    p[1].fd = signal_sk;
-    p[1].events = POLLIN | POLLPRI;
-
-    LOGV("poll...");
-
-    while (poll(p, 2, -1) < 0) {  // blocks
-        if (errno != EINTR) {
-            LOGE("%s: poll() failed: %s", __FUNCTION__, strerror(errno));
-            break;
-        }
-        LOGV("%s: poll() EINTR, retrying", __FUNCTION__);
-    }
-
-    LOGV("poll() returned");
-}
-#endif
-
-static JNINativeMethod sMethods[] = {
-    {"classInitNative", "()V", (void*)classInitNative},
-    {"initNative", "()V", (void *)initNative},
-    {"destroyNative", "()V", (void *)destroyNative},
-    {"connectNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)connectNative},
-    {"acceptNative", "()Z", (void *)acceptNative},
-    {"closeNative", "()V", (void *)closeNative},
-};
-
-int register_android_bluetooth_ScoSocket(JNIEnv *env) {
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/bluetooth/ScoSocket", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */