From 580d55a1e38ce086d3f10e4cad1c06c3d3589bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Cunha?= Date: Wed, 4 May 2022 12:08:05 +0100 Subject: [PATCH] Scan filters with mac addresses --- android/src/main/AndroidManifest.xml | 17 ++++++-- .../FlutterBluePlusPlugin.java | 39 +++++++++++------ lib/gen/flutterblueplus.pb.dart | 8 ++++ lib/gen/flutterblueplus.pbjson.dart | 3 +- lib/src/flutter_blue_plus.dart | 42 ++++++------------- protos/flutterblueplus.proto | 1 + 6 files changed, 63 insertions(+), 47 deletions(-) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index e63b4417..9d47e543 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,16 +1,25 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.boskokg.flutter_blue_plus"> - + - - + + + diff --git a/android/src/main/java/com/boskokg/flutter_blue_plus/FlutterBluePlusPlugin.java b/android/src/main/java/com/boskokg/flutter_blue_plus/FlutterBluePlusPlugin.java index 4eb5e62d..fbf934d3 100644 --- a/android/src/main/java/com/boskokg/flutter_blue_plus/FlutterBluePlusPlugin.java +++ b/android/src/main/java/com/boskokg/flutter_blue_plus/FlutterBluePlusPlugin.java @@ -44,6 +44,7 @@ import java.util.UUID; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -861,21 +862,33 @@ private void startScan21(Protos.ScanSettings proto) throws IllegalStateException BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner(); if(scanner == null) throw new IllegalStateException("getBluetoothLeScanner() is null. Is the Adapter on?"); int scanMode = proto.getAndroidScanMode(); - int count = proto.getServiceUuidsCount(); - List filters = new ArrayList<>(count); - for(int i = 0; i < count; i++) { - String uuid = proto.getServiceUuids(i); - ScanFilter f = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid)).build(); + List filters = fetchFilters(proto); + ScanSettings settings = new ScanSettings.Builder().setScanMode(scanMode).build(); + scanner.startScan(filters, settings, getScanCallback21()); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private List fetchFilters(Protos.ScanSettings proto) { + List filters; + + int macCount = proto.getMacAddressesCount(); + int serviceCount = proto.getServiceUuidsCount(); + int count = macCount > 0 ? macCount : serviceCount; + filters = new ArrayList<>(count); + + for (int i = 0; i < count; i++) { + ScanFilter f; + if (macCount == count) { + String macAddress = proto.getMacAddresses(i); + f = new ScanFilter.Builder().setDeviceAddress(macAddress).build(); + } else { + String uuid = proto.getServiceUuids(i); + f = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid)).build(); + } filters.add(f); } - ScanSettings settings = new ScanSettings.Builder() - .setScanMode(scanMode) - .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE) - .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT) - .setReportDelay(0L) - .build(); - scanner.startScan(filters, settings, getScanCallback21()); + + return filters; } @TargetApi(21) diff --git a/lib/gen/flutterblueplus.pb.dart b/lib/gen/flutterblueplus.pb.dart index d9ed0823..2b8708c1 100644 --- a/lib/gen/flutterblueplus.pb.dart +++ b/lib/gen/flutterblueplus.pb.dart @@ -213,6 +213,7 @@ class ScanSettings extends $pb.GeneratedMessage { ..a<$core.int>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'androidScanMode', $pb.PbFieldType.O3) ..pPS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'serviceUuids') ..aOB(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'allowDuplicates') + ..pPS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'macAddresses') ..hasRequiredFields = false ; @@ -221,6 +222,7 @@ class ScanSettings extends $pb.GeneratedMessage { $core.int? androidScanMode, $core.Iterable<$core.String>? serviceUuids, $core.bool? allowDuplicates, + $core.Iterable<$core.String>? macAddresses, }) { final _result = create(); if (androidScanMode != null) { @@ -232,6 +234,9 @@ class ScanSettings extends $pb.GeneratedMessage { if (allowDuplicates != null) { _result.allowDuplicates = allowDuplicates; } + if (macAddresses != null) { + _result.macAddresses.addAll(macAddresses); + } return _result; } factory ScanSettings.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -275,6 +280,9 @@ class ScanSettings extends $pb.GeneratedMessage { $core.bool hasAllowDuplicates() => $_has(2); @$pb.TagNumber(3) void clearAllowDuplicates() => clearField(3); + + @$pb.TagNumber(4) + $core.List<$core.String> get macAddresses => $_getList(3); } class ScanResult extends $pb.GeneratedMessage { diff --git a/lib/gen/flutterblueplus.pbjson.dart b/lib/gen/flutterblueplus.pbjson.dart index 641741f4..23d9151c 100644 --- a/lib/gen/flutterblueplus.pbjson.dart +++ b/lib/gen/flutterblueplus.pbjson.dart @@ -86,11 +86,12 @@ const ScanSettings$json = const { const {'1': 'android_scan_mode', '3': 1, '4': 1, '5': 5, '10': 'androidScanMode'}, const {'1': 'service_uuids', '3': 2, '4': 3, '5': 9, '10': 'serviceUuids'}, const {'1': 'allow_duplicates', '3': 3, '4': 1, '5': 8, '10': 'allowDuplicates'}, + const {'1': 'mac_addresses', '3': 4, '4': 3, '5': 9, '10': 'macAddresses'}, ], }; /// Descriptor for `ScanSettings`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List scanSettingsDescriptor = $convert.base64Decode('CgxTY2FuU2V0dGluZ3MSKgoRYW5kcm9pZF9zY2FuX21vZGUYASABKAVSD2FuZHJvaWRTY2FuTW9kZRIjCg1zZXJ2aWNlX3V1aWRzGAIgAygJUgxzZXJ2aWNlVXVpZHMSKQoQYWxsb3dfZHVwbGljYXRlcxgDIAEoCFIPYWxsb3dEdXBsaWNhdGVz'); +final $typed_data.Uint8List scanSettingsDescriptor = $convert.base64Decode('CgxTY2FuU2V0dGluZ3MSKgoRYW5kcm9pZF9zY2FuX21vZGUYASABKAVSD2FuZHJvaWRTY2FuTW9kZRIjCg1zZXJ2aWNlX3V1aWRzGAIgAygJUgxzZXJ2aWNlVXVpZHMSKQoQYWxsb3dfZHVwbGljYXRlcxgDIAEoCFIPYWxsb3dEdXBsaWNhdGVzEiMKDW1hY19hZGRyZXNzZXMYBCADKAlSDG1hY0FkZHJlc3Nlcw=='); @$core.Deprecated('Use scanResultDescriptor instead') const ScanResult$json = const { '1': 'ScanResult', diff --git a/lib/src/flutter_blue_plus.dart b/lib/src/flutter_blue_plus.dart index a063e25d..73357ba6 100644 --- a/lib/src/flutter_blue_plus.dart +++ b/lib/src/flutter_blue_plus.dart @@ -5,14 +5,11 @@ part of flutter_blue_plus; class FlutterBluePlus { - final MethodChannel _channel = - const MethodChannel('flutter_blue_plus/methods'); - final EventChannel _stateChannel = - const EventChannel('flutter_blue_plus/state'); - final StreamController _methodStreamController = - StreamController.broadcast(); // ignore: close_sinks - Stream get _methodStream => _methodStreamController - .stream; // Used internally to dispatch methods from platform. + final MethodChannel _channel = const MethodChannel('flutter_blue_plus/methods'); + final EventChannel _stateChannel = const EventChannel('flutter_blue_plus/state'); + final StreamController _methodStreamController = StreamController.broadcast(); // ignore: close_sinks + Stream get _methodStream => + _methodStreamController.stream; // Used internally to dispatch methods from platform. /// Singleton boilerplate FlutterBluePlus._() { @@ -31,8 +28,7 @@ class FlutterBluePlus { LogLevel get logLevel => _logLevel; /// Checks whether the device supports Bluetooth - Future get isAvailable => - _channel.invokeMethod('isAvailable').then((d) => d); + Future get isAvailable => _channel.invokeMethod('isAvailable').then((d) => d); /// Checks if Bluetooth functionality is turned on Future get isOn => _channel.invokeMethod('isOn').then((d) => d); @@ -62,8 +58,7 @@ class FlutterBluePlus { final BehaviorSubject _isScanning = BehaviorSubject.seeded(false); Stream get isScanning => _isScanning.stream; - final BehaviorSubject> _scanResults = - BehaviorSubject.seeded([]); + final BehaviorSubject> _scanResults = BehaviorSubject.seeded([]); /// Returns a stream that is a list of [ScanResult] results while a scan is in progress. /// @@ -117,12 +112,14 @@ class FlutterBluePlus { ScanMode scanMode = ScanMode.lowLatency, List withServices = const [], List withDevices = const [], + List macAddresses = const [], Duration? timeout, bool allowDuplicates = false, }) async* { var settings = protos.ScanSettings.create() ..androidScanMode = scanMode.value ..allowDuplicates = allowDuplicates + ..macAddresses.addAll(macAddresses) ..serviceUuids.addAll(withServices.map((g) => g.toString()).toList()); if (_isScanning.value == true) { @@ -242,15 +239,7 @@ enum LogLevel { } /// State of the bluetooth adapter. -enum BluetoothState { - unknown, - unavailable, - unauthorized, - turningOn, - on, - turningOff, - off -} +enum BluetoothState { unknown, unavailable, unauthorized, turningOn, on, turningOff, off } class ScanMode { const ScanMode(this.value); @@ -272,8 +261,7 @@ class DeviceIdentifier { int get hashCode => id.hashCode; @override - bool operator ==(other) => - other is DeviceIdentifier && compareAsciiLowerCase(id, other.id) == 0; + bool operator ==(other) => other is DeviceIdentifier && compareAsciiLowerCase(id, other.id) == 0; } class ScanResult { @@ -288,10 +276,7 @@ class ScanResult { @override bool operator ==(Object other) => - identical(this, other) || - other is ScanResult && - runtimeType == other.runtimeType && - device == other.device; + identical(this, other) || other is ScanResult && runtimeType == other.runtimeType && device == other.device; @override int get hashCode => device.hashCode; @@ -312,8 +297,7 @@ class AdvertisementData { AdvertisementData.fromProto(protos.AdvertisementData p) : localName = p.localName, - txPowerLevel = - (p.txPowerLevel.hasValue()) ? p.txPowerLevel.value : null, + txPowerLevel = (p.txPowerLevel.hasValue()) ? p.txPowerLevel.value : null, connectable = p.connectable, manufacturerData = p.manufacturerData, serviceData = p.serviceData, diff --git a/protos/flutterblueplus.proto b/protos/flutterblueplus.proto index acfba66d..eb51c7dd 100644 --- a/protos/flutterblueplus.proto +++ b/protos/flutterblueplus.proto @@ -42,6 +42,7 @@ message ScanSettings { int32 android_scan_mode = 1; repeated string service_uuids = 2; bool allow_duplicates = 3; + repeated string mac_addresses = 4; } message ScanResult {