I'm working on making an Android application (EDIT1: developing on 4.0.3 on Nexsus S's) that shares data P2P over Bluetooth and have run into a nasty snag on making the two devices connect. Our app uses NFC to pass the MAC address of one device to another. The sender then creates a BlueToothServer socket instance and calls accept, while the receiver creates a BluetoothDevice instance with the MAC address it received and attempts to connect.
The problem we're having is with the returned BluetoothSocket from accept(). The documentation for it clearly states that it should return a connected socket, but it instead returns a disconnected one which cannot even then be connected by calling connect(). I've checked the MAC address the socket has and it clears out, and the mere fact accept() returned implies that is successfully connected long enough to make the socket, so I'm at a loss here for what else to try.
It is also worth mentioning that the receiver's BluetoothSocket claims during this time that it actually is connected. Obviously it just simply hangs while it waits for data that never comes from the other device, but using checkpoints in multiple places we know that up until that time it is always claiming to be connected.
Any help or advice on this would be appreciated.
Other relevant information:
The sender and receiver are the same app, but represent different activities. This app is a game in which joining the game requires somebody who has the game to give it to someone else, which is initiated by the NFC (the data that is ultimately suppose to be sent over Bluetooth is the game data necessary for joining). The sender has the game and is in an activity that gives it away, while the receiver is in an activity that wants to receive it and then move into the giving away activity to allow them to pass it on to someone else. To make this clear now, while it would be possible for us to merge these two activities right now, we are going to be using the same technique later on as part of the actual game where it will not be possible to make sure both are on the same activity, so we need to overcome the different activity problem at some point anyway.
We are also sure that the UUIDs match properly. We have a global class with a constant UUID that we just generated at some point and use. It would appear depending on your purpose that UUIDs need to be something specific in certain instances, but so I have understood it as well, for this particular use, we were suppose to generate our own.
The BluetoothServerSocket is created and accept() called from it as part of a callback for NdefPushbackComplete, so the other phone definitely has the Ndef message before the sender begins to setup its server socket.
Neither the client or server bluetooth code is running on its own thread as commonly seen online, which is by design since we want the exchange to happen completely before either side can do anything else.
If I neglected to mention anything important, I would be happy to provide it. Finally, here is the client and server side code. This version of it uses an insecure socket, however I have tried it both ways and the phones being used to test this are paired.
Client:
String s = new String(msg.getRecords()[0].getPayload());
otherBluetoothMACAddress = s;
Log.d(DEV, "WaitingToGetGame: Other BT Address... "
+ otherBluetoothMACAddress);
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
Log.d(DEV, "WaitingToGetGame: Getting remote device");
BluetoothDevice bluetoothDevice = bluetoothAdapter
.getRemoteDevice(otherBluetoothMACAddress);
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
try
{
Log.d(DEV, "WaitingToGetGame: Getting BluetoothSocket");
bluetoothSocket = bluetoothDevice
.createInsecureRfcommSocketToServiceRecord(SDP_UUID);
Log.d(DEV, "WaitingToGetGame: Connecting...");
bluetoothSocket.connect();
Log.d(DEV,
"WaitingToGetGame: Bluetooth "
+ ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
+ "Connected.");
Log.d(DEV, "WaitingToGetGame: Getting input stream");
bluetoothInputStream = bluetoothSocket.getInputStream();
Log.d(DEV,
"WaitingToGetGame: Bluetooth "
+ ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
+ "Connected.");
Log.d(DEV, "WaitingToGetGame: Getting output stream");
bluetoothOutputStream = bluetoothSocket.getOutputStream();
Log.d(DEV,
"WaitingToGetGame: Bluetooth "
+ ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
+ "Connected.");
objectInputStream = new ObjectInputStream(bluetoothInputStream);
objectOutputStream = new ObjectOutputStream(bluetoothOutputStream);
Log.d(DEV, this.getClass().getSimpleName() + ": Receiving game data");
game = (Game) objectInputStream.readObject();
Log.d(DEV, this.getClass().getSimpleName() + ": Sending acknowledgment.");
objectOutputStream.writeObject(new Boolean(true));
objectInputStream.close();
objectOutputStream.close();
bluetoothInputStream.close();
bluetoothOutputStream.close();
bluetoothInputStream = null; // GC
bluetoothOutputStream = null; // GC
bluetoothSocket.close();
bluetoothSocket = null;
Server:
BluetoothServerSocket bluetoothServerSocket = null;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
try
{
Log.d(DEV, this.getClass().getSimpleName()
+ ": Getting BluetoothServerSocket");
// bluetoothServerSocket = bluetoothAdapter
// .listenUsingRfcommWithServiceRecord(user.getName(), SDP_UUID);
bluetoothServerSocket = bluetoothAdapter
.listenUsingInsecureRfcommWithServiceRecord(user.getName(), SDP_UUID);
Log.d(DEV, this.getClass().getSimpleName() + ": Waiting for connection.");
bluetoothSocket = bluetoothServerSocket.accept();
bluetoothServerSocket.close();
BluetoothDevice dev = bluetoothSocket.getRemoteDevice();
Log.d(DEV, dev.getAddress());
Log.d(DEV, this.getClass().getSimpleName() + ": Bluetooth "
+ ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
+ "Connected.");
// At this point bluetoothSocket should be ready to use.
Log.d(DEV, this.getClass().getSimpleName() + ": Getting input stream");
bluetoothInputStream = bluetoothSocket.getInputStream();
Log.d(DEV, this.getClass().getSimpleName() + ": Bluetooth "
+ ((bluetoothSocket.isConnected()) ? ("is ") : ("is NOT "))
+ "Connected.");
Log.d(DEV, this.getClass().getSimpleName() + ": Getting output stream");
bluetoothOutputStream = bluetoothSocket.getOutputStream();
// Log.d(DEV, this.getClass().getSimpleName()
// + ": Attempting direct connect()");
// bluetoothSocket.connect();
objectInputStream = new ObjectInputStream(bluetoothInputStream);
objectOutputStream = new ObjectOutputStream(bluetoothOutputStream);
Log.d(DEV, this.getClass().getSimpleName() + ": Sending game data.");
objectOutputStream.writeObject(game);
Log.d(DEV, this.getClass().getSimpleName() + ": Waiting for response.");
Boolean response = (Boolean) objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
bluetoothInputStream.close();
bluetoothOutputStream.close();
bluetoothInputStream = null; // GC
bluetoothOutputStream = null; // GC
bluetoothSocket.close();
bluetoothSocket = null;
}// try
catch( IOException e )
{
Log.d(
DEV,
this.getClass().getSimpleName() + ": "
+ java.util.Arrays.toString(e.getStackTrace()));
e.printStackTrace();
return;
}
catch( ClassNotFoundException e )
{
// TODO Auto-generated catch block
e.printStackTrace();
}