Not disconnecting from BLE device - android

I am using Android 4.4.2 on Moto X. I have a custom bluetooth low energy board, which has a red LED turned on when no devices connected to it. It supports just one connected device at a time. I am building an Android application that tries to connect to this BLE device and writes to its characteristic and then disconnects from it. I am having two problems: after writing a value to characteristic, I am doing:
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
mBluetoothAdapter.cancelDiscovery();
broadcastUpdate(ACTION_GATT_DISCONNECTED);
but that doesn't actually disconnect my smartphone (the LED on BLE device remains turned off, meaning that some device is still connected to it). However, when I turn off the bluetooth adapter on my smartphone, the LED immediately turns on.
The second problem is that I can't write to my characteristic from the first attempt, I have to call the same sequence for the second time.
Here's the procedure that is called to write my characterictic:
public void trytounlock() {
Context context = getApplicationContext();
if (connect("E2:0C:B9:4D:B9:56"))
{
Log.w(TAG, "connect returned true!");
}
else {
Log.w(TAG, "connect returned false - warum?");
};
if (mBluetoothAdapter == null ) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
else
{
Log.w(TAG, "BluetoothAdapter initialized successfully!");
}
if ( mBluetoothGatt == null) {
Log.w(TAG, "GATT not initialized");
return;
}
else
{
Log.w(TAG, "GATT initialized succesfully!");
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000f00d-1212-efde-1523-785fef13d123"));
while (!mBluetoothGatt.discoverServices())
{
Log.w(TAG, "Waiting for service discovery");
}
int duration = Toast.LENGTH_SHORT;
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found here. ");
return;
}
else
{
Log.w(TAG, "Custom BLE Service found successfully!");
}
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("0000beef-1212-efde-1523-785fef13d123"));
byte[] raw={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
mWriteCharacteristic.setValue(raw);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
Toast.makeText(context, "Failed to write characteristic - ошибочка!!", duration).show();
}
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized, while trying to disconnect - weird!!!");
}
else {
mBluetoothGatt.disconnect();
}
mWriteCharacteristic = null;
mCustomService = null;
if (mBluetoothGatt == null) {
}
else {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
mBluetoothAdapter.cancelDiscovery();
}
broadcastUpdate(ACTION_GATT_DISCONNECTED);
}
Here's my connect procedure:
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
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
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
So, the questions are:
How to release my board properly, so that is sees no other devices connected to it?
What is the reason it only write my characteristic, when I call it for the second time after I initially turn on the bluetooth adapter?

Related

Trying to connect to iOS via BLE + BT through Android device

I am trying to connect to the i-phone via Android Bluetooth + BLE.
My goal is to read iOS notifications via Android Bluetooth + BLE.
I am able to show the i-phone Bluetooth in the android app and was able to connect to the i-phone but I am unable to found the Notification characteristic.
I got notification characteristic UUID from this link I am using Notification Source: UUID
Here is my BluetoothGattCallback:
public BluetoothGattCallback mCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
final BluetoothGatt mGatt = gatt;
Handler handler;
handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
mGatt.discoverServices();
}
});
//gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
try
{
Log.i("no_conn", "Connection unsuccessful with status"+status);
//mGatt.disconnect();
mGatt.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.i("Not success", "Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattService> matchingServices = gatt.getServices();
gatt.getService(UUID.fromString(SERVICE_STRING));
List<BluetoothGattCharacteristic> matchingCharacteristics = BluetoothUtils.findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
Log.i("No characteristics", "Unable to find characteristics.");
showToast("No characteristic found");
return;
}else {
showToast("characteristic found");
}
}
};
Here is my findCharacteristics function:
public static List<BluetoothGattCharacteristic> findCharacteristics1(BluetoothGatt bluetoothGatt) {
List<BluetoothGattCharacteristic> matchingCharacteristics = new ArrayList<>();
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = null;
for (BluetoothGattService bgservice : serviceList) {
String serviceIdString = bgservice.getUuid()
.toString();
if (matchesServiceUuidString(serviceIdString)) {
service = bgservice;
}
}
if (service == null) {
Log.i("Null service", "Null service.");
return matchingCharacteristics;
}
return matchingCharacteristics;
}
Here I am matching with serviceIdString with the Notification Source: UUID.
Am I missing anything?

BLE GATT onCharacteristicChanged not called after subscribe to notification

After subscribe notification immediate write command doesn't work. I have to restart server device and auto connect to existing ble instance to get result.
Notification enable code:
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return false;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
System.out.println("descriptor length----" + characteristic.getDescriptors().size());
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
System.out.println("descriptor--" + Arrays.toString(descriptor.getValue()));
System.out.println("characteristic value--" + Arrays.toString(descriptor.getCharacteristic().getValue()));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
return mBluetoothGatt.writeDescriptor(descriptor);
}
return false;
}
and here is my write command code:
public void writeCustomCharacteristic(String value) {
this.value = "";
this.command = value;
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("65333333-a115-11e2-9e9a-0800200ca100"));
if (mCustomService == null) {
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("65333333-a115-11e2-9e9a-0800200ca101"));
mWriteCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
mWriteCharacteristic.setValue(value.getBytes());
if (!mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)) {
Log.w(TAG, "Failed to write characteristic");
}
System.out.println("BluetoothLeService.writeCustomCharacteristic------->" + value);
}
Before write any characteristic , delay for few sec . Bcz it takes time to execute.
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
mBluetoothGatt.writeDescriptor(RTS_CCCD); //for descriptor
// or
mBluetoothGatt.readCharacteristic(brspInfo); //for read
//or
mBluetoothGatt.writeCharacteristic(brspInfo); //for write
}
}, 500);
Here you get more explaination

BluetoothGattCallback returns 129 -> GATT_INTERNAL_ERROR for a Beacon, but returns 0 for phones

I call on my bluetooth adapter mBluetoothAdapter.startDiscovery(); which then returns me a list of BluetoothDevices. When I press on 1 of those devices, I do this:
mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, mGattCallback);
Where my callback is:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} 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) {
Log.w(TAG, "onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
}
}
};
Now, when I try it on phones, I get STATE_CONNECTED on onConnectionStateChange , and I then call discoverServices, and I get back a GATT_SUCCESS onServicesDiscoveres. So I can take the uuids from my services.
BUT when I try it on a beacon, I get back STATE_CONNECTED and when I call discoverServices, I get back an status code: 129 -> GATT_INTERNAL_ERROR
Why is this happening for my beacons? Is there another way, how I can take the devices uuid?
I just need the UUID to be able to do this after, for the beaconManager:
try {
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));
} catch (RemoteException e) { }
EDIT
I know that the beacon should ask me for a code to pair, but it doesn't. Why?
I tried adding this code:
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
But still I don't get a request to pair and input my passkey
This is my pairingRequestReceiver:
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(intToByteArray(123456));
abortBroadcast();
}
else
{
Log.e("","Unexpected pairing type: " + type);
}
}
}
};
After hours of trial and error I did manage to find a way to make it work like this:
1.I start the discovery the same, but when I select an bluetooth device, I ask to bond (pair) with it like this:
private void pairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
I have a ACTION_BOND_STATE_CHANGED receiver:
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED && prevState == BluetoothDevice.BOND_BONDING) {
Log.i("","Paired");
mBluetoothGatt = btDevice.connectGatt(MainActivity.this, false, mGattCallback);
} else if (state == BluetoothDevice.BOND_NONE && prevState == BluetoothDevice.BOND_BONDED){
Log.i("","Unpaired");
}
}
}
};
Which I register like this:
IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, intent);
And only after this, I try to connect with my BluetoothGattCallback. Hence, I can discover the services, and so on

Android BLE connection

I am new to Android Bluetooth API. I have to connect my app with a blood pressure monitor and get measurement data. I manage to get the connection working and get data when the device is not paired with my phone. However when it is paired, i get status = 8 in my onConnectionChanged. Here is my code
This is my mGattCallback
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
DebugLogger.debug("Status is "+status+" - new state is "+newState);
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mCallbacks.onDeviceConnected();
// start discovering services
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mCallbacks.onDeviceDisconnected();
gatt.close();
}
} else {
mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status);
}
}
Here I connect or disconnect my device
#Override
public void connect(final Context context, final BluetoothDevice device) {
mBluetoothGatt = device.connectGatt(context, true, mGattCallback);
mContext = context;
}
#Override
public void disconnect() {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
}
}
And this is for closing the whole connection after device is disconnected
#Override
public void closeBluetoothGatt() {
try {
mContext.unregisterReceiver(mBondingBroadcastReceiver);
} catch (Exception e) {
// the receiver must have been not registered or unregistered before
}
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBPMCharacteristic = null;
mBatteryCharacteristic = null;
mBluetoothGatt = null;
}
}
I know that status 8 means there is a timeout in my connection. Am i missing something? Cause it is really strange why is it doing this only when i try to connect to a paired device

Android BLE: List of discovered characteristics in service is incomplete

Attempting to read characteristics from a GATT service, the list is incomplete compared to the list I get from an iOS device, or the manufacturer guide.
I am reading the characteristics as follows:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
mBluetoothGatt = gatt;
if (shouldStartWriting && writeCharacteristicsQueue.peek() != null) {
mBluetoothGatt.writeCharacteristic(writeCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.CONNECTED));
Log.i(TAG, "Attempting to start service discovery:" +
gatt.discoverServices());
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
mBluetoothGatt = null;
EventBus.getDefault().post(new BTGattDisconnectedEvent());
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DISCOVERED));
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService service : gatt.getServices()) {
LOGD(TAG, "Found Service " + service.getUuid().toString());
discoverCharacteristics(service);
}
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} 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) {
parseCharacteristic(characteristic);
LOGD(TAG, String.format("%s | %s ", characteristic.getUuid(), characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)));//(BluetoothGattCharacteristic.FORMAT_UINT16));
if (readCharacteristicsQueue.peek() != null) {
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DONE_DISCOVERING));
}
}
}
and
private void discoverCharacteristics(BluetoothGattService service) {
for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {
LOGD(TAG, "Discovered UUID: " + gattCharacteristic.getUuid());
readCharacteristicsQueue.add(gattCharacteristic);
}
}
I also attempted to get this characteristic using getCharacteristic, but I received a null.
The characteristics found are:
Discovered UUID: 0000fff1-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff2-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff3-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff4-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff5-0000-1000-8000-00805f9b34fb
However, on iOS and according to the manufacturer, there should also be a 0000fff7.
Why isn't this characteristic being read?
UPDATE:
Nothing happened here. Not one of Android's BLE scanning apps can discover it.

Categories

Resources