disconnect method
Cancels connection to the Bluetooth Device
queue
If true, this disconnect request will be executed after all other operations complete. If false, this disconnect request will be executed right now, i.e. skipping to the front of the fbp operation queue, which is useful to cancel an in-progress connection attempt.androidDelay
Android only. Minimum gap in milliseconds between connect and disconnect to workaround a race condition that leaves connection stranded. A stranded connection in this case refers to a connection that FBP and Android Bluetooth stack are not aware of and thus cannot be disconnected because there is no gatt handle. https://issuetracker.google.com/issues/37121040 From testing, 2 second delay appears to be enough.
Implementation
Future<void> disconnect({
int timeout = 35,
bool queue = true,
int androidDelay = 2000,
}) async {
// Only allow a single disconnect operation at a time
_Mutex dtx = _MutexFactory.getMutexForKey("disconnect");
await dtx.take();
// Only allow a single ble operation to be underway at a time?
_Mutex mtx = _MutexFactory.getMutexForKey("global");
if (queue) {
await mtx.take();
}
try {
// remove from auto connect list if there
FlutterBluePlus._autoConnect.remove(remoteId);
var responseStream = FlutterBluePlus._methodStream.stream
.where((m) => m.method == "OnConnectionStateChanged")
.map((m) => m.arguments)
.map((args) => BmConnectionStateResponse.fromMap(args))
.where((p) => p.remoteId == remoteId)
.where((p) => p.connectionState == BmConnectionStateEnum.disconnected);
// Start listening now, before invokeMethod, to ensure we don't miss the response
Future<BmConnectionStateResponse> futureState = responseStream.first;
// Workaround Android race condition
await _ensureAndroidDisconnectionDelay(androidDelay);
// invoke
bool changed = await FlutterBluePlus._invokeMethod('disconnect', remoteId.str);
// only wait for disconnection if weren't already disconnected
if (changed) {
await futureState.fbpEnsureAdapterIsOn("disconnect").fbpTimeout(timeout, "disconnect");
}
if (Platform.isAndroid) {
// Disconnected, remove connect timestamp
FlutterBluePlus._connectTimestamp.remove(remoteId);
}
} finally {
dtx.give();
if (queue) {
mtx.give();
}
}
}