Skip to content

Commit

Permalink
Merge pull request #967 from don/scan-with-timeout
Browse files Browse the repository at this point in the history
Add duration flag (in seconds) to scan with options
  • Loading branch information
peitschie authored May 20, 2023
2 parents 2349ef0 + 3946f97 commit b4704db
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 101 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,9 @@ See the [location permission notes](#location-permission-notes) above for inform

- **services**: List of services to discover, or [] to find all devices
- **options**: an object specifying a set of name-value pairs. The currently acceptable options are:
- _reportDuplicates_: _true_ if duplicate devices should be reported, _false_ (default) if devices should only be reported once. [optional]
- _scanMode_: String defines [setScanMode()](https://developer.android.com/reference/kotlin/android/bluetooth/le/ScanSettings.Builder#setscanmode) argument on Android.
- _reportDuplicates_: _true_ if duplicate devices should be reported, _false_ (default) if devices should only be reported once.
- _duration_: time in seconds to scan for. (default) Scans forever when not specified.
- _scanMode_: String defines [setScanMode()](https://developer.android.com/reference/kotlin/android/bluetooth/le/ScanSettings.Builder#setscanmode) argument on Android. Default on Android is _lowPower_. When interactive scanning from an app, _lowLatency_ can boost how quickly the device is found, at the expense of using more battery power.
Can be one of: _lowPower_ | _balanced_ | _lowLatency_ | _opportunistic_
- _callbackType_: String defines [setCallbackType()](https://developer.android.com/reference/kotlin/android/bluetooth/le/ScanSettings.Builder#setcallbacktype) argument on Android.
Can be one of: _all_ | _first_ | _lost_
Expand Down
32 changes: 7 additions & 25 deletions src/android/BLECentralPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ public class BLECentralPlugin extends CordovaPlugin {
private static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN" ; // API 31

// actions
private static final String SCAN = "scan";
private static final String START_SCAN = "startScan";
private static final String STOP_SCAN = "stopScan";
private static final String START_SCAN_WITH_OPTIONS = "startScanWithOptions";
private static final String BONDED_DEVICES = "bondedDevices";
Expand Down Expand Up @@ -146,6 +144,7 @@ public class BLECentralPlugin extends CordovaPlugin {
private int scanSeconds;
private ScanSettings scanSettings;
private final Handler stopScanHandler = new Handler(Looper.getMainLooper());
private final Runnable stopScanRunnable = this::stopScan;

// Bluetooth state notification
CallbackContext stateCallback;
Expand Down Expand Up @@ -210,21 +209,7 @@ public boolean execute(String action, CordovaArgs args, CallbackContext callback
}

boolean validAction = true;

if (action.equals(SCAN)) {

UUID[] serviceUUIDs = parseServiceUUIDList(args.getJSONArray(0));
int scanSeconds = args.getInt(1);
resetScanOptions();
findLowEnergyDevices(callbackContext, serviceUUIDs, scanSeconds);

} else if (action.equals(START_SCAN)) {

UUID[] serviceUUIDs = parseServiceUUIDList(args.getJSONArray(0));
resetScanOptions();
findLowEnergyDevices(callbackContext, serviceUUIDs, -1);

} else if (action.equals(STOP_SCAN)) {
if (action.equals(STOP_SCAN)) {
stopScan();
callbackContext.success();

Expand Down Expand Up @@ -526,7 +511,8 @@ public boolean execute(String action, CordovaArgs args, CallbackContext callback
if (reportDelay >= 0L)
scanSettings.setReportDelay( reportDelay );

findLowEnergyDevices(callbackContext, serviceUUIDs, -1, scanSettings.build() );
int scanDuration = options.optInt("duration", -1);
findLowEnergyDevices(callbackContext, serviceUUIDs, scanDuration, scanSettings.build() );
}

} else if (action.equals(BONDED_DEVICES)) {
Expand Down Expand Up @@ -1186,10 +1172,6 @@ public void onScanFailed(int errorCode) {
};


private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] serviceUUIDs, int scanSeconds) {
findLowEnergyDevices( callbackContext, serviceUUIDs, scanSeconds, new ScanSettings.Builder().build() );
}

private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] serviceUUIDs, int scanSeconds, ScanSettings scanSettings) {

if (!locationServicesEnabled() && Build.VERSION.SDK_INT < 31) {
Expand Down Expand Up @@ -1273,11 +1255,11 @@ private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] servic
filters.add(filter);
}
}
stopScanHandler.removeCallbacks(this::stopScan);
stopScanHandler.removeCallbacks(stopScanRunnable);
bluetoothLeScanner.startScan(filters, scanSettings, leScanCallback);

if (scanSeconds > 0) {
stopScanHandler.postDelayed(this::stopScan, scanSeconds * 1000);
stopScanHandler.postDelayed(stopScanRunnable, scanSeconds * 1000);
}

PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
Expand All @@ -1286,7 +1268,7 @@ private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] servic
}

private void stopScan() {
stopScanHandler.removeCallbacks(this::stopScan);
stopScanHandler.removeCallbacks(stopScanRunnable);
if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
LOG.d(TAG, "Stopping Scan");
try {
Expand Down
9 changes: 1 addition & 8 deletions src/browser/BLECentralPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@ function formatUUID(uuid) {

module.exports = {
deviceInfos: new Map(),

scan: function(services, seconds, success, failure) {
return this.startScanWithOptions(services, {}, success, failure);
},
startScan: function(services, success, failure) {
return this.startScanWithOptions(services, {}, success, failure);
},
startScanWithOptions: function(services, options, success, failure) {
startScanWithOptions: function (services, options, success, failure) {
if (!navigator.bluetooth) {
failure('Bluetooth is not supported on this browser.');
return;
Expand Down
3 changes: 1 addition & 2 deletions src/ios/BLECentralPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@
NSMutableDictionary *readRSSICallbacks;
NSDictionary<NSString*,id> *restoredState;
NSMutableDictionary *l2CapContexts;
NSTimer *scanTimer;
}

@property (strong, nonatomic) NSMutableSet *peripherals;
@property (strong, nonatomic) CBCentralManager *manager;

- (void)scan:(CDVInvokedUrlCommand *)command;
- (void)startScan:(CDVInvokedUrlCommand *)command;
- (void)startScanWithOptions:(CDVInvokedUrlCommand *)command;
- (void)stopScan:(CDVInvokedUrlCommand *)command;
- (void)connectedPeripheralsWithServices:(CDVInvokedUrlCommand*)command;
Expand Down
80 changes: 26 additions & 54 deletions src/ios/BLECentralPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -354,50 +354,6 @@ - (void)isEnabled:(CDVInvokedUrlCommand*)command {
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)scan:(CDVInvokedUrlCommand*)command {
NSLog(@"scan");
if ([manager state] != CBManagerStatePoweredOn) {
NSString *error = @"Bluetooth is disabled";
NSLog(@"%@", error);
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsString:error];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

discoverPeripheralCallbackId = [command.callbackId copy];

NSArray<NSString *> *serviceUUIDStrings = [command argumentAtIndex:0];
NSNumber *timeoutSeconds = [command argumentAtIndex:1];
NSArray<CBUUID *> *serviceUUIDs = [self uuidStringsToCBUUIDs:serviceUUIDStrings];

[manager scanForPeripheralsWithServices:serviceUUIDs options:nil];

[NSTimer scheduledTimerWithTimeInterval:[timeoutSeconds floatValue]
target:self
selector:@selector(stopScanTimer:)
userInfo:[command.callbackId copy]
repeats:NO];
}

- (void)startScan:(CDVInvokedUrlCommand*)command {
NSLog(@"startScan");
if ([manager state] != CBManagerStatePoweredOn) {
NSString *error = @"Bluetooth is disabled";
NSLog(@"%@", error);
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsString:error];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

discoverPeripheralCallbackId = [command.callbackId copy];
NSArray<NSString *> *serviceUUIDStrings = [command argumentAtIndex:0];
NSArray<CBUUID *> *serviceUUIDs = [self uuidStringsToCBUUIDs:serviceUUIDStrings];

[manager scanForPeripheralsWithServices:serviceUUIDs options:nil];
}

- (void)startScanWithOptions:(CDVInvokedUrlCommand*)command {
NSLog(@"startScanWithOptions");
if ([manager state] != CBManagerStatePoweredOn) {
Expand All @@ -420,16 +376,24 @@ - (void)startScanWithOptions:(CDVInvokedUrlCommand*)command {
[scanOptions setValue:reportDuplicates
forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
}
NSNumber *timeoutSeconds = [options valueForKey: @"duration"];

[manager scanForPeripheralsWithServices:serviceUUIDs options:scanOptions];

[scanTimer invalidate];
scanTimer = nil;
if (timeoutSeconds) {
scanTimer = [NSTimer scheduledTimerWithTimeInterval:[timeoutSeconds floatValue]
target:self
selector:@selector(stopScanTimer:)
userInfo:[command.callbackId copy]
repeats:NO];
}
}

- (void)stopScan:(CDVInvokedUrlCommand*)command {
NSLog(@"stopScan");

if ([manager state] == CBManagerStatePoweredOn) {
[manager stopScan];
}
[self internalStopScan];

if (discoverPeripheralCallbackId) {
discoverPeripheralCallbackId = nil;
Expand Down Expand Up @@ -639,12 +603,7 @@ - (void)writeL2Cap:(CDVInvokedUrlCommand *)command {

-(void)stopScanTimer:(NSTimer *)timer {
NSLog(@"stopScanTimer");

[manager stopScan];

if (discoverPeripheralCallbackId) {
discoverPeripheralCallbackId = nil;
}
[self internalStopScan];
}

#pragma mark - CBCentralManagerDelegate
Expand Down Expand Up @@ -1251,4 +1210,17 @@ - (id) tryDecodeBinaryData:(id)value {
return value;
}

- (void) internalStopScan {
[scanTimer invalidate];
scanTimer = nil;

if ([manager state] == CBManagerStatePoweredOn) {
[manager stopScan];
}

if (discoverPeripheralCallbackId) {
discoverPeripheralCallbackId = nil;
}
}

@end
2 changes: 2 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ declare namespace BLECentralPlugin {
reportDelay?: number;

reportDuplicates?: boolean;
/** Scanning duration in seconds */
duration?: number;
}

interface L2CAPOptions {
Expand Down
12 changes: 2 additions & 10 deletions www/ble.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,11 @@ var autoconnected = {};

module.exports = {
scan: function (services, seconds, success, failure) {
var successWrapper = function (peripheral) {
convertToNativeJS(peripheral);
success(peripheral);
};
cordova.exec(successWrapper, failure, 'BLE', 'scan', [services, seconds]);
module.exports.startScanWithOptions(services, { duration: seconds }, success, failure);
},

startScan: function (services, success, failure) {
var successWrapper = function (peripheral) {
convertToNativeJS(peripheral);
success(peripheral);
};
cordova.exec(successWrapper, failure, 'BLE', 'startScan', [services]);
module.exports.startScanWithOptions(services, undefined, success, failure);
},

stopScan: function (success, failure) {
Expand Down

0 comments on commit b4704db

Please sign in to comment.