Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Totally Disconnect a Bluetooth Low Energy Device

I connect to a BLE device with the connectGatt() method in Android. This works great.

When I disconnect I use the following:

private void disconnectDevice() {
    gatt.disconnect();
}

When I receive the callback I do a close.

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        switch (newState) {
            case BluetoothProfile.STATE_CONNECTED:
                Log.d("BLED-GATT", "STATE_CONNECTED");
                setUIConnectionStatus("Discover services on device...", Color.YELLOW);
                checkEnableAddButton(simpleTrackEditText.getText().toString());
                gatt.discoverServices();
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
                Log.d("BLED-GATT", "STATE_DISCONNECTED");
                setUIConnectionStatus("Not Connected!", Color.RED);
                gatt.close();
                break;
            default:
                Log.d("BLED-GATT", "STATE_OTHER");
        }
    }
}

This is executed and I can no longer control the device after calling disconnectDevice(). The device itself seems to think that it is still connected since I cant put it in broadcasting visibility mode (which happens if it already has a connection). However, if I kill the application and open it again then I can set the device in broadcasting mode. This tells me the app was not properly disconnected.

Any idea what I missed here?

like image 519
nilsi Avatar asked Mar 14 '16 11:03

nilsi


People also ask

How do I turn off Bluetooth low energy Android?

Users can disable system-level Bluetooth background scanning by going to Settings > Security & Location > Location > Scanning and disabling the toggle for Bluetooth scanning. This does not affect BLE scanning for location or local devices.

Does Bluetooth low energy require location?

Location Permission is mandatory on Android Yes, we were as surprised as you are. Bluetooth is required to setup, update and sync your FitBark device. In 2019, Android made it mandatory for any app to have location permissions in order to work with Bluetooth devices.

What is BLE in Android?

Android provides built-in platform support for Bluetooth Low Energy (BLE) in the central role and provides APIs that apps can use to discover devices, query for services, and transmit information. Common use cases include the following: Transferring small amounts of data between nearby devices.


4 Answers

The problem was that I during scanning was connecting to the same device multiple times causing my application to have many connections open at the same time. Adding !isConnected() solved the problem:

/**
 * Connects to the device. Does nothing if already connected.
 * @param macAddress the address of the device.
 */
private void connectDevice(String macAddress) {
    if (isConnected()) {
        return;
    }
    
    device = bluetoothAdapter.getRemoteDevice(macAddress);

    if (device == null) {
        showToast("Device not available");
    } else {
        showToast("Connecting...");
        gatt = device.connectGatt(this, true, gattCallback);
    }
}
like image 116
nilsi Avatar answered Oct 17 '22 15:10

nilsi


That's totally logic because you are not disconnecting before closing Gatt.

public void disconnect() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.disconnect();
    }

try to call this method before closing your GATT

like image 40
Fakher Avatar answered Oct 17 '22 15:10

Fakher


I experienced same problem and I found two possible root cause as follows: 1. Was same as @nilsi answer, connect to the same device more than once in one scanning. → solved by lock & List 2. connect to the device in one scanning and didn't get onConnectionStateChange, than I scanned again, it resulted in second connection to the same device. → solved by keeping BluetoothGatt object when I call device.connectGatt(), and call object.disconnect(), object.close() before scanning.

My test phone is 4 years old so sometimes it needs more than 20 seconds to return onConnectionStateChange....

like image 1
Ray Chung Avatar answered Oct 17 '22 15:10

Ray Chung


As previously stated, the problem is caused by calling connectGatt multiple times. Each one of those calls create a new BluetoothGatt instance and they are all kept alive, while you have only the last one. Given the fact that sometimes it is needed to call connectGatt multiple times, I just keep all the instances that it returns and call disconnect/close on all of them when I'm done. This fixed the disconnection issue instantly

private val gattInstances = LinkedList<BluetoothGatt>()


fun connect() {
    bluetoothGatt = device?.connectGatt(
        context,
        false, gattCallback, TRANSPORT_LE
    )
    bluetoothGatt?.let { gattInstances.add(it) }
}

fun finish() {
    bluetoothGatt?.close()
    while (gattInstances.isNotEmpty()) {
        gattInstances.pop().apply {
            disconnect()
            close()
        }
    }
}
like image 1
Nick Avatar answered Oct 17 '22 13:10

Nick