androidbluetoothpairingdisconnectionbluetooth-peripheral

Android Bluetooth Peripheral: Connection terminated by peer (Status 19)


Developed an application which acts as peripheral and connects with other device (central only).

It's working fine in devices having OS version 6.0, but getting some issues in Nougat 7.0.

I've collected some logs, enabling "Bluetooth HCI snoop log" in developer option.

Collected Logs:

W/bt_btm: btm_sec_disconnect : reason=19
W/bt_btif: btif_dm_generic_evt: event=33035
W/bt_btif: btif_dm_generic_evt: event=33035
W/bt_btm: btm_sec_send_hci_disconnect:  handle:0x41, reason=0x13
W/bt_btif: btif_dm_generic_evt: event=33035
W/bt_btif: bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0016
W/bt_btif: bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0016
W/bt_btif: bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x0016
W/bt_btif: bta_gattc_conn_cback() - cif=7 connected=0 conn_id=7 reason=0x0016
W/bt_btif: bta_dm_bl_change_cback : reason=22
W/bt_btif: bta_dm_bl_change_cback : reason=22
W/bt_btm: btm_sec_disconnected
W/bt_btif: conn.link_down.is_removed : 0
D/BtGatt.GattService: onClientConnected() serverIf: 6, connId=6, address=00:16:A4:13:1E:48, connected=false
W/bt_btif: btif_dm_upstreams_cback  ev: BTA_DM_LINK_DOWN_EVT
W/bt_btif: BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED


Peripheral Service (Code):

    private boolean addService() {
        if (null == mGattServer) {
            Logger.printLog(TAG, "mGattServer is null");
            return false;
        }

        BluetoothGattService service = new BluetoothGattService(UUID_pService,
                BluetoothGattService.SERVICE_TYPE_PRIMARY);

        //Defined descriptor for CCC and CEP
        final BluetoothGattDescriptor cccDescriptor = new BluetoothGattDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"), BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
        cccDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        final BluetoothGattDescriptor cepDescriptor = new BluetoothGattDescriptor(UUID.fromString("00002900-0000-1000-8000-00805f9b34fb"), BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED);
        cepDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);


        pairingCharacteristic = new BluetoothGattCharacteristic(UUID_pCharac,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS,
                BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED | BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED);
        pairingCharacteristic.addDescriptor(cccDescriptor);
        pairingCharacteristic.addDescriptor(cepDescriptor);
//        pairingCharacteristic.setValue(new String("0.0.0").getBytes());
        service.addCharacteristic(pairingCharacteristic);


        heartbeatCharacteristic = new BluetoothGattCharacteristic(UUID_hCharac,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS,
                BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED | BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED);
        heartbeatCharacteristic.addDescriptor(cccDescriptor);
        heartbeatCharacteristic.addDescriptor(cepDescriptor);
//        heartbeatCharacteristic.setValue(new String("0.0.0").getBytes());
        service.addCharacteristic(heartbeatCharacteristic);


        deviceInfoCharacteristic = new BluetoothGattCharacteristic(UUID_dCharac,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS,
                BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED | BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED);
        deviceInfoCharacteristic.addDescriptor(cccDescriptor);
        deviceInfoCharacteristic.addDescriptor(cepDescriptor);
//        deviceInfoCharacteristic.setValue(new String("0.0.0").getBytes());
        service.addCharacteristic(deviceInfoCharacteristic);


        readCharacteristic = new BluetoothGattCharacteristic(UUID_rCharac,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS,
                BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED | BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED);
        readCharacteristic.addDescriptor(cccDescriptor);
        readCharacteristic.addDescriptor(cepDescriptor);
//        readCharacteristic.setValue(new String("0.0.0").getBytes());
        service.addCharacteristic(readCharacteristic);
        Logger.printLog(TAG, "Add service to gatt server");

        writeCharacteristic = new BluetoothGattCharacteristic(UUID_wCharac,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS,
                BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED | BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED);
        writeCharacteristic.addDescriptor(cccDescriptor);
        writeCharacteristic.addDescriptor(cepDescriptor);
//        writeCharacteristic.setValue(new String("0.0.0").getBytes());
        service.addCharacteristic(writeCharacteristic);

        Logger.printLog(TAG, "Add write char to gatt server");
        return true == mGattServer.addService(service);


    }


private final BluetoothGattServerCallback mGattServerCallback
        = new BluetoothGattServerCallback() {

    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        Logger.printLog(TAG, "Our gatt server connection state changed, new state :" + Integer.toString(newState));
        String intentAction;
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Logger.printLog(TAG, "Connected to GATT server.");
                if (device != null) {
                    int type = device.getType();

                    mDevice = device;
                    Logger.printLog(TAG, "Data available to read, sending notification");
                }
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Logger.printLog(TAG, "Disconnected from GATT server.");

                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                broadcastUpdate(intentAction);
            }
        } else {
            Logger.printLog(TAG, "FAILURE STATUS: " + status);
        }
        if (null != mConnectionCallback && BluetoothGatt.GATT_SUCCESS == status) {
            mConnectionCallback.onConnectionStateChange(device, newState);
        }

    }

    @Override
    public void onServiceAdded(int status, BluetoothGattService service) {
        Logger.printLog(TAG, "Our gatt server service was added.");
        super.onServiceAdded(status, service);
    }

    @Override
    public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
       /* mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
                characteristic.getValue());*/
        Logger.printLog(TAG, "Data read value:" + characteristic.getValue());
        Logger.printLog(TAG, "Data read uuid:" + characteristic.getUuid());

        if (offset != 0) {
            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_INVALID_OFFSET, offset,null);
            return;
        }
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());

    }

    @Override
    public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);

        final String intentAction = ACTION_DATA_AVAILABLE;
        broadcastUpdate(intentAction, value);
        if (responseNeeded) {
            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0,null);
        }

        Logger.printLog(TAG, "We have received a write request for one of our hosted characteristics");


    }

    @Override
    public void onNotificationSent(BluetoothDevice device, int status) {
        Logger.printLog(TAG, "onNotificationSent");
        super.onNotificationSent(device, status);
    }

    @Override
    public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
        Logger.printLog(TAG, "Our gatt server descriptor was read.");
        super.onDescriptorReadRequest(device, requestId, offset, descriptor);

        if (offset != 0) {
            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_INVALID_OFFSET, offset,null);
            return;
        }
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
                descriptor.getValue());

    }

    @Override
    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        Logger.printLog(TAG, "Our gatt server descriptor was written.");
        super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);

        if (responseNeeded) {
            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,0,null);
        }
    }

    @Override
    public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
        Logger.printLog(TAG, "Our gatt server on execute write.");
        super.onExecuteWrite(device, requestId, execute);
    }
};

Solution

  • If you want to support Android version above 6.0 (Marshmallow), just need to connect same device again in onConnectionStateChange method.

     if(newState == BluetoothProfile.STATE_CONNECTED) {
    
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                BluetoothDevice mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress());
                boolean conn = bleServer.connect(mDevice, false);
                Log.i(TAG, "Connection State ---> Connected, Gatt connected result = "+conn);
            }else{
                Log.i(TAG, "Connection State ---> Connected");
            }
        }
    

    For more information, follow reference provided on GitHub