Get last received data after connect to BLE? - android

I have an android app connects to BLE device and communicate together. after connect and bond app to device via BLE, and disconnect it, i receive last received packet and sometimes connect to device failed. see problem steps:
1. connect to ble device from android app.
2. write a characteristic successfully.
3. read a characteristic successfully.(last received data)
4. disconnect from ble device successfully.
5. try to connect app to ble device, i can't and i face below situation; even sometimes i connect but face below situation too:
I get last received data that i read from characteristic for last time.

i can't find solution anywhere, so find solution and put it here, ENJOY!
I wrote this block of code and call it after disconnect:
public void disconnect() {
if (mBluetoothGatt != null && isConnected()) {
mBluetoothGatt.close();
mBluetoothGatt = null;
}
}
mBluetoothGatt is object from BluetoothGatt Class that implements BluetoothProfile. these classes and interfaces need information about implementation of ble in android app. search the web!

Related

Android Bluetooth BLE onDescriptorWrite GATT_INSUFFICIENT_AUTHENTICATION

I have a service that connects to a Bluetooth glucose device directly via the mac address.
if (mBluetoothGatt != null) {
if (mBluetoothGatt.connect()) {
return true;
}
else {
return false;
}
}
 
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
The pairing routine and downloading of data from the device work perfect the first time after pairing, but if I try to re-connect to the device and register for notifications I receive a GATT_INSUFFICIENT_AUTHENTICATION error in my BluetoothGatt.onDescriptorWrite method.
#Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
...
if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
...
The system then prompts the user for a pin code and asks them to re-authenticate with the device, even though the BONDING STATE shows as BONDED.
I've read quite a few StackOverflow posts about BLE and some of them are conflicting or do not address the question of connection handling directly.
If we are trying to connect to a previously paired device, do we use
auto connect or not?
Do we need to re-enable notifications for a
device each time we connect to it? Or only the first time we
connect?
The device I'm using is a Moto G with KitKat 4.4.
Upgrading to Lollipop fixed the problem. The authentication now works perfectly and I do not get prompted every time I create a new connection.

BLE with Android 5.0 : How to get a device to act as Central AND Server?

I'm using two Android 5.0 devices to communicate through Bluetooth Low Energy and I wan't :
Device 1 to act as Central and Server.
Device 2 to act as Peripheral and Client.
This is the behavior I'd like to achieve :
1) Device 2 starts advertising (peripheral role).
2) Device 1 starts scanning (central role), and gets the advertising device (BluetoothDevice object) through the ScanCallback's onScanResult method.
3) I now want the advertising device (Device 2) to be notified that it has been scanned and be able to get the BluetoothDevice associated with Device 1.
4) Device 1 has an instance of BluetoothGattServer. Device 2 would now call connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) on Device 1 to get an instance of BluetoothGatt.
5) In the end, Device 1 is Server and Device 2 is Client.
So far I've found that in step 2, once Device 1 holds the BluetoothDevice for Device 2, it can only connect as client like in step 4 using connectGatt.
I might be able to use the BluetoothGattServer defined in Device 1, and call : gattServer.connect(BluetoothDevice device, boolean autoConnect) with device being Device 2.
But how will Device 2 be notified it's been connected to ?
And how will I get an instance of BluetoothGatt in Device 2 if I can't call connectGatt(Context, boolean, BluetoothGattCallback) on a BluetoothDevice?
Thank you in advance for your help !
Some documentation :
BluetoothGattServer
BluetoothDevice
1) Device 2 starts advertising (peripheral role).
Peripheral role will advertise, make sure to add CONNECTABLE
AdvertiseSettings.Builder settingBuilder = new AdvertiseSettings.Builder();
settingBuilder.setConnectable(true);
And start advertisement accordingly.
2) Device 1 starts scanning (central role), and gets the advertising device (BluetoothDevice object) through the ScanCallback's onScanResult method.
Perfect, now call connectGatt on this device(peripheral), make sure you stops the advertisement after you gets required device, otherwise you will end up sending multiple connect commands.
3) I now want the advertising device (Device 2) to be notified that it has been scanned and be able to get the BluetoothDevice associated with Device 1.
When you calls connectGatt from Central/client role, your peripheral will get a notification in its BluetoothGattServerCallback'onConnectionStateChange.
there you will know that connection has been made. though you have to register gatt Service with characteristics at peripheral side.
4) Device 1 has an instance of BluetoothGattServer. Device 2 would now call connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) on Device 1 to get an instance of BluetoothGatt.
Wrong, Device 1 will initiate connection as I have stated in point 3. both device's onConnectionStateChange will be called to know that connection has been made.
5) In the end, Device 1 is Server and Device 2 is Client.
Wrong, Device 2 is peripheral(Server), Device 1 is Monitor(Client)
You must turn it around a bit.
The scanner is the one connecting to the advertiser.
Dev1 scans dev2 adv and scan response. then dev1 should connect. Dev2 will get callback on connect.
There is no callback when someone hear your adv or request scan response on android.
Check instead 0x14 «List of 16-bit Service Solicitation UUIDs» from btsig if You want to advertise request for servers with a certain service to connect to You. It is a bit unusual ti see this used.

android BLE - automatic re-connect after spontaneous disconnect

using the android 4.4 BLE APIs on my Nexus7, i'm able to successfully interact with a peripheral BLE device -- connect, disconnect, read, write....
if however an active connection breaks for whatever reason (in this case, the peripheral is reset), i observe the following behavior....
my peripheral (by design) begins advertising after any active connection is terminated (for whatever reason); i can see this via my bluetooth packet sniffer....
i receive the onConnectionStateChanged callback as expected in my android app, at which point i invoke close() on my active BluetoothGatt instance; this is the same procedure i follow during a "normal" disconnect initiated from the client...
shortly after this, the android BLE stack tries to re-connect to the same peripheral; through the packet sniffer i can see the BLE connection request going out over the air...
my app, however, did not initiate this re-connection; indeed, i see no information from any bluetooth log suggesting this even happened!!!!
is there some "mode" in the BLE stack where it attempts to re-establish busted connections automatically???
thanks....
This happens on various Android phones whether the autoConnect flag is set to false or true.
Couldn't yet find a complete solution, it seems as the android BLE stack is spontaneously re-initiating the connection once it is getting the advertising signal again, just ignoring that it was the app that disconnected on purpose...
A partial solution may involve not using the BluetoothGatt.connect() method as explained here:
https://stackoverflow.com/a/23749770/4144487
So, a sample connect method can look like:
void connect(Context context) {
if (mGatt != null) {
mGatt.close();
}
mGatt = mDevice.connectGatt(context, false, callback);
}
To explain the importance of this issue, when it happens the peripheral thinks it is connected and my "real" app can't find it any more. At some phones like Galaxy S3 and Redmi note 3 I found that closing the bluetooth switch from the notification bar is "releasing" the peripheral and allowing me to discover the device. At others like Nexus 5x only a phone reboot will do the trick.
I've observed this happening if you use autoConnect=true when calling BluetoothGatt#connectGatt(). Generally I've found that it is best to use autoConnect=false, but with some devices you simply cannot connect unless you use true, so I usually do both. I try false first and if that fails then use true and then the behavior you're describing is something you simply have to work around.

Android Bluetooth LE: Not discovering services after connection

I'm trying to use Android's Bluetooth Low Energy to communicate with a BLE device. The first time I connect, everything works fine (connecting to GATT server works, all services and characteristics are discovered, etc.) But, if I disconnect and try to re-connect, it will connect to the GATT server, but will not be able to discover the services. I have to kill the app and restart it, and sometimes even that doesn't work.
This is the code I'm using to disconnect from the device:
public void close(View view) {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
Is there anything else that I need to do when disconnecting? There seems to be some resource that is still connected that prevents discovery of services when I try and reconnect.
I seem to have found the solution: you need to call both BluetoothGatt.disconnect() AND BluetoothGatt.close().

Unable to accept incoming Bluetooth connection in Android

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.
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);
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:
use reflection
include an additional development JAR at compile time which exposes these methods, but make sure this JAR is not packaged with your application.
We opted for #1 as our requirements were minimal.
Access the Method
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
Create a server socket
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
Fin
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.

Categories

Resources