Fix bug GATT_FAILURE
This commit is contained in:
parent
ce95316494
commit
0d7019a7be
|
|
@ -37,6 +37,7 @@ import kotlin.random.nextInt
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
|
||||
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
||||
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
||||
|
|
@ -73,7 +74,7 @@ fun TemperatureHistory(
|
|||
viewModel.setEvent(TemperatureHistoryContract.Event.LoadHistory(ble.serial))
|
||||
}
|
||||
|
||||
Column() {
|
||||
Column {
|
||||
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
|
|
@ -90,7 +91,10 @@ fun TemperatureHistory(
|
|||
onClick = {
|
||||
viewModel.setEvent(TemperatureHistoryContract.Event.LoadHistory(ble.serial))
|
||||
},
|
||||
enabled = state.loadingHistoryState is ProgressState.Finished
|
||||
enabled = when(state){
|
||||
is TemperatureHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished
|
||||
TemperatureHistoryContract.State.Exception -> true
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Refresh,
|
||||
|
|
@ -102,71 +106,67 @@ fun TemperatureHistory(
|
|||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
when (state.loadingHistoryState) {
|
||||
is ProgressState.Finished -> {
|
||||
when(state){
|
||||
is TemperatureHistoryContract.State.Display -> Display(state = state)
|
||||
TemperatureHistoryContract.State.Exception -> Exception()
|
||||
}
|
||||
|
||||
Text(text = "${state.loadingHistoryState.data.size}")
|
||||
}
|
||||
|
||||
val producer = state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
||||
TemperatureEntry(measurePoint.date, index.toFloat(), measurePoint.value) }.let {
|
||||
ChartEntryModelProducer(it)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Display(
|
||||
state: TemperatureHistoryContract.State.Display
|
||||
) {
|
||||
when (state.loadingHistoryState) {
|
||||
is ProgressState.Finished -> {
|
||||
|
||||
Text(text = "${state.loadingHistoryState.data.size}")
|
||||
|
||||
val producer = state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
||||
TemperatureEntry(measurePoint.date, index.toFloat(), measurePoint.value) }.let {
|
||||
ChartEntryModelProducer(it)
|
||||
}
|
||||
|
||||
val axisValueFormatter = AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
||||
(chartValues.chartEntryModel.entries.first().getOrNull(value.toInt()) as? TemperatureEntry)
|
||||
?.localDate
|
||||
?.let { formatter.format(Date(it)) }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
val lineChart = lineChart(
|
||||
spacing = 110.dp
|
||||
)
|
||||
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
val scrollState = rememberChartScrollState()
|
||||
|
||||
LaunchedEffect(scrollState.maxValue){
|
||||
scrollState.scrollBy(scrollState.maxValue)
|
||||
}
|
||||
|
||||
val axisValueFormatter = AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
||||
(chartValues.chartEntryModel.entries.first().getOrNull(value.toInt()) as? TemperatureEntry)
|
||||
?.localDate
|
||||
?.let { formatter.format(Date(it)) }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
val lineChart = lineChart(
|
||||
spacing = 110.dp
|
||||
Chart(
|
||||
chartScrollState = scrollState,
|
||||
chart = lineChart,
|
||||
chartModelProducer = producer,
|
||||
startAxis = startAxis(),
|
||||
bottomAxis = bottomAxis(
|
||||
valueFormatter = axisValueFormatter,
|
||||
labelRotationDegrees = 0f,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1.5f),
|
||||
)
|
||||
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
val scrollState = rememberChartScrollState()
|
||||
|
||||
LaunchedEffect(scrollState.maxValue){
|
||||
scrollState.scrollBy(scrollState.maxValue)
|
||||
}
|
||||
|
||||
Chart(
|
||||
chartScrollState = scrollState,
|
||||
chart = lineChart,
|
||||
chartModelProducer = producer,
|
||||
startAxis = startAxis(),
|
||||
bottomAxis = bottomAxis(
|
||||
valueFormatter = axisValueFormatter,
|
||||
labelRotationDegrees = 0f,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1.5f),
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
is ProgressState.Indeterminate -> {
|
||||
}
|
||||
is ProgressState.Indeterminate -> {
|
||||
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(2f),
|
||||
){
|
||||
|
||||
CircularProgressIndicator(
|
||||
strokeCap = StrokeCap.Round,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
is ProgressState.Progress -> Box(modifier = Modifier.padding(8.dp)) {
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
|
@ -174,15 +174,8 @@ fun TemperatureHistory(
|
|||
.aspectRatio(2f),
|
||||
){
|
||||
|
||||
val progressAnimDuration = 1500
|
||||
val progressAnimation by animateFloatAsState(
|
||||
targetValue = state.loadingHistoryState.value,
|
||||
animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing)
|
||||
)
|
||||
|
||||
CircularProgressIndicator(
|
||||
strokeCap = StrokeCap.Round,
|
||||
progress = progressAnimation,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
|
||||
|
|
@ -190,6 +183,48 @@ fun TemperatureHistory(
|
|||
|
||||
}
|
||||
}
|
||||
is ProgressState.Progress -> Box(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(2f),
|
||||
){
|
||||
|
||||
val progressAnimDuration = 1500
|
||||
val progressAnimation by animateFloatAsState(
|
||||
targetValue = state.loadingHistoryState.value,
|
||||
animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing)
|
||||
)
|
||||
|
||||
CircularProgressIndicator(
|
||||
strokeCap = StrokeCap.Round,
|
||||
progress = progressAnimation,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Exception(
|
||||
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(2f),
|
||||
){
|
||||
|
||||
Text(
|
||||
textAlign = TextAlign.Center,
|
||||
text = "Во время загрузки произошла ошибка",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -205,9 +240,15 @@ class TemperatureHistoryContract {
|
|||
|
||||
}
|
||||
|
||||
class State(
|
||||
val loadingHistoryState : ProgressState<List<Ble.Thermometer.MeasurePoint>>
|
||||
) : ViewState
|
||||
sealed class State : ViewState {
|
||||
|
||||
data class Display(
|
||||
val loadingHistoryState : ProgressState<List<Ble.Thermometer.MeasurePoint>>
|
||||
) : State()
|
||||
|
||||
object Exception : State()
|
||||
|
||||
}
|
||||
|
||||
sealed class Effect : ViewSideEffect {
|
||||
|
||||
|
|
@ -222,7 +263,7 @@ class TemperatureHistoryViewModel @Inject constructor(
|
|||
private val getTemperatureHistoryBySerial: GetTemperatureHistoryBySerial
|
||||
) : BaseViewModel<TemperatureHistoryContract.State, TemperatureHistoryContract.Event, TemperatureHistoryContract.Effect>() {
|
||||
|
||||
override fun setInitialState() = TemperatureHistoryContract.State(
|
||||
override fun setInitialState() = TemperatureHistoryContract.State.Display(
|
||||
ProgressState.Indeterminate
|
||||
)
|
||||
|
||||
|
|
@ -239,18 +280,20 @@ class TemperatureHistoryViewModel @Inject constructor(
|
|||
viewModelScope.launch {
|
||||
|
||||
setState {
|
||||
TemperatureHistoryContract.State(ProgressState.Indeterminate)
|
||||
TemperatureHistoryContract.State.Display(ProgressState.Indeterminate)
|
||||
}
|
||||
|
||||
getTemperatureHistoryBySerial(event.serial).onEach {
|
||||
it.fold(
|
||||
onSuccess = {
|
||||
setState {
|
||||
TemperatureHistoryContract.State(it)
|
||||
TemperatureHistoryContract.State.Display(it)
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
|
||||
setState {
|
||||
TemperatureHistoryContract.State.Exception
|
||||
}
|
||||
}
|
||||
)
|
||||
}.launchIn(this)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ import android.Manifest
|
|||
import android.app.Application
|
||||
import android.bluetooth.*
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
|
|
@ -25,6 +27,7 @@ import java.util.*
|
|||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@Singleton
|
||||
class BleRepositoryImpl @Inject constructor(
|
||||
|
|
@ -316,7 +319,15 @@ class BleRepositoryImpl @Inject constructor(
|
|||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
||||
(this[idx].toUInt() and 0xFFu)
|
||||
|
||||
deviceCache[serial]?.device?.let { device ->
|
||||
findDeviceBySerial(serial).fold(
|
||||
onSuccess = {
|
||||
return@fold it
|
||||
},
|
||||
onFailure = {
|
||||
emit(Result.failure(it))
|
||||
return@flow
|
||||
}
|
||||
).let { device ->
|
||||
|
||||
emit(Result.success(ProgressState.Indeterminate))
|
||||
|
||||
|
|
@ -330,7 +341,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
val countDataArray = readCharacteristic(
|
||||
device = device,
|
||||
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb")
|
||||
).fold(
|
||||
onFailure = {
|
||||
emit(Result.failure(it))
|
||||
|
|
@ -355,7 +366,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
val firstPackageResponse = readCharacteristic(
|
||||
device = device,
|
||||
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb")
|
||||
).fold(
|
||||
onFailure = {
|
||||
emit(Result.failure(it))
|
||||
|
|
@ -397,7 +408,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
val readResponse = readCharacteristic(
|
||||
device = device,
|
||||
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb")
|
||||
).fold(
|
||||
onFailure = {
|
||||
emit(Result.failure(it))
|
||||
|
|
@ -406,20 +417,34 @@ class BleRepositoryImpl @Inject constructor(
|
|||
onSuccess = { return@fold it }
|
||||
)
|
||||
|
||||
dataCount = readResponse[1].toUByte()
|
||||
if(readResponse[0] == 251.toByte()) {
|
||||
|
||||
temperatureDataArray = readResponse.toList().subList(2, readResponse.size)
|
||||
dataCount = readResponse[1].toUByte()
|
||||
|
||||
temperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
(it[0] + it[1] * 256).toFloat() / 100f
|
||||
}
|
||||
)
|
||||
temperatureDataArray = readResponse.toList().subList(2, readResponse.size)
|
||||
|
||||
emit(Result.success(ProgressState.Progress(totalDataSize.toFloat() / temperaturePackage.size.toFloat())))
|
||||
temperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
(it[0] + it[1] * 256).toFloat() / 100f
|
||||
}
|
||||
)
|
||||
|
||||
emit(Result.success(ProgressState.Progress(totalDataSize.toFloat() / temperaturePackage.size.toFloat())))
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
readCharacteristic(
|
||||
device = device,
|
||||
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
|
||||
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb")
|
||||
)
|
||||
|
||||
emit(
|
||||
Result.success(
|
||||
ProgressState.Finished(
|
||||
|
|
@ -433,6 +458,10 @@ class BleRepositoryImpl @Inject constructor(
|
|||
)
|
||||
)
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -559,14 +588,19 @@ class BleRepositoryImpl @Inject constructor(
|
|||
characteristicId: UUID
|
||||
): Result<ByteArray, BleException> = suspendCancellableCoroutine {
|
||||
|
||||
var result: ByteArray? = null
|
||||
var bleGatt: BluetoothGatt? = null
|
||||
|
||||
val callback = object : BluetoothGattCallback() {
|
||||
|
||||
override fun onConnectionStateChange(
|
||||
gatt: BluetoothGatt?,
|
||||
gatt: BluetoothGatt,
|
||||
status: Int,
|
||||
newState: Int
|
||||
) {
|
||||
|
||||
Log.d("read", "onConnectionStateChange $newState $status")
|
||||
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(
|
||||
|
|
@ -574,7 +608,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
gatt?.discoverServices()
|
||||
gatt.discoverServices()
|
||||
} else {
|
||||
it.resume(Result.failure(BleException.PermissionDenied))
|
||||
}
|
||||
|
|
@ -584,14 +618,16 @@ class BleRepositoryImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onServicesDiscovered(
|
||||
gatt: BluetoothGatt?,
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
|
||||
Log.d("read", "onServicesDiscovered $status")
|
||||
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
|
||||
gatt?.services?.firstOrNull { service ->
|
||||
gatt.services?.firstOrNull { service ->
|
||||
service.uuid == serviceId
|
||||
}?.characteristics?.firstOrNull { characteristic ->
|
||||
characteristic.uuid == characteristicId
|
||||
|
|
@ -620,6 +656,9 @@ class BleRepositoryImpl @Inject constructor(
|
|||
status: Int
|
||||
) {
|
||||
super.onCharacteristicRead(gatt, characteristic, value, status)
|
||||
|
||||
Log.d("read", "onCharacteristicRead $status")
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
app,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
|
|
@ -627,9 +666,17 @@ class BleRepositoryImpl @Inject constructor(
|
|||
) {
|
||||
it.resume(Result.failure(BleException.PermissionDenied))
|
||||
}else {
|
||||
gatt.disconnect()
|
||||
it.resume(Result.success(value))
|
||||
gatt.close()
|
||||
result = value
|
||||
if(result != null){
|
||||
it.resume(Result.success(result!!))
|
||||
} else {
|
||||
bleGatt?.close()
|
||||
it.resume(Result.failure(BleException.UnexpectedResponse))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -641,7 +688,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
) {
|
||||
it.resume(Result.failure(BleException.PermissionDenied))
|
||||
} else {
|
||||
device.connectGatt(app, true, callback)
|
||||
bleGatt = device.connectGatt(app, true, callback)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -653,14 +700,18 @@ class BleRepositoryImpl @Inject constructor(
|
|||
writeData: ByteArray
|
||||
) = suspendCancellableCoroutine {
|
||||
|
||||
var bleGatt: BluetoothGatt? = null
|
||||
|
||||
val callback = object : BluetoothGattCallback() {
|
||||
|
||||
override fun onConnectionStateChange(
|
||||
gatt: BluetoothGatt?,
|
||||
gatt: BluetoothGatt,
|
||||
status: Int,
|
||||
newState: Int
|
||||
) {
|
||||
|
||||
Log.d("write", "onConnectionStateChange $newState")
|
||||
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(
|
||||
|
|
@ -668,7 +719,13 @@ class BleRepositoryImpl @Inject constructor(
|
|||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
gatt?.discoverServices()
|
||||
gatt.discoverServices()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if(newState == BluetoothProfile.STATE_DISCONNECTED && status == BluetoothGatt.GATT_FAILURE){
|
||||
bleGatt?.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -676,14 +733,14 @@ class BleRepositoryImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onServicesDiscovered(
|
||||
gatt: BluetoothGatt?,
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
|
||||
Log.d("write", "onServicesDiscovered $status")
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
|
||||
gatt?.services?.firstOrNull { service ->
|
||||
gatt.services?.firstOrNull { service ->
|
||||
service.uuid == serviceId
|
||||
}?.characteristics?.firstOrNull { characteristic ->
|
||||
characteristic.uuid == characteristicId
|
||||
|
|
@ -712,10 +769,13 @@ class BleRepositoryImpl @Inject constructor(
|
|||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic?,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int
|
||||
) {
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
Log.d("write", "onCharacteristicWrite $status")
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
app,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
|
|
@ -723,7 +783,7 @@ class BleRepositoryImpl @Inject constructor(
|
|||
) {
|
||||
return
|
||||
} else {
|
||||
gatt.disconnect()
|
||||
gatt.close()
|
||||
it.resume(Unit)
|
||||
}
|
||||
|
||||
|
|
@ -731,7 +791,63 @@ class BleRepositoryImpl @Inject constructor(
|
|||
|
||||
}
|
||||
|
||||
device.connectGatt(app, true, callback)
|
||||
bleGatt = device.connectGatt(app, true, callback)
|
||||
|
||||
}
|
||||
|
||||
private suspend fun findDeviceBySerial(serial: String): Result<BluetoothDevice, BleException> = suspendCancellableCoroutine {
|
||||
|
||||
val bleCallback = object : ScanCallback() {
|
||||
|
||||
override fun onScanResult(
|
||||
callbackType: Int,
|
||||
result: ScanResult
|
||||
) {
|
||||
|
||||
super.onScanResult(callbackType, result)
|
||||
|
||||
if(it.isActive) {
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
app,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
|
||||
it.resume(Result.success(result.device))
|
||||
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
it.resume(
|
||||
Result.failure(BleException.PermissionDenied)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val bleScanner =
|
||||
app.getSystemService(BluetoothManager::class.java).adapter.bluetoothLeScanner
|
||||
|
||||
bleScanner.startScan(
|
||||
listOf(ScanFilter.Builder().setDeviceAddress(serial).build()),
|
||||
ScanSettings.Builder()
|
||||
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||
.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
|
||||
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
|
||||
.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
|
||||
.setReportDelay(400L)
|
||||
.build(),
|
||||
bleCallback)
|
||||
|
||||
it.invokeOnCancellation {
|
||||
bleScanner.stopScan(bleCallback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@ sealed class BleException {
|
|||
|
||||
object PermissionDenied : BleException()
|
||||
|
||||
object UnexpectedResponse : BleException()
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue