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().
Related
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!
I'm slightly familiar with BLE and I am facing some problem with an inherited code. So the app works like that:
With BLE enabled the app scans for devices
The app displays the devices found
The user selects the device to pair with
The app pairs with the device
The problem I'm facing is that after pairing several times (it varies) the phone is not able to discover devices, hence blocking the user to pair.
I'm using GattServer to connect with the client device, and I'm reseting the services as below:
public void resetBluetoothGattServer() {
Log.i(TAG," resetBluetoothGattServer: bluetoothGattServer: "+ bluetoothGattServer);
if (bluetoothGattServer != null) {
if(!bluetoothGattServer.getServices().isEmpty()){
Log.i(TAG," resetBluetoothGattServer: clearing services on bluetooth Gatt Server");
bluetoothGattServer.clearServices();
}
Log.i(TAG," resetBluetoothGattServer: closing bluetoothGattServer");
bluetoothGattServer.close();
}
bluetoothGattServer = openGattServer();
}
Restarting the phone, turning bluetooth off and then back on, and uninstalling and installing the app won't fix the problem. The only solution is to clear the cache from the Bluetooth Share app on the android apps manager.
This post How to programmatically force bluetooth low energy service discovery on Android without using cache adresses to a similar problem but since we are not using BluetoothGatt to connect it's no a suitable solution. Neither will be to refactor the whole inherited code.
I'm asking you if there is a way to clear the cache programmatically using BluetoothGattServer.
One solution - solve this issue using reflection.
private void refreshDeviceCache(BluetoothGatt gatt) {
try {
Method localMethod = gatt.getClass().getMethod("refresh");
if(localMethod != null) {
localMethod.invoke(gatt);
}
} catch(Exception localException) {
Log.d("Exception", localException.toString());
}
}
Note : I am not recommended this way
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.
I am develop in Android and BLE. I want the App automatic reconnect to the BLE device after the BLE device disconnect but come back in the range and advertising.
I use the following code to connect to the BLE device:
public void connect(final String address) {
// TODO Auto-generated method stub
Log.w(TAG, "BluetoothLeService Connect function.");
if(mBluetoothAdapter == null || address == null){
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
//return false;
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(this, true, mGattCallback);
}
I have set the AutoConnect to the true , but it didn't reconnect when the BLE device has disconnect and come back in the range.
Why the App doesn't reconnect to the BLE device when set autoConnect to true in Android?
Did I missing something ?
Thanks in advance.
The auto connect parameter determines whether to actively connect to the remote device (or) rather passively scan and finalize the connection when the remote device is in range.
But this does not mean that a peripheral that's been disconnected for days then reappears will be reconnected.
Generally, the first ever connection to a device should be direct (autoConnect set to false) and subsequent connections to known devices should be invoked with the autoConnect parameter set to true.
Also please note, the auto connect will only work when the device is still broadcasting. If not, then it will not work.
I would prefer that you re-connect manually when the device is disconnected. If in case you do end up following this, you would need a marker to determine whether the device was actually disconnected without the user consent.
If true then unbind/unregister your service/broadcast receiver and connect again using the device address which you must have saved previously.
As per my experimentation with the BLE devices it has different behavior in different builds like Kitkat and Lollipop. Even I have observed, using ScanCallback is not so reliable introduced in API level 24.
For auto connect to work the BLE device must be active.
For me i had to support kitkat and lollipop so while connecting gatt i called as:
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
gatt = device.connectGatt(this, true, executor);
} else {
gatt = device.connectGatt(this, false, executor);
}
Now auto connect is working for me in both Lollipop and Kitkat.
I am trying to disconnect bluetooth by using
if (bluetoothAdapter != null) {
if(bluetoothAdapter.isEnabled()|bluetoothAdapter.isDiscovering()){
bluetoothAdapter.disable();
bluetoothAdapter.cancelDiscovery();
}
}
But it is not working.Can anyone suggest something on that which will be fruitful for me.
If you are disconnecting you should try and disconnect your specific connection rather than turning off bluetooth.. turning off will cause other active connections (which you might not have created also to disconnect)
If this is what you want i.e to disconnect every thing, then in the code above you should first cancel Discovery then Disable.
To do both of these you need the BLUETOOTH_ADMIN privilege.