[Android] Local name is not always updated during Scan
murilommp opened this issue · 3 comments
Hello, everyone.
I'm building a cordova app for Android with the goal of write data to and read data from a proprietary BLE device. Everything works great, but I am facing an issue when scanning devices with "ble.startScan()" just after I have changed the device name. The new device name is not updated immediately.
My proprietary device is advertising it's name correctaly and I can receive the updated information when I use third party apps (like ST BLE TooBox) to perform an scan.
I realize that method asJSONObject() in Peripheral class (in file Peripheral.java) uses method getName() from class BluetoothDevice to fill attribute name in JSON object passed as parameter to javascript callback. I saw in method documentation that the name returned by it may be old due to have been extracted from cache.
I also checked that class ScanRecord has the method getDeviceName and it returns the local name received in advertising packet.
So I created an attribute called "advertsingName" in class Peripheral to hold that information:
private BluetoothDevice device;
private byte[] advertisingData;
private String advertsingName = null;
private int advertisingRSSI;
private boolean autoconnect = false;
private boolean connected = false;
private boolean connecting = false;
private ConcurrentLinkedQueue<BLECommand> commandQueue = new ConcurrentLinkedQueue<BLECommand>();
private final Map<Integer, L2CAPContext> l2capContexts = new HashMap<Integer, L2CAPContext>();
private final AtomicBoolean bleProcessing = new AtomicBoolean();
Then, I changed the constructor from:
public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord) {
this.device = device;
this.advertisingRSSI = advertisingRSSI;
this.advertisingData = scanRecord;
}
to
public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord, String advertsingName) {
this.device = device;
this.advertisingRSSI = advertisingRSSI;
this.advertisingData = scanRecord;
this.advertsingName = advertsingName;
}
And finally, I changed method asJSONObject from:
public JSONObject asJSONObject() {
JSONObject json = new JSONObject();
try {
json.put("name", device.getName());
json.put("id", device.getAddress()); // mac address
if (advertisingData != null) {
json.put("advertising", byteArrayToJSON(advertisingData));
}
// TODO real RSSI if we have it, else
if (advertisingRSSI != FAKE_PERIPHERAL_RSSI) {
json.put("rssi", advertisingRSSI);
}
} catch (JSONException e) { // this shouldn't happen
e.printStackTrace();
}
return json;
}
to
public JSONObject asJSONObject() {
JSONObject json = new JSONObject();
try {
if(this.advertsingName == null)
json.put("name", device.getName());
else
json.put("name", this.advertsingName);
json.put("id", device.getAddress()); // mac address
if (advertisingData != null) {
json.put("advertising", byteArrayToJSON(advertisingData));
}
// TODO real RSSI if we have it, else
if (advertisingRSSI != FAKE_PERIPHERAL_RSSI) {
json.put("rssi", advertisingRSSI);
}
} catch (JSONException e) { // this shouldn't happen
e.printStackTrace();
}
return json;
}
I also changed the onScanResult() in BLECentralPlugin.java file from:
public void onScanResult(int callbackType, ScanResult result) {
LOG.w(TAG, "Scan Result");
super.onScanResult(callbackType, result);
BluetoothDevice device = result.getDevice();
String address = device.getAddress();
boolean alreadyReported = peripherals.containsKey(address) && !peripherals.get(address).isUnscanned();
if (!alreadyReported) {
Peripheral peripheral = new Peripheral(device, result.getRssi(), result.getScanRecord().getBytes());
peripherals.put(device.getAddress(), peripheral);
if (discoverCallback != null) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, peripheral.asJSONObject());
pluginResult.setKeepCallback(true);
discoverCallback.sendPluginResult(pluginResult);
}
} else {
Peripheral peripheral = peripherals.get(address);
if (peripheral != null) {
peripheral.update(result.getRssi(), result.getScanRecord().getBytes());
if (reportDuplicates && discoverCallback != null) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, peripheral.asJSONObject());
pluginResult.setKeepCallback(true);
discoverCallback.sendPluginResult(pluginResult);
}
}
}
}
to
public void onScanResult(int callbackType, ScanResult result) {
LOG.w(TAG, "Scan Result");
super.onScanResult(callbackType, result);
BluetoothDevice device = result.getDevice();
String address = device.getAddress();
boolean alreadyReported = peripherals.containsKey(address) && !peripherals.get(address).isUnscanned();
if (!alreadyReported) {
Peripheral peripheral = new Peripheral(device, result.getRssi(), result.getScanRecord().getBytes(), result.getScanRecord().getDeviceName());
peripherals.put(device.getAddress(), peripheral);
if (discoverCallback != null) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, peripheral.asJSONObject());
pluginResult.setKeepCallback(true);
discoverCallback.sendPluginResult(pluginResult);
}
} else {
Peripheral peripheral = peripherals.get(address);
if (peripheral != null) {
peripheral.update(result.getRssi(), result.getScanRecord().getBytes());
if (reportDuplicates && discoverCallback != null) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, peripheral.asJSONObject());
pluginResult.setKeepCallback(true);
discoverCallback.sendPluginResult(pluginResult);
}
}
}
}
Now I always have the local name updated during scan, even just after I have writen a new value to it.
Is there any other way to have the local name updated during scan instead having a cached info?
Thanks in advance!
Thanks for the tip and code samples @murilommp
I'll have a look... it seems like something we should easily support in the plugin.
The same thing happened to me, I performed a scan and changed the name.
On my Android the name was updated but my iPhone was not. I restarted the phone but it still showed the same name.
@GerardoPrototype I think you're hitting an iOS caching issue. The specific code suggestion here is for Android only, which sounds like it's already working correctly for you.
iOS does a lot of caching. For some good info, check out: https://developer.apple.com/forums/thread/19381