thegecko/bleat

Calling requestDevice twice produces error on Android when using Evothings adapter

mikaelkindborg opened this issue · 5 comments

Found a bug on Android when calling requestDevice a second time (did disconnect in between calls), get this error "requestDevice error: Android function startLeScan failed".

I now understand why this error happens. It is because stopScan is never called. (This was an issue on iOS also, but did not cause an error.) Need some advice on how to proceed.

The Evothings adapter never calls the callback completeFn in startScan:

adapter.startScan = function(
    serviceUUIDs,   // String[] serviceUUIDs        advertised service UUIDs to restrict results by
    foundFn,        // Function(Object deviceInfo)  function called with each discovered deviceInfo
    completeFn,     // Function()                   function called when scanning completed
    errorFn         // Function(String errorMsg)    function called if error occurs
    )
{
    init(function() {
        evothings.ble.startScan(
            function(deviceInfo) {
                if (foundFn) { foundFn(createBleatDeviceObject(deviceInfo)); }
            },
            function(error) {
                if (errorFn) { errorFn(error); }
            });
    });
};

https://github.com/thegecko/bleat/blob/master/dist/adapter.evothings.js#L67

This means that the variable scanner in api.web-bluetooth.js won't be set:

https://github.com/thegecko/bleat/blob/master/dist/api.web-bluetooth.js#L202

And adapter.stopScan() is never called in cancelRequest:

https://github.com/thegecko/bleat/blob/master/dist/api.web-bluetooth.js#L209

I don't quite understand when completeFn is supposed to be called. Should it be called as soon as scanning begins (when startScan is called)?

This might be a problem also for other adapters if scanning is started and completeFn for some reason is never called. Then stopScan will not be called.

Should I solve this by calling completeFn or should the code in api.web-bluetooth.js handle this situation?

Making this change to startScan in the adapter solves the bug:

adapter.startScan = function(
    serviceUUIDs,   // String[] serviceUUIDs        advertised service UUIDs to restrict results by
    foundFn,        // Function(Object deviceInfo)  function called with each discovered deviceInfo
    completeFn,     // Function()                   function called when scanning completed
    errorFn         // Function(String errorMsg)    function called if error occurs
    )
{
    init(function() {
        evothings.ble.startScan(
            function(deviceInfo) {
                if (foundFn) { foundFn(createBleatDeviceObject(deviceInfo)); }
            },
            function(error) {
                if (errorFn) { errorFn(error); }
            });
        if (completeFn) { completeFn(); }
    });
};

Your suggested change is the right fix. Both APIs expect the callback function to be executed once scanning starts.

I would also suggest the evothings adapter explicitly stops any scanning before starting if that's what it requires. This is an adapter implementation issue, the old ChromeOS adapter used to always call stop() before starting a scan, too.

In this case, it's your call whether you just add the callback function or both a callback and explicit stop().

@thegecko Thanks a lot for the help. Added call to completeFn and also now stopping scan before scanning starts.

Tested working on Android and iOS.