From 771717224efa935e224ad976ba771bcdbf75b5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylwester=20Zieli=C5=84ski?= Date: Fri, 11 Feb 2022 14:27:12 +0100 Subject: [PATCH] Change HRS module --- .../nrftoolbox/viewmodel/HomeViewModel.kt | 8 +- .../android/csc/data/CSCServiceCommand.kt | 7 -- .../android/csc/repository/CSCManager.kt | 18 +--- .../android/hrs/data/HRSRepository.kt | 82 +++++++++++-------- .../android/hrs/data/HRSServiceCommand.kt | 3 - .../android/hrs/service/HRSManager.kt | 69 ++++++++++------ .../android/hrs/service/HRSService.kt | 22 ++--- .../nordicsemi/android/hrs/view/HRSScreen.kt | 28 +++++-- .../nordicsemi/android/hrs/view/HRSState.kt | 6 +- .../android/hrs/viewmodel/HRSViewModel.kt | 49 +++++------ 10 files changed, 160 insertions(+), 132 deletions(-) delete mode 100644 profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceCommand.kt delete mode 100644 profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSServiceCommand.kt diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/viewmodel/HomeViewModel.kt b/app/src/main/java/no/nordicsemi/android/nrftoolbox/viewmodel/HomeViewModel.kt index 5a3f9161..10a6c463 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/viewmodel/HomeViewModel.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import no.nordicsemi.android.cgms.data.CGMRepository import no.nordicsemi.android.csc.data.CSCRepository +import no.nordicsemi.android.hrs.data.HRSRepository import no.nordicsemi.android.navigation.NavigationManager import no.nordicsemi.android.nrftoolbox.ProfileDestination import no.nordicsemi.android.nrftoolbox.view.HomeViewState @@ -18,7 +19,8 @@ import javax.inject.Inject class HomeViewModel @Inject constructor( private val navigationManager: NavigationManager, cgmRepository: CGMRepository, - cscRepository: CSCRepository + cscRepository: CSCRepository, + hrsRepository: HRSRepository ) : ViewModel() { private val _state = MutableStateFlow(HomeViewState()) @@ -32,6 +34,10 @@ class HomeViewModel @Inject constructor( cscRepository.isRunning.onEach { _state.value = _state.value.copy(isCSCModuleRunning = it) }.launchIn(viewModelScope) + + hrsRepository.isRunning.onEach { + _state.value = _state.value.copy(isHRSModuleRunning = it) + }.launchIn(viewModelScope) } fun openProfile(destination: ProfileDestination) { diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceCommand.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceCommand.kt deleted file mode 100644 index f8dae6ed..00000000 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceCommand.kt +++ /dev/null @@ -1,7 +0,0 @@ -package no.nordicsemi.android.csc.data - -internal sealed class CSCServiceCommand - -internal data class SetWheelSizeCommand(val wheelSize: WheelSize) : CSCServiceCommand() - -internal object DisconnectCommand : CSCServiceCommand() diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCManager.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCManager.kt index 504cd402..3875f527 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCManager.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCManager.kt @@ -24,18 +24,14 @@ package no.nordicsemi.android.csc.repository import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import android.content.Context -import android.util.Log -import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch import no.nordicsemi.android.ble.BleManager import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelResponse import no.nordicsemi.android.ble.common.callback.csc.CyclingSpeedAndCadenceMeasurementResponse import no.nordicsemi.android.ble.ktx.asValidResponseFlow -import no.nordicsemi.android.ble.ktx.suspend import no.nordicsemi.android.csc.data.CSCData import no.nordicsemi.android.csc.data.WheelSize import no.nordicsemi.android.service.ConnectionObserverAdapter @@ -61,10 +57,6 @@ internal class CSCManager( private val data = MutableStateFlow(CSCData()) val dataHolder = ConnectionObserverAdapter() - private val exceptionHandler = CoroutineExceptionHandler { _, t -> - Log.e("COROUTINE-EXCEPTION", "Uncaught exception", t) - } - init { setConnectionObserver(dataHolder) @@ -107,18 +99,12 @@ internal class CSCManager( previousResponse = it }.launchIn(scope) - - scope.launch(exceptionHandler) { - enableNotifications(cscMeasurementCharacteristic).suspend() - } + enableNotifications(cscMeasurementCharacteristic).enqueue() setNotificationCallback(batteryLevelCharacteristic).asValidResponseFlow().onEach { data.value = data.value.copy(batteryLevel = it.batteryLevel) }.launchIn(scope) - - scope.launch { - enableNotifications(batteryLevelCharacteristic).suspend() - } + enableNotifications(batteryLevelCharacteristic).enqueue() } public override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean { diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSRepository.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSRepository.kt index 6f1c049c..d638d98b 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSRepository.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSRepository.kt @@ -1,52 +1,70 @@ package no.nordicsemi.android.hrs.data -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.* -import no.nordicsemi.android.service.BleManagerStatus +import android.bluetooth.BluetoothDevice +import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import no.nordicsemi.android.ble.ktx.suspend +import no.nordicsemi.android.hrs.service.HRSManager +import no.nordicsemi.android.hrs.service.HRSService +import no.nordicsemi.android.service.BleManagerResult +import no.nordicsemi.android.service.ConnectingResult +import no.nordicsemi.android.service.ServiceManager import javax.inject.Inject import javax.inject.Singleton @Singleton -internal class HRSRepository @Inject constructor() { +class HRSRepository @Inject constructor( + @ApplicationContext + private val context: Context, + private val serviceManager: ServiceManager, +) { + private var manager: HRSManager? = null - private val _data = MutableStateFlow(HRSData()) - val data: StateFlow = _data + private val _data = MutableStateFlow>(ConnectingResult()) + internal val data = _data.asStateFlow() - private val _command = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST) - val command = _command.asSharedFlow() + private val _isRunning = MutableStateFlow(false) + val isRunning = _isRunning.asStateFlow() - private val _status = MutableStateFlow(BleManagerStatus.CONNECTING) - val status = _status.asStateFlow() - - fun addNewHeartRate(heartRate: Int) { - val result = _data.value.heartRates.toMutableList().apply { - add(heartRate) - } - _data.tryEmit(_data.value.copy(heartRates = result)) + fun launch(device: BluetoothDevice) { + serviceManager.startService(HRSService::class.java, device) } - fun setSensorLocation(sensorLocation: Int) { - _data.tryEmit(_data.value.copy(sensorLocation = sensorLocation)) - } + fun start(device: BluetoothDevice, scope: CoroutineScope) { + val manager = HRSManager(context, scope) + this.manager = manager - fun setBatteryLevel(batteryLevel: Int) { - _data.tryEmit(_data.value.copy(batteryLevel = batteryLevel)) - } + manager.dataHolder.status.onEach { + _data.value = it + }.launchIn(scope) - fun sendDisconnectCommand() { - if (_command.subscriptionCount.value > 0) { - _command.tryEmit(DisconnectCommand) - } else { - _status.tryEmit(BleManagerStatus.DISCONNECTED) + scope.launch { + manager.start(device) } } - fun setNewStatus(status: BleManagerStatus) { - _status.value = status + private suspend fun HRSManager.start(device: BluetoothDevice) { + try { + connect(device) + .useAutoConnect(false) + .retry(3, 100) + .suspend() + _isRunning.value = true + } catch (e: Exception) { + e.printStackTrace() + } } - fun clear() { - _status.value = BleManagerStatus.CONNECTING - _data.tryEmit(HRSData()) + fun release() { + serviceManager.stopService(HRSService::class.java) + manager?.disconnect()?.enqueue() + manager = null + _isRunning.value = false } } diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSServiceCommand.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSServiceCommand.kt deleted file mode 100644 index 938371a8..00000000 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/data/HRSServiceCommand.kt +++ /dev/null @@ -1,3 +0,0 @@ -package no.nordicsemi.android.hrs.data - -internal object DisconnectCommand diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSManager.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSManager.kt index ba9b5284..0f15a10f 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSManager.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSManager.kt @@ -24,74 +24,95 @@ package no.nordicsemi.android.hrs.service import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import android.content.Context +import android.util.Log +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import no.nordicsemi.android.ble.BleManager +import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelResponse import no.nordicsemi.android.ble.common.callback.hr.BodySensorLocationResponse import no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementResponse import no.nordicsemi.android.ble.ktx.asValidResponseFlow -import no.nordicsemi.android.ble.ktx.suspend import no.nordicsemi.android.ble.ktx.suspendForValidResponse -import no.nordicsemi.android.hrs.data.HRSRepository -import no.nordicsemi.android.service.BatteryManager +import no.nordicsemi.android.hrs.data.HRSData +import no.nordicsemi.android.service.ConnectionObserverAdapter +import no.nordicsemi.android.utils.launchWithCatch import java.util.* val HRS_SERVICE_UUID: UUID = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb") private val BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID = UUID.fromString("00002A38-0000-1000-8000-00805f9b34fb") private val HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb") +private val BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb") +private val BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb") + internal class HRSManager( context: Context, - scope: CoroutineScope, - private val dataHolder: HRSRepository -) : BatteryManager(context, scope) { + private val scope: CoroutineScope, +) : BleManager(context) { + private var batteryLevelCharacteristic: BluetoothGattCharacteristic? = null private var heartRateCharacteristic: BluetoothGattCharacteristic? = null private var bodySensorLocationCharacteristic: BluetoothGattCharacteristic? = null - override fun onBatteryLevelChanged(batteryLevel: Int) { - dataHolder.setBatteryLevel(batteryLevel) + private val data = MutableStateFlow(HRSData()) + val dataHolder = ConnectionObserverAdapter() + + init { + setConnectionObserver(dataHolder) + + data.onEach { + dataHolder.setValue(it) + }.launchIn(scope) } - override fun getGattCallback(): BatteryManagerGattCallback { + override fun getGattCallback(): BleManagerGattCallback { return HeartRateManagerCallback() } - private inner class HeartRateManagerCallback : BatteryManagerGattCallback() { + private inner class HeartRateManagerCallback : BleManagerGattCallback() { override fun initialize() { super.initialize() - scope.launch { - val data = readCharacteristic(bodySensorLocationCharacteristic) + scope.launchWithCatch { + val readData = readCharacteristic(bodySensorLocationCharacteristic) .suspendForValidResponse() - dataHolder.setSensorLocation(data.sensorLocation) + data.value = data.value.copy(sensorLocation = readData.sensorLocation) } setNotificationCallback(heartRateCharacteristic).asValidResponseFlow() .onEach { - dataHolder.addNewHeartRate(it.heartRate) + val result = data.value.heartRates.toMutableList().apply { + add(it.heartRate) + } + data.tryEmit(data.value.copy(heartRates = result)) }.launchIn(scope) + enableNotifications(heartRateCharacteristic).enqueue() - scope.launch { - enableNotifications(heartRateCharacteristic).suspend() - } + setNotificationCallback(batteryLevelCharacteristic).asValidResponseFlow().onEach { + data.value = data.value.copy(batteryLevel = it.batteryLevel) + }.launchIn(scope) + enableNotifications(batteryLevelCharacteristic).enqueue() } override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean { - val service = gatt.getService(HRS_SERVICE_UUID) - if (service != null) { - heartRateCharacteristic = service.getCharacteristic(HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID) + gatt.getService(HRS_SERVICE_UUID)?.run { + heartRateCharacteristic = getCharacteristic(HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID) } - return heartRateCharacteristic != null + gatt.getService(BATTERY_SERVICE_UUID)?.run { + batteryLevelCharacteristic = getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID) + } + return heartRateCharacteristic != null && batteryLevelCharacteristic != null } override fun isOptionalServiceSupported(gatt: BluetoothGatt): Boolean { super.isOptionalServiceSupported(gatt) - val service = gatt.getService(HRS_SERVICE_UUID) - if (service != null) { - bodySensorLocationCharacteristic = service.getCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID) + gatt.getService(HRS_SERVICE_UUID)?.run { + bodySensorLocationCharacteristic = getCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID) } return bodySensorLocationCharacteristic != null } diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSService.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSService.kt index 504272df..3de42e08 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSService.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/service/HRSService.kt @@ -1,25 +1,27 @@ package no.nordicsemi.android.hrs.service +import android.bluetooth.BluetoothDevice +import android.content.Intent +import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach import no.nordicsemi.android.hrs.data.HRSRepository -import no.nordicsemi.android.service.ForegroundBleService +import no.nordicsemi.android.service.DEVICE_DATA +import no.nordicsemi.android.service.NotificationService import javax.inject.Inject @AndroidEntryPoint -internal class HRSService : ForegroundBleService() { +internal class HRSService : NotificationService() { @Inject lateinit var repository: HRSRepository - override val manager: HRSManager by lazy { HRSManager(this, scope, repository) } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + super.onStartCommand(intent, flags, startId) - override fun onCreate() { - super.onCreate() + val device = intent!!.getParcelableExtra(DEVICE_DATA)!! - repository.command.onEach { - stopSelf() - }.launchIn(scope) + repository.start(device, lifecycleScope) + + return START_REDELIVER_INTENT } } diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSScreen.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSScreen.kt index 042bd900..beedf2a7 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSScreen.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSScreen.kt @@ -4,14 +4,19 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import no.nordicsemi.android.hrs.R import no.nordicsemi.android.hrs.viewmodel.HRSViewModel +import no.nordicsemi.android.service.* import no.nordicsemi.android.theme.view.BackIconAppBar +import no.nordicsemi.android.theme.view.scanner.DeviceConnectingView +import no.nordicsemi.android.theme.view.scanner.DeviceDisconnectedView +import no.nordicsemi.android.theme.view.scanner.NoDeviceView +import no.nordicsemi.android.theme.view.scanner.Reason +import no.nordicsemi.android.utils.exhaustive @Composable fun HRSScreen() { @@ -19,15 +24,22 @@ fun HRSScreen() { val state = viewModel.state.collectAsState().value Column { - BackIconAppBar(stringResource(id = R.string.hrs_title)) { - viewModel.onEvent(DisconnectEvent) - } + val navigateUp = { viewModel.onEvent(NavigateUpEvent) } + + BackIconAppBar(stringResource(id = R.string.hrs_title), navigateUp) Column(modifier = Modifier.verticalScroll(rememberScrollState())) { -// when (state) { -// is DisplayDataState -> HRSContentView(state.data) { viewModel.onEvent(it) } -// LoadingState -> DeviceConnectingView() -// }.exhaustive + when (state) { + NoDeviceState -> NoDeviceView() + is WorkingState -> when (state.result) { + is ConnectingResult, + is ReadyResult -> DeviceConnectingView { viewModel.onEvent(DisconnectEvent) } + is DisconnectedResult -> DeviceDisconnectedView(Reason.USER, navigateUp) + is LinkLossResult -> DeviceDisconnectedView(Reason.LINK_LOSS, navigateUp) + is MissingServiceResult -> DeviceDisconnectedView(Reason.MISSING_SERVICE, navigateUp) + is SuccessResult -> HRSContentView(state.result.data) { viewModel.onEvent(it) } + } + }.exhaustive } } } diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSState.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSState.kt index 32f98b03..ec42ff89 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSState.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/view/HRSState.kt @@ -1,9 +1,9 @@ package no.nordicsemi.android.hrs.view import no.nordicsemi.android.hrs.data.HRSData +import no.nordicsemi.android.service.BleManagerResult internal sealed class HRSViewState -internal object LoadingState : HRSViewState() - -internal data class DisplayDataState(val data: HRSData) : HRSViewState() +internal data class WorkingState(val result: BleManagerResult) : HRSViewState() +internal object NoDeviceState : HRSViewState() diff --git a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/viewmodel/HRSViewModel.kt b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/viewmodel/HRSViewModel.kt index 58110b44..6a5ac14c 100644 --- a/profile_hrs/src/main/java/no/nordicsemi/android/hrs/viewmodel/HRSViewModel.kt +++ b/profile_hrs/src/main/java/no/nordicsemi/android/hrs/viewmodel/HRSViewModel.kt @@ -3,14 +3,14 @@ package no.nordicsemi.android.hrs.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import no.nordicsemi.android.hrs.data.HRSRepository -import no.nordicsemi.android.hrs.service.HRSService import no.nordicsemi.android.hrs.service.HRS_SERVICE_UUID import no.nordicsemi.android.hrs.view.* import no.nordicsemi.android.navigation.* -import no.nordicsemi.android.service.BleManagerStatus -import no.nordicsemi.android.service.ServiceManager import no.nordicsemi.android.utils.exhaustive import no.nordicsemi.android.utils.getDevice import no.nordicsemi.ui.scanner.ScannerDestinationId @@ -19,19 +19,23 @@ import javax.inject.Inject @HiltViewModel internal class HRSViewModel @Inject constructor( private val repository: HRSRepository, - private val serviceManager: ServiceManager, private val navigationManager: NavigationManager ) : ViewModel() { - val state = repository.data.combine(repository.status) { data, status -> -// when (status) { -// BleManagerStatus.CONNECTING -> LoadingState -// BleManagerStatus.OK, -// BleManagerStatus.DISCONNECTED -> DisplayDataState(data) -// } - }.stateIn(viewModelScope, SharingStarted.Lazily, LoadingState) + private val _state = MutableStateFlow(NoDeviceState) + val state = _state.asStateFlow() init { + if (!repository.isRunning.value) { + requestBluetoothDevice() + } + + repository.data.onEach { + _state.value = WorkingState(it) + }.launchIn(viewModelScope) + } + + private fun requestBluetoothDevice() { navigationManager.navigateTo(ScannerDestinationId, UUIDArgument(HRS_SERVICE_UUID)) navigationManager.recentResult.onEach { @@ -39,35 +43,24 @@ internal class HRSViewModel @Inject constructor( handleArgs(it) } }.launchIn(viewModelScope) - - repository.status.onEach { - if (it == BleManagerStatus.DISCONNECTED) { - navigationManager.navigateUp() - } - }.launchIn(viewModelScope) } private fun handleArgs(args: DestinationResult) { when (args) { is CancelDestinationResult -> navigationManager.navigateUp() - is SuccessDestinationResult -> serviceManager.startService(HRSService::class.java, args.getDevice()) + is SuccessDestinationResult -> repository.launch(args.getDevice().device) }.exhaustive } fun onEvent(event: HRSScreenViewEvent) { when (event) { - DisconnectEvent -> onDisconnectButtonClick() + DisconnectEvent -> disconnect() NavigateUpEvent -> navigationManager.navigateUp() }.exhaustive } - private fun onDisconnectButtonClick() { - repository.sendDisconnectCommand() - repository.clear() - } - - override fun onCleared() { - super.onCleared() - repository.clear() + private fun disconnect() { + repository.release() + navigationManager.navigateUp() } }