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);
}
};
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