Android - Bluetooth Writing Event - android

I'v made a Ble(Bluetooth 4.0 LE) App.
This App send byte data to BT device.
I had test when I made this function, but as soon as send(write) device was disconnected.
why disconnect?
Especially, LG SMART Phone.
Plz Help me..
//////////////
public static void Send_Data(byte[] data) {
if (mByteCharacteristic != null ) {
mByteCharacteristic.setValue(data);
mByteCharacteristic setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
if (bluetoothGatt != null) {
bluetoothGatt.writeCharacteristic(mByteCharacteristic);
}
}
}
///////////////

Make sure that:
mByteCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0x0
Otherwise try omitting the setWriteType() call. By default the characteristic should be using the correct write type.

Related

Android "A Call is in Progress" notification issue

I created a chat application that uses Twilio Sdk. Everything works fine but after a Video Call ends, I get this notification which doesn't go away whatever I try to do. After this notification appears, if I try to initiate Video Call, it doesn't work then. Maybe its using some of my resources like microphone which does not allow the app to start Video Calling because the Android system shows that microphone is still being used. Also this is appearing on my Redmi 9C. I have already searched everywhere on the net but no such solution found. It also states its a bug in some devices but there must be something that can be done to resolve this. Help would be appreciated thank you.
This is the code that is used to disconnect from a room:
private fun killAllVideoProcess() {
if (localVideoTrack != null) {
if (localParticipant != null) {
localParticipant!!.unpublishTrack(localVideoTrack!!)
}
localVideoTrack!!.release()
localVideoTrack = null
}
if (room != null && room!!.state != Room.State.DISCONNECTED) {
room!!.disconnect()
disconnectedFromOnDestroy = true
}
if (localAudioTrack != null) {
localAudioTrack!!.release()
localAudioTrack = null
}
if (localVideoTrack != null) {
localVideoTrack!!.release()
localVideoTrack = null
}
}//killAllVideoProcess ends

How to get the bluetooth a2dp connetcted event on xamarin?

I have a xamarin project (API 28, soon to be 29), and I need to catch the event of bluetooth a2dp device.
I have a broadcast receiver with the following intent filter:
IntentFilter bluetoothFilter = new IntentFilter();
bluetoothFilter.AddAction(BluetoothDevice.ActionAclConnected);
bluetoothFilter.AddAction(BluetoothDevice.ActionAclDisconnectRequested);
bluetoothFilter.AddAction(BluetoothDevice.ActionAclDisconnected);
var btReciever = new BluetoothReceiver();
this.RegisterReceiver(btReciever, bluetoothFilter);
In my manisfest, I got the following permission:
<uses-permission android:name="android.permission.BLUETOOTH" />
In the Receiver.OnReceive, I got this code:
public override void OnReceive(Context context, Intent intent) {
String action = intent.Action;
BluetoothDevice device = (BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
There I have a switch:
switch (action)
{
case BluetoothDevice.ActionFound:
Android.Util.Log.Debug(TAG, "Device Found");
//Device found
break;
case BluetoothDevice.ActionAclConnected:
Android.Util.Log.Debug(TAG, "Device Connected");
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
Thread.Sleep(1500);
var manager = context.GetSystemService(Context.AudioService) as AudioManager;
var devices = manager.GetDevices(GetDevicesTargets.Outputs);
Android.Util.Log.Debug(TAG, "devices=" + devices.Length);
foreach (var dev in devices)
{
Android.Util.Log.Debug(TAG, "dev: id={0} name={1} type={2}", dev.Id, dev.ProductName, dev.Type);
if (dev.ProductName == device.Name)
{
if (dev.Type.ToString().Contains("a2dp"))
{
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
}
Android.Util.Log.Debug(TAG, "Found output device");
}
}
//Device is now connected
break;
...
}
And I got a listener that implements the IBluetoothProfileServiceListener interface, and looks like this:
var btsListener = new BTServiceListener();
class BTServiceListener : AppCompatActivity, IBluetoothProfileServiceListener
{
public void OnServiceConnected([GeneratedEnum] ProfileType profile, IBluetoothProfile proxy)
{
if (profile == ProfileType.A2dp)
{
Android.Util.Log.Debug(TAG, "A2dp");
}
}
...
}
I need to catch the event onConnect of the bluetooth a2dp (and later headset), but I have no idea how exactly I should do it.
This code in the receiver, shows the bluetooth onConnect event (BluetoothDevice.ActionAclConnected in the switch), then I check the device list, there is not yet the connected device, then I wait 1500ms (I need somehow to improve this method, this cannot stay like this), for the audioService to add the actual a2dp device to the list, and in the for loop, I find the additional device via its name, and I am certain it is the right one. BUT, I have no programmaticaly way to find out what type of device was connected (remote, headset, a2bp...) other than to check is the name contains a2dp (see for loop)
After my research, I found this line:
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
This uses the context, the listener, and the desierd type of device (see Listener: BTServiceListener ), the problem is, I don't know if the proxy in the listener is the same device as the device in the broadcast receiver onConnect, and I have no idea how to use that function.
So my questions:
How and when should I use the BluetoothAdapter.DefaultAdapter.GetProfileProxy function and be certain that I have the same device in the listener and in the onConnect function?
How to get all the devices from the manager without putting the thread to sleep? Because, without the Thread.Sleep, the actual device is not in the list because the onConnect function is called earlyer then the addition of the device to the audioService.
Thread.Sleep(1500); // <-- this needs to go
var manager = context.GetSystemService(Context.AudioService) as AudioManager;
var devices = manager.GetDevices(GetDevicesTargets.Outputs);
How should I distinguish between the device types? Because, I have a feeling that my method of String.Contains(string) is not the way to go
Sorry for the long question, thank you for your help and time.
Let me know, if you need anything else.

BLE writeCharacteristic issue

I'm trying to writeCharacteristic() to a BLE device.
I used Google example app to establish the connection, the connection is fine. I can see the BLE Services and the services Characteristics.
The writeCharacteristic() method return true and the onCharacteristicWrite() callback return status BluetoothGatt.GATT_SUCCESS but nothing happening with the device:
I tried all the solutions in stack overflow and nothing helps.
Here is my code:
In the BluetoothLeService class i have sendData() method, which gets a byte[]
I'm sending each command separately because of the maximum payload of 33 bytes.
public void sendData(byte[] data) {
String lService = "71387664-eb78-11e6-b006-92361f002671";
String lCharacteristic = "71387663-eb78-11e6-b006-92361f002671";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
if (mBluetoothGattCharacteristic == null) {
mBluetoothGattCharacteristic = mBluetoothGatt.getService(UUID.fromString(lService)).getCharacteristic(UUID.fromString(lCharacteristic));
}
mBluetoothGattCharacteristic.setValue(data);
boolean write = mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic);
}
In your code you check property of characteristics?
If Write something on device then characteristics must have write property or write no response property or write & notify property.
So Check in your code on which characteristics you are write.
Your code looks OK, if you've got GATT_SUCCESS it means that characteristic was written successfully.
You can also try to read this characteristic and check if value is updated. Also it's possible that characteristic was written successfully but corresponded device's functionality will be triggered only after disconnection from device. And also it's possible that there is some bug on a device side.
I found the issue. Hope my answer will help others.
The issue was that, I was sending byte[] array bigger than it's allow(20 byte). Also, I needed to add "\r" inside this byte[] array, thats way, the BLE Devise knows it's the end of the command.
Another thing, I needed to create a queue and pop from it after I get response in onCharacteristicRead().
class DataQueues {
private ArrayList<byte[]> queueArray;
private int queuSize;
protected DataQueues() {
queueArray = new ArrayList<>();
}
protected void addToQueue(byte[] bytesArr) {
queueArray.add(bytesArr);
}
protected byte[] popQueue() {
if (queueArray.size() >= 0)
return queueArray.remove(0);
else {
return null;
}
}
protected int getArrSize() {
return queueArray.size();
}
}
Hope this will help some one.

Android BLE - Connecting to multiple devices at once

I am developing an Android Application that connects to a BLE Device and reads the Gatt Services and Gatt Characteristics. I used the BluetoothLeGatt sample project from the Android Development Site as my reference.
So far, I am able to programmatically connect to a device (I took note of my Device's Address to be able to do this) and filter out the specific Gatt Service I want to read and that Services' specific Characteristics by taking note of the UUID of both the Service and the Characteristics. The sample provided by Google also updates whenever there's a message sent from my BLE Device to my Android Application. Overall, I have no problems at this end.
However, upon reading up further on GATT, I found that it is possible to connect to multiple BLE devices (all slaves OR servers - being the ones that send the data) using a single Android Application (as master OR client - as the one who receives said data). So what I tried to do was to have 2 BLE Devices (different Address), took note of their Address, and then my application tries to connect to them once the application sees that those 2 addresses are up and running.
In code, I call this function when I see my 2 BLE Devices:
private void connectToDevice(){
mDeviceName = deviceList.get(currentIndex).getName();
mDeviceAddress = deviceList.get(currentIndex).getAddress();
Log.e(TAG, "connecting to device name = " + mDeviceName);
mBluetoothLeService.connect(mDeviceAddress);
}
Where currentIndex is initially set to zero. Then once I get a successful connection, I do:
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
Log.e(TAG, "connected");
mConnected = true;
if(currentIndex < deviceList.size()-1) currentIndex ++;
connectToDevice();
}
}
};
Where I check if I still have devices to connect to in my deviceList, if so, increment my counter and then connect until I exhaust everything in my list.
However, I seem to have no success at all using this method.
Kindly note that switching connection (round robin) between my devices isn't an option. This will be an issue when I have a lot of devices and it's important to get their messages real time without delays. This said, I have to have a live connection to my devices.
Has anyone tried to connect to multiple BLE Devices in Android? I'm not sure on how to proceed on this.
Indeed it is possible to connect to more than one peripheral from your Android device. However, it will make your code much more complex since you will need to manage each connection and responses.
For each connection you would have to implement a BluetoothGatt with it's callbacks. I tested it many months ago with a dummy test and as I said, it worked well and I was able to connect to different peripherals. However, if you chain many commands there seem to be some overlapping issues described in this thread.
As asked here is the relevant code : (Here the ArrayList contains the founded peripheral devices)
for(int i=0;i< Utility.selectedDeviceList.size();i++) {
Log.d(Utility.TAG,"state"+ Utility.selectedDeviceList.get(i).getmConnectionState());
if (Utility.selectedDeviceList.get(i).getmConnectionState() != Utility.CONNECTED) {
Log.d(Utility.TAG,"Connecting LeSerive::" + Utility.selectedDeviceList.get(i).getAddress());
Utility.mBluetoothLeService.connect(i, Utility.selectedDeviceList.get(i).getAddress());
}
}
This for loop is a part of runnable interface which is called inside a handler having a looper.
public void run() {
Looper.prepare();
Looper mLooper = Looper.myLooper();
Log.d(Utility.TAG,"BLE Thread Started::");
mHandler = new Handler(mLooper) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Utility.BLE_SYNC:
Log.d(Utility.TAG,"BLE Sync Connecting::");
mHandler.post(SynState);
break;
}
};
Looper.loop();
}
I used this approach because their is lot of communication between peripherals to send and receive the data from them.
This is the connect method which inside a Service :
public boolean connect(int tag,final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(Utility.TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
Utility.selectedDeviceList.get(tag).setmConnectionState(Utility.CONNECTING);
if( Utility.selectedDeviceList.get(tag).getmBluetoothGatt()==null){
Log.w(Utility.TAG, "new connect :: "+ Utility.selectedDeviceList.get(tag).getAddress());
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(Utility.TAG, "Device not found. Unable to connect.");
return false;
}
try {
Utility.selectedDeviceList.get(tag).setmBluetoothGatt(device.connectGatt(this, false, mGattCallback));
}
catch (Exception e)
{
e.printStackTrace();
Log.d(Utility.TAG,"ConnectGatt exception caught");
}
}
return true;
}
This is the mGattCallBack :
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(Utility.TAG, "onServicesDiscovered");
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(Utility.TAG,">>onCharacteristicWrite");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
}
};
Hope it clears few things for you
It is possible to connect to multiple devices at a time. in my experience it works pretty stable and the number of devices you can connect to (stable) depends on your hardware. I found out that best practise (for me) was to create one separate service for the scanning stuff and one service for each Bluetoothconnection. it's important not to use bound services because the termination of a connection is not stible when binding to it.
With this pattern you can control your connection easily. To transport data out of your service you can use a broadcastreceiver, for example if you want to display the data in your main activity. Termination of the connection is pretty important so stop the service and in onDestroy call
mConnectedGatt.disconnect();
ble_device=null;
For the Scanning part I've used a List of Strings where I saved all the mac Adresses I want to find. When i found one device I deleted it from the list and if the list is empty it stopped the scanner service. To transmit my found device I used a broadcastreceiver and sent it to my main Activity. There I transmitted it to the right service.
Hope this helps

Android Bluetooth Low Energy Pairing

How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.
Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.
When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.
I am not sure how to get the device paired or how to provide the authentication information for the read to complete.
I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!
When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementNotificationEnabled();
if (mGlucoseMeasurementContextCharacteristic != null) {
enableGlucoseMeasurementContextNotification(gatt);
} else {
enableRecordAccessControlPointIndication(gatt);
}
}
if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementContextNotificationEnabled();
enableRecordAccessControlPointIndication(gatt);
}
if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onRecordAccessControlPointIndicationsEnabled();
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
// this is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
mCallbacks.onBondingRequired();
// I'm starting the Broadcast Receiver that will listen for bonding process changes
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mContext.registerReceiver(mBondingBroadcastReceiver, filter);
} else {
// this situation happens when you try to connect for the second time to already bonded device
// it should never happen, in my opinion
Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
// I don't know what to do here
// This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.
}
} else {
mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);
}
};
Where the mBondingBroadcastReceiver is:
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
if (bondState == BluetoothDevice.BOND_BONDED) {
// Continue to do what you've started before
enableGlucoseMeasurementNotification(mBluetoothGatt);
mContext.unregisterReceiver(this);
mCallbacks.onBonded();
}
}
};
Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.
You might need to check the Kernel smp.c file, which method of paring it invoke for paring. 1) passkey 2)Just work or etc . i guess if it will be able to invoke MIMT and passkey level of security , there will not be any authentication issue. Make sure all flags is set to invoke the SMP passkey methods. track by putting some print in smp.c file.
A solution which works in ICS : with btmgmt tool in android and hooking it in encryption APIs. with passkey or any other methods. it works. You might need to add the passkey APIs in btmgmt from latest bluez code.
i think new android 4.4 provide pairing method. same problem already i am facing so wait for update and hope over problem solved createBond() method .
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#setPairingConfirmation%28boolean%29

Categories

Resources