blob: f3afd2a4a0bb58d0835ef7331a6fff6aa59b5835 [file] [log] [blame]
package android.bluetooth;
import java.lang.Thread;
import android.os.Message;
import android.os.Handler;
import android.util.Log;
/**
* Listen's for incoming RFCOMM connection for the headset / handsfree service.
*
* This class is planned for deletion, in favor of a generic Rfcomm class.
*
* @hide
*/
public class BluetoothAudioGateway {
private static final String TAG = "BT Audio Gateway";
private static final boolean DBG = false;
private int mNativeData;
static { classInitNative(); }
private BluetoothDevice mBluetooth;
/* in */
private int mHandsfreeAgRfcommChannel = -1;
private int mHeadsetAgRfcommChannel = -1;
/* out */
private String mConnectingHeadsetAddress;
private int mConnectingHeadsetRfcommChannel; /* -1 when not connected */
private int mConnectingHeadsetSocketFd;
private String mConnectingHandsfreeAddress;
private int mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
private int mConnectingHandsfreeSocketFd;
private int mTimeoutRemainingMs; /* in/out */
public static final int DEFAULT_HF_AG_CHANNEL = 10;
public static final int DEFAULT_HS_AG_CHANNEL = 11;
public BluetoothAudioGateway(BluetoothDevice bluetooth) {
this(bluetooth, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
}
public BluetoothAudioGateway(BluetoothDevice bluetooth,
int handsfreeAgRfcommChannel,
int headsetAgRfcommChannel) {
mBluetooth = bluetooth;
mHandsfreeAgRfcommChannel = handsfreeAgRfcommChannel;
mHeadsetAgRfcommChannel = headsetAgRfcommChannel;
initializeNativeDataNative();
}
private Thread mConnectThead;
private volatile boolean mInterrupted;
private static final int SELECT_WAIT_TIMEOUT = 1000;
private Handler mCallback;
public class IncomingConnectionInfo {
IncomingConnectionInfo(BluetoothDevice bluetooth, String address, int socketFd,
int rfcommChan) {
mBluetooth = bluetooth;
mAddress = address;
mSocketFd = socketFd;
mRfcommChan = rfcommChan;
}
public BluetoothDevice mBluetooth;
public String mAddress;
public int mSocketFd;
public int mRfcommChan;
}
public static final int MSG_INCOMING_HEADSET_CONNECTION = 100;
public static final int MSG_INCOMING_HANDSFREE_CONNECTION = 101;
public synchronized boolean start(Handler callback) {
if (mConnectThead == null) {
mCallback = callback;
mConnectThead = new Thread(TAG) {
public void run() {
if (DBG) log("Connect Thread starting");
while (!mInterrupted) {
//Log.i(TAG, "waiting for connect");
mConnectingHeadsetRfcommChannel = -1;
mConnectingHandsfreeRfcommChannel = -1;
if (waitForHandsfreeConnectNative(SELECT_WAIT_TIMEOUT) == false) {
if (mTimeoutRemainingMs > 0) {
try {
Log.i(TAG, "select thread timed out, but " +
mTimeoutRemainingMs + "ms of waiting remain.");
Thread.sleep(mTimeoutRemainingMs);
} catch (InterruptedException e) {
Log.i(TAG, "select thread was interrupted (2), exiting");
mInterrupted = true;
}
}
}
else {
Log.i(TAG, "connect notification!");
/* A device connected (most likely just one, but
it is possible for two separate devices, one
a headset and one a handsfree, to connect
simultaneously.
*/
if (mConnectingHeadsetRfcommChannel >= 0) {
Log.i(TAG, "Incoming connection from headset " +
mConnectingHeadsetAddress + " on channel " +
mConnectingHeadsetRfcommChannel);
Message msg = Message.obtain(mCallback);
msg.what = MSG_INCOMING_HEADSET_CONNECTION;
msg.obj =
new IncomingConnectionInfo(
mBluetooth,
mConnectingHeadsetAddress,
mConnectingHeadsetSocketFd,
mConnectingHeadsetRfcommChannel);
msg.sendToTarget();
}
if (mConnectingHandsfreeRfcommChannel >= 0) {
Log.i(TAG, "Incoming connection from handsfree " +
mConnectingHandsfreeAddress + " on channel " +
mConnectingHandsfreeRfcommChannel);
Message msg = Message.obtain();
msg.setTarget(mCallback);
msg.what = MSG_INCOMING_HANDSFREE_CONNECTION;
msg.obj =
new IncomingConnectionInfo(
mBluetooth,
mConnectingHandsfreeAddress,
mConnectingHandsfreeSocketFd,
mConnectingHandsfreeRfcommChannel);
msg.sendToTarget();
}
}
}
if (DBG) log("Connect Thread finished");
}
};
if (setUpListeningSocketsNative() == false) {
Log.e(TAG, "Could not set up listening socket, exiting");
return false;
}
mInterrupted = false;
mConnectThead.start();
}
return true;
}
public synchronized void stop() {
if (mConnectThead != null) {
if (DBG) log("stopping Connect Thread");
mInterrupted = true;
try {
mConnectThead.interrupt();
if (DBG) log("waiting for thread to terminate");
mConnectThead.join();
mConnectThead = null;
mCallback = null;
tearDownListeningSocketsNative();
} catch (InterruptedException e) {
Log.w(TAG, "Interrupted waiting for Connect Thread to join");
}
}
}
protected void finalize() throws Throwable {
try {
cleanupNativeDataNative();
} finally {
super.finalize();
}
}
private static native void classInitNative();
private native void initializeNativeDataNative();
private native void cleanupNativeDataNative();
private native boolean waitForHandsfreeConnectNative(int timeoutMs);
private native boolean setUpListeningSocketsNative();
private native void tearDownListeningSocketsNative();
private static void log(String msg) {
Log.d(TAG, msg);
}
}