From d526d11d20c81a0ff4de81f96efdd55578825bca Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 4 Jun 2020 09:35:25 -0700 Subject: [PATCH] Fix #32 + // Note: To workaround https://issuetracker.google.com/issues/36995652 + // Always call BluetoothDevice#connectGatt() with autoConnect=false + // (the race condition does not affect that case). If that connection times out + // you will get a callback with status=133. Then call BluetoothGatt#connect() + // to initiate a background connection. --- .../mesh/service/RadioInterfaceService.kt | 7 ++-- .../geeksville/mesh/service/SafeBluetooth.kt | 35 +++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index 976564986..22194f60a 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -580,12 +580,15 @@ class RadioInterfaceService : Service(), Logging { } else { if (safe != null) { info("Closing radio interface service") + val s = safe + safe = + null // We do this first, because if we throw we still want to mark that we no longer have a valid connection + if (logSends) sentPacketsLog.close() if (logReceives) receivedPacketsLog.close() - safe?.close() - safe = null + s?.close() onDisconnect(isPermanent = true) // Tell any clients we are now offline } else { debug("Radio was not connected, skipping disable") diff --git a/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt b/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt index 23369cf43..cd6e6c16d 100644 --- a/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt +++ b/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt @@ -208,6 +208,12 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD it.invoke() } + // Note: To workaround https://issuetracker.google.com/issues/36995652 + // Always call BluetoothDevice#connectGatt() with autoConnect=false + // (the race condition does not affect that case). If that connection times out + // you will get a callback with status=133. Then call BluetoothGatt#connect() + // to initiate a background connection. + // Queue a new connection attempt val cb = connectionCallback if (cb != null) { @@ -457,21 +463,37 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD // see https://stackoverflow.com/questions/40156699/which-correct-flag-of-autoconnect-in-connectgatt-of-ble for // more info. // Otherwise if you pass in false, it will try to connect now and will timeout and fail in 30 seconds. - private fun queueConnect(autoConnect: Boolean = false, cont: Continuation) { + private fun queueConnect( + autoConnect: Boolean = false, + cont: Continuation, + isFirstAttempt: Boolean + ) { this.autoConnect = autoConnect // assert(gatt == null) this now might be !null with our new reconnect support queueWork("connect", cont) { + + // Note: To workaround https://issuetracker.google.com/issues/36995652 + // Always call BluetoothDevice#connectGatt() with autoConnect=false + // (the race condition does not affect that case). If that connection times out + // you will get a callback with status=133. Then call BluetoothGatt#connect() + // to initiate a background connection. + val autoNow = if (isFirstAttempt) false else autoConnect + val g = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { device.connectGatt( context, - autoConnect, + autoNow, gattCallback, BluetoothDevice.TRANSPORT_LE ) } else { - device.connectGatt(context, autoConnect, gattCallback) + device.connectGatt( + context, + autoNow, + gattCallback + ) } if (g != null) gatt = g @@ -501,17 +523,18 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD cb else null - queueConnect(autoConnect, CallbackContinuation(cb)) + queueConnect(autoConnect, CallbackContinuation(cb), true) } /// Restart any previous connect attempts private fun reconnect() { connectionCallback?.let { cb -> - queueConnect(true, CallbackContinuation(cb)) + queueConnect(true, CallbackContinuation(cb), false) } } - fun connect(autoConnect: Boolean = false) = makeSync { queueConnect(autoConnect, it) } + fun connect(autoConnect: Boolean = false) = + makeSync { queueConnect(autoConnect, it, true) } private fun queueReadCharacteristic( c: BluetoothGattCharacteristic,