Skip to content

Commit

Permalink
connect now returns Stream<BluetoothDeviceState>, automatically disco…
Browse files Browse the repository at this point in the history
…nnects on unsubscribe
  • Loading branch information
pauldemarco committed Sep 6, 2017
1 parent 19d8110 commit 3788a1a
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ public void onMethodCall(MethodCall call, Result result) {
case "connect":
{
byte[] data = call.arguments();
Protos.ConnectOptions options;
Protos.ConnectRequest options;
try {
options = Protos.ConnectOptions.newBuilder().mergeFrom(data).build();
options = Protos.ConnectRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
Expand Down
40 changes: 22 additions & 18 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
/// Device
BluetoothDevice device;
bool get isConnected => (device != null);
StreamSubscription connectionSubscription;
List<BluetoothService> services = new List();
StreamSubscription<List<int>> valueChangedSubscription;
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;
Expand Down Expand Up @@ -62,6 +63,8 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
_stateSubscription = null;
_scanSubscription?.cancel();
_scanSubscription = null;
connectionSubscription?.cancel();
connectionSubscription = null;
super.dispose();
}

Expand All @@ -87,35 +90,36 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
});
}

_connect(ScanResult r) async {
_connect(BluetoothDevice d) async {
device = d;
// Connect to device
BluetoothDevice d = await _flutterBlue.connect(r.device.id);
setState(() {
device = d;
});

// Discover the services
List<BluetoothService> s = await device.discoverServices();
setState(() {
services = s;
});
connectionSubscription = _flutterBlue.connect(device).listen(null);

// Update the connection state
var state = await device.state;
setState(() {
deviceState = state;
// Update the connection state immediately
device.state.then((s) {
setState(() {
deviceState = s;
});
});

// Subscribe to connection changes
device.onStateChanged().listen((s) {
setState(() {
deviceState = s;
});
if(s == BluetoothDeviceState.connected) {
device.discoverServices().then((s) {
setState(() {
services = s;
});
});
}
});
}

_disconnect() async {
await _flutterBlue.cancelConnection(device.id);
_disconnect() {
connectionSubscription?.cancel();
connectionSubscription = null;
setState(() {
device = null;
});
Expand Down Expand Up @@ -186,7 +190,7 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
title: new Text(s.device.name),
subtitle: new Text(s.device.id.toString()),
leading: new Text(s.rssi.toString()),
onTap: () => _connect(s),
onTap: () => _connect(s.device),
))
.toList();
}
Expand Down
28 changes: 14 additions & 14 deletions lib/gen/flutterblue.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,27 +206,27 @@ class ScanResult extends GeneratedMessage {

class _ReadonlyScanResult extends ScanResult with ReadonlyMessageMixin {}

class ConnectOptions extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ConnectOptions')
class ConnectRequest extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ConnectRequest')
..a<String>(1, 'remoteId', PbFieldType.OS)
..a<bool>(2, 'androidAutoConnect', PbFieldType.OB)
..hasRequiredFields = false
;

ConnectOptions() : super();
ConnectOptions.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ConnectOptions.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ConnectOptions clone() => new ConnectOptions()..mergeFromMessage(this);
ConnectRequest() : super();
ConnectRequest.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ConnectRequest.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ConnectRequest clone() => new ConnectRequest()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static ConnectOptions create() => new ConnectOptions();
static PbList<ConnectOptions> createRepeated() => new PbList<ConnectOptions>();
static ConnectOptions getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyConnectOptions();
static ConnectRequest create() => new ConnectRequest();
static PbList<ConnectRequest> createRepeated() => new PbList<ConnectRequest>();
static ConnectRequest getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyConnectRequest();
return _defaultInstance;
}
static ConnectOptions _defaultInstance;
static void $checkItem(ConnectOptions v) {
if (v is! ConnectOptions) checkItemFailed(v, 'ConnectOptions');
static ConnectRequest _defaultInstance;
static void $checkItem(ConnectRequest v) {
if (v is! ConnectRequest) checkItemFailed(v, 'ConnectRequest');
}

String get remoteId => $_get(0, 1, '');
Expand All @@ -240,7 +240,7 @@ class ConnectOptions extends GeneratedMessage {
void clearAndroidAutoConnect() => clearField(2);
}

class _ReadonlyConnectOptions extends ConnectOptions with ReadonlyMessageMixin {}
class _ReadonlyConnectRequest extends ConnectRequest with ReadonlyMessageMixin {}

class BluetoothDevice extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('BluetoothDevice')
Expand Down
4 changes: 2 additions & 2 deletions lib/gen/flutterblue.pbjson.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ const ScanResult$json = const {
],
};

const ConnectOptions$json = const {
'1': 'ConnectOptions',
const ConnectRequest$json = const {
'1': 'ConnectRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'android_auto_connect', '3': 2, '4': 1, '5': 8, '10': 'androidAutoConnect'},
Expand Down
33 changes: 23 additions & 10 deletions lib/src/flutter_blue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class FlutterBlue {
..serviceUuids.addAll(withServices.map((g) => g.toString()).toList());
StreamSubscription subscription;
final controller = new StreamController(onCancel: () {
print('onCancel');
_stopScan();
subscription.cancel();
});
Expand All @@ -85,23 +84,37 @@ class FlutterBlue {
Future<Null> _stopScan() => _channel.invokeMethod('stopScan');

/// Establishes a connection to the Bluetooth Device.
/// Upon a successful connection, this method will return a [BluetoothDevice].
/// Returns a stream of [BluetoothDeviceState]
/// When [autoConnect] is true, the connection attempt will not time out.
/// To explicitly cancel a connection, call the cancelConnection() method.
/// To cancel connection to device, simply cancel() the stream subscription
/// NOTE: iOS will never time out the connection, Android may return GATT error 133 (or others).
Future<BluetoothDevice> connect(DeviceIdentifier deviceId, {bool autoConnect = true}) {
var options = protos.ConnectOptions.create()
..remoteId = deviceId.toString()
Stream<BluetoothDeviceState> connect(BluetoothDevice device, {bool autoConnect = true}) async* {
var request = protos.ConnectRequest.create()
..remoteId = device.id.toString()
..androidAutoConnect = autoConnect;
return _channel
.invokeMethod('connect', options.writeToBuffer())
StreamSubscription subscription;
final controller = new StreamController(onCancel: () {
_cancelConnection(device);
subscription.cancel();
});

await _channel
.invokeMethod('connect', request.writeToBuffer())
.then((List<int> data) => new protos.BluetoothDevice.fromBuffer(data))
.then((d) => new BluetoothDevice.fromProto(d));

subscription = device.onStateChanged().listen(
controller.add,
onError: controller.addError,
onDone: controller.close,
);

yield* controller.stream;
}

/// Cancels connection to the Bluetooth Device
Future<Null> cancelConnection(DeviceIdentifier device) {
return _channel.invokeMethod('disconnect', device.toString());
Future<Null> _cancelConnection(BluetoothDevice device) {
return _channel.invokeMethod('disconnect', device.id.toString());
}
}

Expand Down
2 changes: 1 addition & 1 deletion protos/flutterblue.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ message ScanResult {
int32 rssi = 3;
}

message ConnectOptions {
message ConnectRequest {
string remote_id = 1;
bool android_auto_connect = 2;
}
Expand Down

0 comments on commit 3788a1a

Please sign in to comment.