It's my code to enable characteristic notification.
private void enableNotification(BluetoothGattCharacteristic characteristic) {
boolean s = bluetoothGatt.setCharacteristicNotification(characteristic, true);
Log.d(TAG, "enableNotification: setCharacteristicNotification " + s);
List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
if (null != descriptors && descriptors.size() > 0) {
for (BluetoothGattDescriptor descriptor : descriptors) {
Log.d(TAG, "enableNotification: " + descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
boolean s1 = bluetoothGatt.writeDescriptor(descriptor);
Log.d(TAG, "enableNotification: writeDescriptor " + s1);
}
} else {
Log.d(TAG, "enableNotification: descriptors is null");
}
}
The following are the logs
BluetoothGatt: setCharacteristicNotification() - uuid: 00002a4d-0000-1000-8000-00805f9b34fb enable: true
BleService: enableNotification: setCharacteristicNotification true
BleService: enableNotification: 00002902-0000-1000-8000-00805f9b34fb
BleService: enableNotification: writeDescriptor true
BluetoothGatt: onConnectionUpdated() - Device=5C:B6:CC:00:1E:23 interval=40 latency=4 timeout=600 status=0
As we can see, writeDescriptor return true, but the onDescriptorWrite() method is not trigger, and the BluetoothGatt shows the log onConnectionUpdated(). If someone could tell why my notify have no trigger. the following is my onDescriptorWrite code in BluetoothGattCallback, if the code executed, in any case there will have some logs.
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
connectCallback.readMeterId();
} else if (status == BluetoothGatt.GATT_FAILURE) {
Log.d(TAG, "onDescriptorWrite: GATT_FAILURE");
} else {
Log.d(TAG, "onDescriptorWrite: something");
}
}
my BluetoothGattCallback code as follows
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
bluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
gatt.close();
Log.d(TAG, "onConnectionStateChange: DISCONNECTED");
} else {
Log.d(TAG, "onConnectionStateChange: FAIL");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//print all the service and characteristic
for (BluetoothGattService service : bluetoothGatt.getServices()) {
Log.d(TAG, "onServicesDiscovered: service ->" + service.getUuid());
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
Log.d(TAG, "onServicesDiscovered: characteristic ->" + characteristic.getUuid());
}
}
BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(BleConstant.SERVICE_UUID.SERVICE));
characteristics = service.getCharacteristics().subList(0, 2);
// enableNotification(characteristics.get(0));
for (BluetoothGattCharacteristic characteristic : characteristics) {
Log.d(TAG, "onServicesDiscovered: Properties -> " + characteristic.getUuid() + " " + characteristic.getProperties());
enableNotification(characteristic);
}
} else {
Log.d(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.d(TAG, "onCharacteristicChanged: " + Arrays.toString(characteristic.getValue()));
Log.d(TAG, "onCharacteristicChanged: string -> " + characteristic.getStringValue(0));
String callbackDataString = characteristic.getStringValue(0);
byte[] callbackDataByte = characteristic.getValue();
// boolean checkData = CRC16Util.getInstance().verification(callbackDataString);
dosomething with the response date
if (CRC16Util.getInstance().verification(callbackDataString)) {
connectCallback.crcError();
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "onCharacteristicRead: " + Arrays.toString(characteristic.getValue()));
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "onCharacteristicWrite: " + Arrays.toString(characteristic.getValue()));
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
connectCallback.readMeterId();
} else if (status == BluetoothGatt.GATT_FAILURE) {
Log.d(TAG, "onDescriptorWrite: GATT_FAILURE");
} else {
Log.d(TAG, "onDescriptorWrite: something");
}
}
};
in this code connectCallback is a interface like this
public interface ConnectCallback {
/**
* It needs to be triggered after notify successful
*/
void readMeterId();
/**
* callback of CRC ERROR
*/
void crcError();
/**
* callback of Transmission completed
*/
void onComplete();
/**
* callback of Read MeterId Error
*/
void onReadMeterIdError();
}
I only send command to ble when I onDescriptorWrite success(notify success)
The following is my connect code
public boolean connectToDevice(final String address, ConnectCallback connectCallback) {
if (null == bluetoothAdapter || null == address) {
Log.d(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
if (null != bluetoothGatt) {
bluetoothGatt = null;
}
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.d(TAG, "Device not found. Unable to connect.");
return false;
}
Log.d(TAG, "Trying to create a new connection.");
this.connectCallback = connectCallback;
bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
return true;
}
I write all the ble code in Service and use it in an activity like this
private void bindBleService() {
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
BleService.LocalBinder binder = (BleService.LocalBinder) service;
bleService = binder.getService();
if (!bleService.init()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
boolean isConn = bleService.connectToDevice(deviceAddress, new BleService.ConnectCallback() {
#Override
public void readMeterId() {
notifySuccess = true;
runOnUiThread(() -> {
waitBleDialog.setTitle(getString(R.string.edit_read_meter_id));
waitBleDialog.show();
});
bleService.sendDataToBle(READ_METER_ID.OCP);
meterIdUsed.put(READ_METER_ID.OCP, true);
}
#Override
public void crcError() {
if (waitBleDialog.isShowing()) {
waitBleDialog.cancel();
}
runOnUiThread(() -> {
Toast.makeText(BleResultActivity.this, getString(R.string.ble_crc_error), Toast.LENGTH_SHORT).show();
finish();
});
}
#Override
public void onComplete() {
if (recordList.size() == 0) {
if (waitBleDialog.isShowing()) {
waitBleDialog.cancel();
}
runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_no_new_record), Toast.LENGTH_SHORT).show());
recordTestButton.setOnClickListener(v -> runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_no_new_record), Toast.LENGTH_SHORT).show()));
} else {
runOnUiThread(() -> {
recordTestButton.setEnabled(true);
Toast.makeText(BleResultActivity.this, getString(R.string.edit_transmit_finish), Toast.LENGTH_SHORT).show();
});
recordTestButton.setOnClickListener(recordTest);
}
}
#Override
public void onReadMeterIdError() {
boolean haveCommendNotUsed = true;
for (String command : meterIdUsed.keySet()) {
Boolean commandUsed = meterIdUsed.get(command);
if (null == commandUsed) {
commandUsed = false;
}
if (!commandUsed) {
haveCommendNotUsed = true;
bleService.sendDataToBle(command);
meterIdUsed.put(command, true);
break;
} else {
haveCommendNotUsed = false;
}
}
if (!haveCommendNotUsed) {
waitBleDialog.cancel();
runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_read_meter_id_failed), Toast.LENGTH_SHORT).show());
finish();
}
}
});
if (!isConn) {
Log.d(TAG, "onServiceConnected: false");
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
bleService = null;
}
};
final Intent intent = new Intent(this, BleService.class);
bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
}
What I know now is that after run the enableNotification() method and the writeDescriptor() return true, the onConnectionUpdated() happened and I lose my connection. The onConnectionUpdated() is hide in souce code, and I don't know why it occurs and how to deal with it.
It seems your app is not connected to your BLE device.
To know whether the connection is succesful, you need to check the given status is equal to BluetoothGatt.GATT_SUCCESS in onConnectionStateChange().
Also, check for possible GATT_CONN_TIMEOUT:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if ((newState == BluetoothProfile.STATE_CONNECTED) && (status == BluetoothGatt.GATT_SUCCESS)) {
bluetoothGatt.discoverServices();
} else if ((newState == BluetoothProfile.STATE_DISCONNECTED) && (status == BluetoothGatt.GATT_SUCCESS)) {
gatt.close();
Log.d(TAG, "onConnectionStateChange: DISCONNECTED");
} else if (status == GATT_CONN_TIMEOUT) {
Log.e(TAG, "GATT_CONN_TIMEOUT !");
} else {
Log.e(TAG, "onConnectionStateChange: FAIL");
}
}
Related
I am trying to get data from a glucose meter and I am not able to find good resources regarding the implementation on internet. Here is what I have been able to implement till now:
I am scanning the devices using BluetoothAdapter.LeScanCallback Interface:
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if ((device.getName() != null) && !bleDevices.contains(device)) {
bleDevices.add(device);
}
}
After getting the devices I am connecting to device using:
device.connectGatt(MainActivity.this, true, bleGattCallBack);
In BluetoothGattCallback class I am able to get the status connected in:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
connectionState = STATE_CONNECTED;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
connectionState = STATE_DISCONNECTED;
gatt.close();
}
}
After that onServicesDiscovered gets called
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
String serviceUUID = gattService.getUuid().toString();
if (serviceUUID.equals("00001808-0000-1000-8000-00805f9b34fb")) {
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
if (characteristic.getUuid().equals(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charGM =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charGM, true);
glucoseCharacteristic = characteristic;
BluetoothGattDescriptor descGM = charGM.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descGM.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descGM);
} else if (characteristic.getUuid().equals(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charRACP =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charRACP, true);
BluetoothGattDescriptor descRACP = charRACP.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descRACP.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descRACP);
}
}
}
} else {
}
}
After this onDescriptorWrite gets called:
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
BluetoothGattCharacteristic writeRACPchar =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
byte[] data = new byte[2];
data[0] = 0x01; // Report Stored records
data[1] = 0x01; // All records
writeRACPchar.setValue(data);
gatt.writeCharacteristic(writeRACPchar);
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
} else {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
}
and then onCharacteristicWrite
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.d(TAG, "onCharacteristicWrite: " + status + "\n" + characteristic.getUuid() + "\n" + stringBuilder.toString() + "\n" + characteristic.getValue().length);
}
}
Now, how do I proceed further? I know that I will get the data in onCharacteristicRead but that is never called.
android 10 for BLE Bluetooth connection is not connected , i will set all permission also but i get connection status 133 issues ,how to solve this issues ,here i declare the scanning and callback code ,please check and give your idea
but below android 10 version is working fine,only issues on android 10 device ,give an idea to solve the issues
private void scanLeDevice(final boolean enable) {
if (scanner == null) {
scanner = btAdapter.getBluetoothLeScanner();
}
if (scanCallback == null) setScanCallback(null);
scanner.startScan(createScanFilters(),createScanSettings(),scanCallback);
isScanning = true;
}
ScanCallback scanCallback = new ScanCallback() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onScanResult(int callbackType, #NonNull ScanResult scanResult) {
if (connectedDevices.containsKey(scanResult.getDevice().getAddress())) {
return;
}
if (connectingDevices.contains(scanResult.getDevice().getAddress())) {
// If we're already connected, forget it
//Timber.d("Denied connection. Already connecting to " + scanResult.getDevice().getAddress());
return;
}
if (connectionGovernor != null && !connectionGovernor.shouldConnectToAddress(scanResult.getDevice().getAddress())) {
// If the BLEConnectionGovernor says we should not bother connecting to this peer, don't
return;
}
final BluetoothDevice device = btAdapter.getRemoteDevice(scanResult.getDevice().getAddress());
if (device == null) {
Log.e(TAG, "Device not found. Unable to connect.");
}
connectingDevices.add(scanResult.getDevice().getAddress());
// connectToDevice(device);
Timber.d("Initiating connection to " + scanResult.getDevice().getAddress());
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE );
}
#Override
public void onScanFailed(int i) {
Timber.e("Scan failed with code " + i);
}
};
#NonNull
BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(#NonNull BluetoothGatt gatt, int status, int newState) {
synchronized (connectedDevices) {
// It appears that certain events (like disconnection) won't have a GATT_SUCCESS status
// even when they proceed as expected, at least with the Motorola bluetooth stack
if (status != BluetoothGatt.GATT_SUCCESS)
Timber.w("onConnectionStateChange with newState %d and non-success status %s", newState, gatt.getDevice().getAddress());
Set<BluetoothGattCharacteristic> characteristicSet;
switch (newState) {
case BluetoothProfile.STATE_DISCONNECTING:
Timber.d("Disconnecting from " + gatt.getDevice().getAddress());
characteristicSet = discoveredCharacteristics.get(gatt.getDevice().getAddress());
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
Timber.d("Attempting to unsubscribe on disconneting");
setIndictaionSubscription(gatt, characteristic, false);
}
}
discoveredCharacteristics.remove(gatt.getDevice().getAddress());
break;
case BluetoothProfile.STATE_DISCONNECTED:
Timber.d("Disconnected from " + gatt.getDevice().getAddress());
connectedDevices.remove(gatt.getDevice().getAddress());
connectingDevices.remove(gatt.getDevice().getAddress());
if (transportCallback != null)
transportCallback.identifierUpdated(BLETransportCallback.DeviceType.CENTRAL,
gatt.getDevice().getAddress(),
Transport.ConnectionStatus.DISCONNECTED,
null);
characteristicSet = discoveredCharacteristics.get(gatt.getDevice().getAddress());
if (characteristicSet != null) { // Have we handled unsubscription on DISCONNECTING?
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
Timber.d("Attempting to unsubscribe before disconnet");
setIndictaionSubscription(gatt, characteristic, false);
}
}
} else
if ( status != BluetoothGatt.GATT_SUCCESS ) {
if ( status == 133) {
refreshDeviceCache(gatt);
}
}
gatt.close(); discoveredCharacteristics.remove(gatt.getDevice().getAddress());
break;
case BluetoothProfile.STATE_CONNECTED:
boolean mtuSuccess = gatt.requestMtu(BLETransport.DEFAULT_MTU_BYTES);
Timber.d("Connected to %s. Requested MTU success %b", gatt.getDevice().getAddress(),
mtuSuccess);
break;
}
super.onConnectionStateChange(gatt, status, newState);
}
}
#Override
public void onMtuChanged(#NonNull BluetoothGatt gatt, int mtu, int status) {
Timber.d("Got MTU (%d bytes) for device %s. Was changed successfully: %b",
mtu,
gatt.getDevice().getAddress(),
status == BluetoothGatt.GATT_SUCCESS);
mtus.put(gatt.getDevice().getAddress(), mtu);
// TODO: Can we craft characteristics and avoid discovery step?
boolean discovering = gatt.discoverServices();
Timber.d("Discovering services : " + discovering);
}
#Override
public void onServicesDiscovered(#NonNull BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS)
Timber.d("Discovered services");
else
Timber.d("Discovered services appears unsuccessful with code " + status);
// TODO: Keep this here to examine characteristics
// eventually we should get rid of the discoverServices step
boolean foundService = false;
try {
List<BluetoothGattService> serviceList = gatt.getServices();
for (BluetoothGattService service : serviceList) {
if (service.getUuid().equals(serviceUUID)) {
Timber.d("Discovered Service");
foundService = true;
HashSet<BluetoothGattCharacteristic> characteristicSet = new HashSet<>();
characteristicSet.addAll(service.getCharacteristics());
discoveredCharacteristics.put(gatt.getDevice().getAddress(), characteristicSet);
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
setIndictaionSubscription(gatt, characteristic, true);
}
}
}
}
if (foundService) {
synchronized (connectedDevices) {
connectedDevices.put(gatt.getDevice().getAddress(), gatt);
}
connectingDevices.remove(gatt.getDevice().getAddress());
}
} catch (Exception e) {
Timber.d("Exception analyzing discovered services " + e.getLocalizedMessage());
e.printStackTrace();
}
if (!foundService)
Timber.d("Could not discover chat service!");
super.onServicesDiscovered(gatt, status);
}
/**
* Subscribe or Unsubscribe to/from indication of a peripheral's characteristic.
*
* After calling this method you must await the result via
* {#link #onDescriptorWrite(BluetoothGatt, BluetoothGattDescriptor, int)}
* before performing any other peripheral actions.
*/
private void setIndictaionSubscription(#NonNull BluetoothGatt peripheral,
#NonNull BluetoothGattCharacteristic characteristic,
boolean enable) {
boolean success = peripheral.setCharacteristicNotification(characteristic, enable);
Timber.d("Request notification %s %s with sucess %b", enable ? "set" : "unset", characteristic.getUuid().toString(), success);
BluetoothGattDescriptor desc = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
desc.setValue(enable ? BluetoothGattDescriptor.ENABLE_INDICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
boolean desSuccess = peripheral.writeDescriptor(desc);
Timber.d("Wrote descriptor with success %b", desSuccess);
}
#Override
public void onDescriptorWrite(#NonNull BluetoothGatt gatt, #NonNull BluetoothGattDescriptor descriptor,
int status) {
Timber.d("onDescriptorWrite");
if (status == BluetoothGatt.GATT_SUCCESS && transportCallback != null) {
if (Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
transportCallback.identifierUpdated(BLETransportCallback.DeviceType.CENTRAL,
gatt.getDevice().getAddress(),
Transport.ConnectionStatus.CONNECTED,
null);
} else if (Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
Timber.d("disabled indications successfully. Closing gatt");
gatt.close();
}
}
}
#Override
public void onCharacteristicChanged(#NonNull BluetoothGatt gatt, #NonNull BluetoothGattCharacteristic characteristic) {
Timber.d("onCharacteristicChanged %s with %d bytes", characteristic.getUuid().toString().substring(0,5),
characteristic.getValue().length);
if (transportCallback != null)
transportCallback.dataReceivedFromIdentifier(BLETransportCallback.DeviceType.CENTRAL,
characteristic.getValue(),
gatt.getDevice().getAddress());
super.onCharacteristicChanged(gatt, characteristic);
}
#Override
public void onCharacteristicWrite(#NonNull BluetoothGatt gatt,
#NonNull BluetoothGattCharacteristic characteristic, int status) {
Timber.d("onCharacteristicWrite with %d bytes", characteristic.getValue().length);
Exception exception = null;
if (status != BluetoothGatt.GATT_SUCCESS) {
String msg = "Write was not successful with code " + status;
Timber.w(msg);
exception = new UnknownServiceException(msg);
}
if (transportCallback != null)
transportCallback.dataSentToIdentifier(BLETransportCallback.DeviceType.CENTRAL,
characteristic.getValue(),
gatt.getDevice().getAddress(),
exception);
}
#Override
public void onReadRemoteRssi(#NonNull BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
};
now the app is working for change the bluetooth device support type
device.connectGatt(context, false, mGattCallback, BluetoothDevice.DEVICE_TYPE_LE);
but now the app is not working on huawei device , if any have idea for the device huawei for this issue
I pair with my device, I connect to it, using this code
//this will try to connect to our bluetooth device
public void connectGatt(Context context, BluetoothDevice btDevice) {
this.btDevice = btDevice;
mBluetoothGatt = btDevice.connectGatt(context, false, mGattCallback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothGatt != null) {
mBluetoothGatt.requestMtu(512);
}
}
This is my GATT Callback:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
tryToConnect = false;
Log.i("BluetoothService", "BluetoothService onConnectionStateChange CONNECTED");
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
Log.i("", "Connected to GATT server.");
boolean discover = mBluetoothGatt.discoverServices();
Log.i("", "Attempting to start service discovery:" + discover);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange STATE_DISCONNECTED");
if (tryToConnect) {
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
stopMonitoringBeacons();
stopListeningForBeacons();
mBluetoothAdapter.disable();
setSleep(1500);
mBluetoothAdapter.enable();
setSleep(1500);
Log.i("BluetoothService", "BluetoothService onConnectionStateChange WILL TRY CONNECT");
if (back != null)
back.onResponse(CONNECT);
tryToConnect = false;
}
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
tryToConnect = false;
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS" + status);
Log.w("", "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("", "list size: " + listBGS.size());
if (listBGS.size() > 0) {
if (back != null)
back.onResponse(CONFIGURE);
String character = "FF05";
if (justName)
character = "FF01";
setCharacteristic(gatt, character);
} else {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS but ZERO SERVICES: " + btDevice.getBondState());
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
setSleep(500);
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED)
mBluetoothGatt.discoverServices();
} else if (btDevice.getBondState() == BluetoothDevice.BOND_NONE) {
askPairDevice();
}
}
} else {
askPairDevice();
Log.w("BluetoothService", "BluetoothService onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
int status) {
handler.removeCallbacksAndMessages(null);
Log.i("BluetoothService", "BluetoothService onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onCharacteristicRead GATT_SUCCESS");
Log.w("", "BGC onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
if (characteristic.getUuid().toString().toUpperCase().contains("FF05")) {
final String value = toHexadecimal(characteristic.getValue());
if (newBeacon == null || newBeacon.getName() == null) {
checkIfNeedsToChangeUUID(gatt, value);
} else if (newBeacon != null && (newBeacon.getUuid() != null || justName)) {
Log.i("BluetoothService", "BluetoothService new Beacon UUID is: " + value);
newBeacon.setUuid(Identifier.parse(value).toString());
if (back != null)
back.onResponse(CHANGED);
} else {
changeUUID(gatt, characteristic, value);
}
} else if (characteristic.getUuid().toString().toUpperCase().contains("FF01")) {
changeName(gatt, characteristic);
}
} else {
Log.i("", "");
}
}
};
The part that I am interested in is here:
public void changeUUID(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, String value) {
int size = value.length();
RandomString gen = new RandomString(size, new SecureRandom());
String uuid = gen.nextString();
Log.i("", "BluetoothService BGC value NEW UUID: " + uuid);
boolean change = characteristic.setValue(hexStringToByteArray(uuid));
Log.i("", "BluetoothService BGC value after: " + toHexadecimal(characteristic.getValue()) + " / has changed: " + change);
boolean statusWrite = gatt.writeCharacteristic(characteristic);
Log.i("", "BluetoothService BGC value after statusWRITE: " + statusWrite);
if (statusWrite) {
newBeacon.setUuid(Identifier.parse(toHexadecimal(characteristic.getValue())).toString());
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
setCharacteristic(gatt, "FF05");
}
});
} else {
if (back != null)
back.onResponse(ERROR);
}
}
Which will call this:
try {
Log.i("BluetoothService", "BluetoothService set characteristic: " + characteristic);
BluetoothGattCharacteristic btChar = null;
for (BluetoothGattService bgs : gatt.getServices()) {
for (final BluetoothGattCharacteristic bgc : bgs.getCharacteristics()) {
if (bgc.getUuid().toString().toUpperCase().contains(characteristic)) {
btChar = bgc;
gatt.readCharacteristic(bgc);
break;
}
}
}
final BluetoothGattCharacteristic btF = btChar;
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (btF != null)
gatt.readCharacteristic(btF);
}
}, 1000);
} catch (Exception e) {
Log.i("BluetoothService", "BluetoothService set characteristic ERROR: " + e.getMessage());
setCharacteristic(gatt, characteristic);
}
}
This works, but not 100%, I could say that it works on less than 50% of the cases. and I don't understand why. Can someone help?
I mean boolean statusWrite = gatt.writeCharacteristic(characteristic); Always returns to me "TRUE" so then if in the "changeUUID function I make after that another call, to try to log it, why is it NOT changed?
Also with other apps, if I check, my UUID is not changed, which is really weird. Why get the TRUE for the write, if value is the same?
If you look at the documentation for writeCharacteristic, you'll see this:
Returns boolean true, if the write operation was initiated successfully
The emphasis above is mine. Just because you successfully initiated the write doesn't mean it compleleted successfully, and indeed, in my apps I often see that it does not.
What you need to do is implement the callback public void onCharacteristicWrite (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status), then check the status to see if it is BluetoothGatt.GATT_SUCCESS. If not, you will need to retry the write. I usually make code that retries up to 10 times, then gives up after that, triggering code that presents an error to the user.
Most other Android Bluetooth APIs work this way -- discovering services, discovering characteristics, etc. Each one of these async operations can fail, and you have to implement the callbacks to find out if they actually succeeded or not, and add a retry strategy.
I'm building an app that should to connect with a BLE device.
This device, storage the information that retreive from its sensors in a queque.
It is possibile that at the time X, the queque of this device have 100 items value.
Now my Android application must to connect of it, and download the data of the characteristic untile the queque of devis is empty.
This is the code that I use to read one value at time. How can I change it to get all data ?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ble);
mHandler = new Handler();
//mSensors = db.getAllSensorTypes();
//BLUETOOTH LOW ENERGY NON SUPPORTATO
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//VERIFICO SE IL BLUETOOTH DEL DISPOSITIVO E' ABILITATO
//OPPURE NO. SE NON è ABILITATO DEVO CHIEDERE ALL'UTENTE DI ATTIVARLO
// Ensures Bluetooth is available on the device and it is enabled. If not,
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
tvBLE = (TextView) findViewById(R.id.tvBLE);
ibDownload = (ImageButton) findViewById(R.id.ibDownload);
//ibDownload.setEnabled(false);
ibDownload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(currDevice!=null){
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}
refreshListView();
}
});
// Bluetooth is supported?
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth non supportato", Toast.LENGTH_SHORT).show();
finish();
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
String nomeDispositivo = device.getName();
if (mGatt == null && device.getName()!= null && device.getName().equals("Diabesity care")) {
currDevice = device;
ibDownload.setEnabled(true);
ibDownload.setImageResource(R.drawable.download_ok);
//mGatt = device.connectGatt(this, false, gattCallback);
//scanLeDevice(false);// will stop after first device detection
}
}
private class GattClientCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.i("tag","onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
logError("Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
logError("Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("INFO","Connected to device " + gatt.getDevice().getAddress());
setConnected(true);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("INFO","Disconnected from device");
disconnectGattServer();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.i("INFO","Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics = BluetoothUtils.findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
logError("Unable to find characteristics.");
return;
}
ReadQueue = new ArrayList<>();
for (BluetoothGattCharacteristic characterist: matchingCharacteristics) {
ReadQueue.add(characterist);
}
ReadQueueIndex = 1;
ReadCharacteristics(ReadQueueIndex);
}
private void ReadCharacteristics(int index){
mGatt.readCharacteristic(ReadQueue.get(index));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("INFO","Characteristic read successfully");
//readCharacteristic(characteristic);
SensorData mSenData = new SensorData();
mSenData.setValue(characteristic.getStringValue(0));
//TO-DO HO COMMENTATO QUESTA RIGA DI CODICE
// mSenData.setIdType(st.getId());
mSenData.setIdType(++id);
mSenData.setCharacteristic(characteristic.getUuid().toString());
mSenData.setValueTimestamp(db.getDateTime());
//inserisco i dati nel db
db.insertSensorData(mSenData);
ReadQueue.remove(ReadQueue.get(ReadQueueIndex));
if (ReadQueue.size() >= 0) {
ReadQueueIndex--;
if (ReadQueueIndex == -1) {
Log.i("Read Queue: ", "Complete");
}
else {
ReadCharacteristics(ReadQueueIndex);
}
}
//refreshListView();
} else {
logError("Characteristic read unsuccessful, status: " + status);
// Trying to read from the Time Characteristic? It doesnt have the property or permissions
// set to allow this. Normally this would be an error and you would want to:
// disconnectGattServer();
}
}
}
}
i have two problem.I want connect my ble service .I can connect but i cant disconnect serive when i use mService.disconnect(); my app will crash.and other problem is i cant send value to RXchar......
All problem are dispaly on a null object reference
this is disconnect error
RxChar error
my code _ble_fragment
switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
try {
//send data to service
if (isChecked) {
message = "1";
} else {
message = "0";
}
value = message.getBytes("UTF-8");
sendText.setText(message);
mService.writeRXCharacteristic(value);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("click", "按下去了");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (scanButton.getText().equals("Connect")) {
Log.i("scan", "open device");
switch1.setEnabled(true);
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Intent newIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivity(newIntent);
} else {
//Disconnect button pressed
mService.disconnect();
Log.i("Diconnect", "Disconnect Ble");
// mHandler.removeCallbacks(runnable);
}
}
}
});
DeviceList & UartService code:
public void writeGatt(BluetoothDevice dev){
byte[] msgBuffer; //bluetooth send alway byte
String message = "1"; //ON
msgBuffer = message.getBytes();
mBtGatt = dev.connectGatt(this,false,GattCallback);//call Gattcallback
}
private final BluetoothGattCallback GattCallback = new BluetoothGattCallback() { //
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBtGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
};
public void disconnect() { //deisconnect
if (mBtGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBtGatt.close();
mBtGatt = null;
// mBluetoothGatt.close();
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.i("broadcastUpdate", "run broadcastUpdate send " + intent);
}
public void close() {
if (mBtGatt == null) {
return;
}
Log.w(TAG, "mBluetoothGatt closed");
;
mBtGatt.close();
mBtGatt = null;
}
public void writeRXCharacteristic(byte[] value)
{
/* BluetoothGattService RxService = mBtGatt.getService(RX_SERVICE_UUID);
//showMessage("mBluetoothGatt null"+ mBluetoothGatt);
if (RxService == null) {
//showMessage("Rx service not found!");
// broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
Log.i("RxService is null!!","RxService is null!!");
return;
}
BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RX_CHAR_UUID);
if (RxChar == null) {
// showMessage("Rx charateristic not found!");
//broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
Log.i("RxCHAR is null!!","RxCHAR is null!!");
return;
}
RxChar.setValue(value);
boolean status = mBtGatt.writeCharacteristic(RxChar);
Log.d(TAG, "write TXchar - status=" + status);*/
BluetoothGattService RxService=null;
while( RxService==null) {
try{
RxService = mBtGatt.getService(RX_SERVICE_UUID);}
catch(Exception e){
Log.d(TAG, e.toString());}
}
if (RxService == null) {
Log.d(TAG, "1");
return;
}BluetoothGattCharacteristic RxChar=null;
while( RxChar ==null){
try{
RxChar = RxService.getCharacteristic(RX_CHAR_UUID);}
catch(Exception e)
{Log.d(TAG, e.toString());}
}
if (RxChar == null) {
Log.d(TAG, "2");
return;
}
RxChar.setValue(value);
mBtGatt.writeCharacteristic(RxChar);
}
what can i do?
you can try this:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter.isEnabled()){
bluetoothAdapter.disable();
}
you need add two permission bellow:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>