fix(devices): preserve connection and transport on launch timeout for native reconnect (#20777)
Merged
DR
2d ago+201+201+012345678901234567890123456789-4-4-0123456789
Summary
Resolves #20777.
Problem
At app launch, DeviceService.ensureConnection makes an initial connection attempt to the saved pendant. If the pendant is out of range or powered off for 60 seconds:
NativeBleTransport.connect()times out and rethrowsTimeoutException.DeviceConnection.connect()wraps this inDeviceConnectionException.- In
DeviceService._connectToDevice, the catch block was tearing down the connection unconditionally (disconnect(),transport.dispose(), and removing from_connections). - Disposing the transport calls
BleBridge.instance.unregisterPeripheral(), which removes_deviceReadyCallbacks. - When the user later brings the pendant in range or powers it on, native BLE reconnects and emits
onDeviceReady, but finds no Dart callback. The app stays permanently disconnected and never captures audio until manual user reconnection or relaunch.
Solution
DeviceConnectionException(device_connection.dart):- Added
DeviceConnectionTimeoutExceptionandisTimeoutproperty to distinguish timeout errors from failed device-specific initialization. - Wrapped
TimeoutExceptioninDeviceConnectionTimeoutExceptionduringDeviceConnection.connect().
- Added
DeviceService._connectToDevice(devices.dart):- Guarded the teardown path (
disconnect(),transport.dispose(), and cache removal) whenisTimeoutis true. - Preserves the cached connection and registered
NativeBleTransportso native background auto-reconnection persists and routes late readiness events back into Dart. - Non-timeout failures (such as a broken GATT link or failed device initialization) continue to tear down partial links as before.
- Guarded the teardown path (
- Tests:
- Extended
app/test/services/device_service_connection_failure_test.dartto verify that launch timeouts preserve the connection and transport, while initialization errors still tear down. - Added hermetic regression test
app/test/services/devices/saved_pendant_launch_timeout_reconnect_test.dartdriving realDeviceService,FriendPendantDeviceConnection,NativeBleTransport, andBleBridgewithfake_asyncadvancing the 60s timeout, proving the transport stays registered and reconnects intoDeviceConnectionState.connectedon subsequentonDeviceReady.
- Extended