Reputation: 3033
Maybe similar to the unanswered thread here, but we have an Android application (tested on multiple handsets and multiple Android 2.1+ versions) which needs to listen for and accept connections from a remote bluetooth device. The remote device is a digital pen, but the main point is that the pen is paired with the phone and then sends data via SPP, which uses OBEX, which uses RFComm so all that should be fine.
Currently the application works by allowing the Android device to receive the OBEX payload and then get the app to look in the bluetooth folder to pick up the payload, but we want the application to be able to talk directly to the remote device. Keep in mind the remote connects to the android phone, the phone does not connect to the pen.
Our test code is based on the sample BluetoothChat application available in the Android samples, but essentially adapter.listenUsingRfcommWithServiceRecord
never gets called and the best that we see in the Motorola Defy+ DDMS logs is:
INFO/BtOppRfcommListener(2577): Accepted connectoin from 00:07:CF:55:94:FB
INFO/BtOpp Service(2577): Start Obex Server
DEBUG/Obex ServerSession(2577): java.io.IOException: Software caused connection abort
This appears to show that the connection is accepted by Android but not made available to the application. The UUID used is the same UUID used in the JME version of the same application and was provided by the pen supplier.
Upvotes: 0
Views: 2763
Reputation: 3033
In our case the only solution we found which could reliably accept Bluetooth OPP data from a remote device was to use the 'hidden' Android API. If you check the Android source, there are additional methods defined which are annotated @hide
which excludes them from the exported Android jar and the API docs.
Using these methods should be avoided if possible and are not guaranteed to be consistent across Android versions.
There are two ways to include these in your code:
We opted for #1 as our requirements were minimal.
Class<?>[] args = new Class[] { int.class };
Method listenMethod = BluetoothAdapter.class.getMethod(listenMethod, args);
Where the method name is one of (in order of preference) listenUsingEncryptedRfcommOn
, listenUsingRfcommOn
or listenUsingUnencrytptedRfcommOn
BluetoothAdapter target = *your adapter, probably the default one*;
BluetoothServerSocket sock = (BluetoothServerSocket) (listenMethod.invoke(target, new Object[] { channel }));
Where in our case the OPP channel is 12
Provided you manage to get a BluetoothServerSocket
back (exception handling is omitted, your mileage may vary, user discretion advised, no warrantee provided etc etc) you should be able to use it to listen for incoming OPP data.
Upvotes: 1
Reputation: 2960
The most common mistake we android developers do while copying BluetoothChat app code is we don't follow the flow of that app.
The common errors while implementing this code, like "Service Discovery Failed", "Software caused connection abort", "Connection aborted by peer", "Unable to start Service Discovery" , "Connection Lost" is the outcome of neglecting the flow.
I have faced all these issues while implementing the BluetoothChat code in my app and the solution was to correct the flow.
For example in my case :
OnCreate:
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
OnStart:
if(this.mChatService == null)
this.mChatService = new BluetoothChatService(this, mHandler);
OnResume:
if ((mChatService != null) && (mBluetoothAdapter.isEnabled())) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
OnDestroy:
if(mTransferService != null) mTransferService.stop();
onActivityResult:
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
if(mChatService .getState() != BluetoothChatService.STATE_CONNECTED){
String address = data.getExtras().getString(ViewContactList.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
device = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device);
}
else{
if(messageString.length() > 0)
MyCurrentActivity.this.sendMessage(messageString);
}
In simple words, implement the code in such a way both devices are in mState = STATE_LISTEN , before you will call
mChatService.connect(device);
Upvotes: 1