Catching DeadObjectException raised while calling BluetoothGatt.connect() after reseting Bluetooth chip on Android 4.3 Bluetooth BLE

StackOverflow https://stackoverflow.com/questions/21850172

Question

I'm developing an app that takes advantage of the new Bluetooth BLE API from Android 4.3.

I used the Samsung BLE Stack for Android 4.2 and it's working ok, even if the stability could be better.

Now with 4.3, for each client connection, we have an instance of the BluetoothGatt class.

That is, I connect to a BLE device by calling

BluetoothGatt gatt = device.connectGatt(this, true, callbacks);

These BluetoothGatt objects are the ones to use to actually interact with a device.

Since I want to connect to multiple devices and interact with those, I'm caching the BluetoothGatt instances in a HashMap defined as my service's private property :

private HashMap<String, BluetoothGatt> devicesGatts 
    = new HashMap<String, BluetoothGatt>();

The keys are device addresses.

Then whenever I want to connect to a device, I pull the BluetoothGatt instance out of this HashMap :

public BluetoothGatt connectGatt(final BluetoothDevice device){
    if(device == null){
        return null;
    }
    String adr = device.getAddress();
    BluetoothGatt gatt = devicesGatts.get(adr);
    if(gatt == null){
        gatt = device.connectGatt(this, true, mGattCallbacks);
    } else {
        BluetoothDevice gattDevice = gatt.getDevice();
        if(gattDevice != null && adr.equals(gattDevice.getAddress())){
                gatt.connect(); // PROBLEM APPEARS HERE
        } else {
            gatt = device.connectGatt(this, true, mGattCallbacks);
        }
    }
    devicesGatts.put(adr, gatt);
    return gatt;
}

The problem is that sometimes, if a device is tried reconnecting via its cached BluetoothGatt instance by calling gatt.connect(), I get an error (not Fatal) called DeadObjectException.

It happens when I pause the application and restart the Bluetooth chip, then resuming the application.

I'm not surprised that I can't use the cached instance after that happened, but I'd like to know how I could either catch that exception or detect it prior to it happening.

Here is the stack trace :

02-18 10:43:51.884: E/BluetoothGatt(23312): android.os.DeadObjectException
02-18 10:43:51.884: E/BluetoothGatt(23312):     at android.os.BinderProxy.transact(Native Method)
02-18 10:43:51.884: E/BluetoothGatt(23312):     at android.bluetooth.IBluetoothGatt$Stub$Proxy.clientConnect(IBluetoothGatt.java:841)
02-18 10:43:51.884: E/BluetoothGatt(23312):     at android.bluetooth.BluetoothGatt.connect(BluetoothGatt.java:759)
02-18 10:43:51.884: E/BluetoothGatt(23312):     at MYSERVICE.connectGatt(...)

The exception is raised by a native method but is not thrown by the Bluetooth stack classes.

How could I catch it?

Was it helpful?

Solution

I found a workaround.

I just reset the HashMap when the Bluetooth chip gets turned off.

IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
this.registerReceiver(bluetoothStatusChangeReceiver, filter);

private final BroadcastReceiver bluetoothStatusChangeReceiver
= new BroadcastReceiver() {

    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)){
            if(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) 
                    == BluetoothAdapter.STATE_OFF){
                devicesGatts.clear();
                resetBluetooth();
            } else if(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) 
                    == BluetoothAdapter.STATE_ON){
                initBluetooth();
            }
        }
    }
}

The functions initBluetooth and resetBluetooth allow me to reset the BluetoothGattServer and BluetoothManager instances.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top