Skip to content
This repository has been archived by the owner on Aug 30, 2022. It is now read-only.

Commit

Permalink
Split suspendUntilConnectionState into specialized functions
Browse files Browse the repository at this point in the history
Having a function specific for suspension while waiting for connect and
disconnect allowed for more informative logging and more readable code.

For example, reaching a disconnected state is only a failure while
suspending until a connected state.
  • Loading branch information
twyatt committed Jun 3, 2020
1 parent 95d393c commit 69f540e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
27 changes: 24 additions & 3 deletions core/src/main/java/device/CoroutinesDevice.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@
package com.juul.able.device

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt.STATE_CONNECTED
import android.bluetooth.BluetoothGatt.GATT_SUCCESS
import android.bluetooth.BluetoothProfile.STATE_CONNECTED
import android.bluetooth.BluetoothProfile.STATE_DISCONNECTED
import android.content.Context
import android.os.RemoteException
import com.juul.able.Able
import com.juul.able.device.ConnectGattResult.Failure
import com.juul.able.device.ConnectGattResult.Success
import com.juul.able.gatt.ConnectionLost
import com.juul.able.gatt.CoroutinesGatt
import com.juul.able.gatt.GattCallback
import com.juul.able.gatt.suspendUntilConnectionState
import com.juul.able.gatt.GattConnection
import com.juul.able.gatt.GattErrorStatus
import com.juul.able.gatt.asGattConnectionStateString
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.newSingleThreadContext

private const val DISPATCHER_NAME = "Gatt"
Expand All @@ -33,7 +40,7 @@ internal class CoroutinesDevice(

return try {
val gatt = CoroutinesGatt(bluetoothGatt, dispatcher, callback)
gatt.suspendUntilConnectionState(STATE_CONNECTED)
gatt.suspendUntilConnected()
Success(gatt)
} catch (cancellation: CancellationException) {
Able.info { "connectGatt() canceled for $this" }
Expand All @@ -48,5 +55,19 @@ internal class CoroutinesDevice(
}
}

private suspend fun GattConnection.suspendUntilConnected() {
Able.debug { "Suspending until device $device is connected" }
onConnectionStateChange
.onEach { event ->
Able.verbose { "← Device $device received $event while waiting for connection" }
if (event.status != GATT_SUCCESS) throw GattErrorStatus(event)
if (event.newState == STATE_DISCONNECTED) throw ConnectionLost()
}
.first { (_, newState) -> newState == STATE_CONNECTED }
.also { (_, newState) ->
Able.info { "Device $device reached ${newState.asGattConnectionStateString()}" }
}
}

override fun toString(): String = "CoroutinesDevice(device=$device)"
}
24 changes: 23 additions & 1 deletion core/src/main/java/gatt/CoroutinesGatt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package com.juul.able.gatt

import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGatt.GATT_SUCCESS
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
Expand All @@ -17,6 +18,8 @@ import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.ExecutorCoroutineDispatcher
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
Expand All @@ -42,7 +45,7 @@ class CoroutinesGatt internal constructor(
try {
Able.info { "Disconnecting $this" }
bluetoothGatt.disconnect()
suspendUntilConnectionState(STATE_DISCONNECTED)
suspendUntilDisconnected()
} finally {
callback.close(bluetoothGatt)
}
Expand Down Expand Up @@ -128,5 +131,24 @@ class CoroutinesGatt internal constructor(
)
}

private suspend fun suspendUntilDisconnected() {
Able.debug { "Suspending until device ${bluetoothGatt.device} is disconnected" }
onConnectionStateChange
.onEach { event ->
Able.verbose {
val device = bluetoothGatt.device
"← Device $device received $event while waiting for disconnection"
}
if (event.status != GATT_SUCCESS) throw GattErrorStatus(event)
}
.first { (_, newState) -> newState == STATE_DISCONNECTED }
.also { (_, newState) ->
Able.info {
val state = newState.asGattConnectionStateString()
"Device ${bluetoothGatt.device} reached $state"
}
}
}

override fun toString(): String = "CoroutinesGatt(device=${bluetoothGatt.device})"
}
18 changes: 0 additions & 18 deletions core/src/main/java/gatt/GattConnection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ package com.juul.able.gatt

import android.bluetooth.BluetoothGatt.GATT_SUCCESS
import android.bluetooth.BluetoothProfile
import android.bluetooth.BluetoothProfile.STATE_DISCONNECTED
import com.juul.able.Able
import java.io.IOException
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach

/**
* Represents the possible GATT connection statuses as defined in the Android source code.
Expand Down Expand Up @@ -57,17 +53,3 @@ class ConnectionLost internal constructor(
message: String? = null,
cause: Throwable? = null
) : IOException(message, cause)

internal suspend fun GattConnection.suspendUntilConnectionState(state: GattConnectionState) {
Able.debug { "Suspending until ${state.asGattConnectionStateString()}" }
onConnectionStateChange
.onEach { event ->
Able.verbose { "← Received $event while waiting for ${state.asGattConnectionStateString()}" }
if (event.status != GATT_SUCCESS) throw GattErrorStatus(event)
if (event.newState == STATE_DISCONNECTED && state != STATE_DISCONNECTED) throw ConnectionLost()
}
.first { (_, newState) -> newState == state }
.also { (_, newState) ->
Able.info { "Reached ${newState.asGattConnectionStateString()}" }
}
}

0 comments on commit 69f540e

Please sign in to comment.