I am trying to implement an android app that scans for BLE devices. Because I need some sort of distance information of the beacons I want to read the RSSI continuously. Currently I am able to display the RSSI but the value does not change. The application reads the value once and does not update the value. I used the sample BLE application from gitHub as a basis.
This is my Bluetooth device:
class DeviceHolder{
BluetoothDevice device;
int rssi;
public DeviceHolder(BluetoothDevice device, int rssi){
this. device = device;
this.rssi = rssi;
}
}
The list adapter:
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private ArrayList<DeviceHolder> mLeHolders;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mLeHolders = new ArrayList<DeviceHolder>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(DeviceHolder deviceHolder) {
if(!mLeDevices.contains(deviceHolder.device)) {
mLeDevices.add(deviceHolder.device);
mLeHolders.add(deviceHolder);
}
}
and the scan callback:
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
DeviceHolder deviceHolder = new DeviceHolder(device,rssi);
runOnUiThread(new DeviceAddTask( deviceHolder ) );
}
};
class DeviceAddTask implements Runnable {
DeviceHolder deviceHolder;
public DeviceAddTask( DeviceHolder deviceHolder ) {
this.deviceHolder = deviceHolder;
}
public void run() {
mLeDeviceListAdapter.addDevice(deviceHolder);
mLeDeviceListAdapter.notifyDataSetChanged();
}
}
The Bluetooth GattCallback in the BluetoothLeService Activity looks as follows:
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;
boolean rssiStatus = mBluetoothGatt.readRemoteRssi();
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);
}
public void onReadRemoteRssi(BluetoothGatt gatt,
int rssi, int status){
super.onReadRemoteRssi(gatt, rssi, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, String.format("BluetoothGatt ReadRssi[%d]", rssi));
} else {
Log.w(TAG, "onReadRemoteRssi received: " + status);
}
broadcastUpdate(ACTION_RSSI_VALUE_READ, rssi);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action, int rssi){
Log.d(TAG, "broadcastUpdate - rssi");
final Intent intent = new Intent(action);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_RSSI, rssi);
intent.setAction(ACTION_RSSI_VALUE_READ);
sendBroadcast(intent);
}
I looked up the internet and Stackoverflow for guidance, but the provided solutions did not work for me. I am using a Samsung Galaxy S5 with Android 6.01. Does anyone have a hint how to display the RSSI continuously for non-connected devices (while scanning)? Any hints regarding wrong implementation are welcome too.
Thanks a lot for your help!
Sayus
PS: onReadRemoteRssi is implemented because I want to read the RSSI when the devices are conected as well. This functionality is not important at this time and is only nice to have.
Your application reads an RSSI value once and doesn't update it because when you add a new BluetoothDevice
into your adapter, it checks if it already contains one.
if(!mLeDevices.contains(deviceHolder.device)) {
mLeDevices.add(deviceHolder.device);
mLeHolders.add(deviceHolder);
}
Instead, I would create a Map<BluetoothDevice,Integer>
where you update the rssi value for the device: mDeviceRssi.put(device, rssi)
.