From 488104c3d5f0691f3c2e9190c31d5208c72fb030 Mon Sep 17 00:00:00 2001 From: Sylwester Zielinski Date: Mon, 20 Mar 2023 13:43:49 +0100 Subject: [PATCH] Fix CSC profile --- .../android/csc/data/CSCServiceData.kt | 6 ++- .../android/csc/{view => data}/SpeedUnit.kt | 2 +- .../android/csc/repository/CSCRepository.kt | 9 ++++ .../android/csc/repository/CSCService.kt | 6 ++- .../android/csc/view/CSCContentView.kt | 9 ++-- .../nordicsemi/android/csc/view/CSCMappers.kt | 1 + .../nordicsemi/android/csc/view/CSCScreen.kt | 12 +++-- .../nordicsemi/android/csc/view/CSCState.kt | 46 ------------------- .../android/csc/view/CSCViewEvent.kt | 1 + .../android/csc/view/SensorsReadingView.kt | 1 + .../android/csc/viewmodel/CSCViewModel.kt | 14 ++---- 11 files changed, 36 insertions(+), 71 deletions(-) rename profile_csc/src/main/java/no/nordicsemi/android/csc/{view => data}/SpeedUnit.kt (97%) delete mode 100644 profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCState.kt diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceData.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceData.kt index d0a4af36..635fb318 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceData.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/data/CSCServiceData.kt @@ -3,8 +3,10 @@ package no.nordicsemi.android.csc.data import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.profile.csc.data.CSCData -data class CSCServiceData( +internal data class CSCServiceData( val data: CSCData = CSCData(), val batteryLevel: Int? = null, - val connectionState: GattConnectionState? = null + val connectionState: GattConnectionState? = null, + val speedUnit: SpeedUnit = SpeedUnit.M_S, + val deviceName: String? = null ) diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SpeedUnit.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/data/SpeedUnit.kt similarity index 97% rename from profile_csc/src/main/java/no/nordicsemi/android/csc/view/SpeedUnit.kt rename to profile_csc/src/main/java/no/nordicsemi/android/csc/data/SpeedUnit.kt index fe083614..0ebea419 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SpeedUnit.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/data/SpeedUnit.kt @@ -29,7 +29,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package no.nordicsemi.android.csc.view +package no.nordicsemi.android.csc.data internal enum class SpeedUnit(val displayName: String) { M_S("m/s"), diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCRepository.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCRepository.kt index a149395c..db1507b5 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCRepository.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCRepository.kt @@ -40,6 +40,7 @@ import kotlinx.coroutines.flow.map import no.nordicsemi.android.common.core.simpleSharedFlow import no.nordicsemi.android.common.logger.NordicLogger import no.nordicsemi.android.csc.data.CSCServiceData +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.profile.csc.data.CSCData @@ -73,6 +74,14 @@ class CSCRepository @Inject constructor( serviceManager.startService(CSCService::class.java, device) } + fun onInitComplete(device: ServerDevice) { + _data.value = _data.value.copy(deviceName = device.name) + } + + internal fun setSpeedUnit(speedUnit: SpeedUnit) { + _data.value = _data.value.copy(speedUnit = speedUnit) + } + fun setWheelSize(wheelSize: WheelSize) { _wheelSize.value = wheelSize } diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCService.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCService.kt index f9d0f303..181abbd0 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCService.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/repository/CSCService.kt @@ -91,11 +91,11 @@ internal class CSCService : NotificationService() { client.services .filterNotNull() - .onEach { configureGatt(it) } + .onEach { configureGatt(it, device) } .launchIn(lifecycleScope) } - private suspend fun configureGatt(services: BleGattServices) { + private suspend fun configureGatt(services: BleGattServices, device: ServerDevice) { val cscService = services.findService(CSC_SERVICE_UUID)!! val cscMeasurementCharacteristic = cscService.findCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID)!! val batteryService = services.findService(BATTERY_SERVICE_UUID)!! @@ -111,6 +111,8 @@ internal class CSCService : NotificationService() { .mapNotNull { cscDataParser.parse(it, repository.wheelSize.value) } .onEach { repository.onCSCDataChanged(it) } .launchIn(lifecycleScope) + + repository.onInitComplete(device) } private fun stopIfDisconnected(connectionState: GattConnectionState) { diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCContentView.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCContentView.kt index a970e2f8..2140926a 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCContentView.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCContentView.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.unit.dp import no.nordicsemi.android.common.theme.view.RadioButtonGroup import no.nordicsemi.android.csc.R import no.nordicsemi.android.csc.data.CSCServiceData +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.kotlin.ble.profile.csc.data.CSCData import no.nordicsemi.android.kotlin.ble.profile.csc.data.WheelSize import no.nordicsemi.android.ui.view.ScreenSection @@ -58,7 +59,7 @@ import no.nordicsemi.android.ui.view.dialog.FlowCanceled import no.nordicsemi.android.ui.view.dialog.ItemSelectedResult @Composable -internal fun CSCContentView(state: CSCServiceData, speedUnit: SpeedUnit, onEvent: (CSCViewEvent) -> Unit) { +internal fun CSCContentView(state: CSCServiceData, onEvent: (CSCViewEvent) -> Unit) { val showDialog = rememberSaveable { mutableStateOf(false) } if (showDialog.value) { @@ -79,11 +80,11 @@ internal fun CSCContentView(state: CSCServiceData, speedUnit: SpeedUnit, onEvent Column( horizontalAlignment = Alignment.CenterHorizontally, ) { - SettingsSection(state.data, speedUnit, onEvent) { showDialog.value = true } + SettingsSection(state.data, state.speedUnit, onEvent) { showDialog.value = true } Spacer(modifier = Modifier.height(16.dp)) - SensorsReadingView(state = state, speedUnit) + SensorsReadingView(state = state, state.speedUnit) Spacer(modifier = Modifier.height(16.dp)) @@ -125,5 +126,5 @@ private fun SettingsSection( @Preview @Composable private fun ConnectedPreview() { - CSCContentView(CSCServiceData(), SpeedUnit.KM_H) { } + CSCContentView(CSCServiceData()) { } } diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCMappers.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCMappers.kt index 660972c4..e60e3f30 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCMappers.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCMappers.kt @@ -33,6 +33,7 @@ package no.nordicsemi.android.csc.view import no.nordicsemi.android.common.theme.view.RadioButtonItem import no.nordicsemi.android.common.theme.view.RadioGroupViewEntity +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.kotlin.ble.profile.csc.data.CSCData import java.util.* diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCScreen.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCScreen.kt index 003d895b..692ba72d 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCScreen.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCScreen.kt @@ -47,6 +47,7 @@ import no.nordicsemi.android.common.ui.scanner.view.DeviceConnectingView import no.nordicsemi.android.common.ui.scanner.view.DeviceDisconnectedView import no.nordicsemi.android.common.ui.scanner.view.Reason import no.nordicsemi.android.csc.R +import no.nordicsemi.android.csc.data.CSCServiceData import no.nordicsemi.android.csc.viewmodel.CSCViewModel import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.ui.view.BackIconAppBar @@ -70,14 +71,15 @@ fun CSCScreen() { .padding(16.dp) .verticalScroll(rememberScrollState()) ) { - when (state.cscManagerState) { - NoDeviceState -> DeviceConnectingView() - is WorkingState -> when (state.cscManagerState.result.connectionState) { + if (state.deviceName == null) { + DeviceConnectingView() + } else { + when (state.connectionState) { null, GattConnectionState.STATE_CONNECTING -> DeviceConnectingView { NavigateUpButton(navigateUp) } GattConnectionState.STATE_DISCONNECTED, GattConnectionState.STATE_DISCONNECTING -> DeviceDisconnectedView(Reason.UNKNOWN) { NavigateUpButton(navigateUp) } - GattConnectionState.STATE_CONNECTED -> CSCContentView(state.cscManagerState.result, state.speedUnit) { viewModel.onEvent(it) } + GattConnectionState.STATE_CONNECTED -> CSCContentView(state) { viewModel.onEvent(it) } } } } @@ -85,7 +87,7 @@ fun CSCScreen() { } @Composable -private fun AppBar(state: CSCViewState, navigateUp: () -> Unit, viewModel: CSCViewModel) { +private fun AppBar(state: CSCServiceData, navigateUp: () -> Unit, viewModel: CSCViewModel) { if (state.deviceName?.isNotBlank() == true) { LoggerIconAppBar(state.deviceName, navigateUp, { viewModel.onEvent(OnDisconnectButtonClick) }) { viewModel.onEvent(OpenLogger) diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCState.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCState.kt deleted file mode 100644 index c5638323..00000000 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCState.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022, Nordic Semiconductor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package no.nordicsemi.android.csc.view - -import no.nordicsemi.android.csc.data.CSCServiceData - -internal data class CSCViewState( - val speedUnit: SpeedUnit = SpeedUnit.M_S, - val cscManagerState: CSCMangerState = NoDeviceState, - val deviceName: String? = null -) - -internal sealed class CSCMangerState - -internal data class WorkingState(val result: CSCServiceData) : CSCMangerState() - -internal object NoDeviceState : CSCMangerState() diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCViewEvent.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCViewEvent.kt index 87f510db..d48b4e7e 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCViewEvent.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/CSCViewEvent.kt @@ -31,6 +31,7 @@ package no.nordicsemi.android.csc.view +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.kotlin.ble.profile.csc.data.WheelSize internal sealed class CSCViewEvent diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SensorsReadingView.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SensorsReadingView.kt index 10cbbd5c..3bbba565 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SensorsReadingView.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/view/SensorsReadingView.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import no.nordicsemi.android.csc.R import no.nordicsemi.android.csc.data.CSCServiceData +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.ui.view.BatteryLevelView import no.nordicsemi.android.ui.view.KeyValueField import no.nordicsemi.android.ui.view.ScreenSection diff --git a/profile_csc/src/main/java/no/nordicsemi/android/csc/viewmodel/CSCViewModel.kt b/profile_csc/src/main/java/no/nordicsemi/android/csc/viewmodel/CSCViewModel.kt index b6a0c75e..19fb8c6c 100644 --- a/profile_csc/src/main/java/no/nordicsemi/android/csc/viewmodel/CSCViewModel.kt +++ b/profile_csc/src/main/java/no/nordicsemi/android/csc/viewmodel/CSCViewModel.kt @@ -35,8 +35,6 @@ import android.os.ParcelUuid import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -46,17 +44,15 @@ import no.nordicsemi.android.analytics.Profile import no.nordicsemi.android.analytics.ProfileConnectedEvent import no.nordicsemi.android.common.navigation.NavigationResult import no.nordicsemi.android.common.navigation.Navigator +import no.nordicsemi.android.csc.data.SpeedUnit import no.nordicsemi.android.csc.repository.CSCRepository import no.nordicsemi.android.csc.repository.CSC_SERVICE_UUID import no.nordicsemi.android.csc.view.CSCViewEvent -import no.nordicsemi.android.csc.view.CSCViewState import no.nordicsemi.android.csc.view.NavigateUp import no.nordicsemi.android.csc.view.OnDisconnectButtonClick import no.nordicsemi.android.csc.view.OnSelectedSpeedUnitSelected import no.nordicsemi.android.csc.view.OnWheelSizeSelected import no.nordicsemi.android.csc.view.OpenLogger -import no.nordicsemi.android.csc.view.SpeedUnit -import no.nordicsemi.android.csc.view.WorkingState import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.toolbox.scanner.ScannerDestinationId @@ -69,8 +65,7 @@ internal class CSCViewModel @Inject constructor( private val analytics: AppAnalytics ) : ViewModel() { - private val _state = MutableStateFlow(CSCViewState()) - val state = _state.asStateFlow() + val state = repository.data init { viewModelScope.launch { @@ -80,8 +75,6 @@ internal class CSCViewModel @Inject constructor( } repository.data.onEach { - _state.value = _state.value.copy(cscManagerState = WorkingState(it)) - if (it.connectionState == GattConnectionState.STATE_CONNECTED) { analytics.logEvent(ProfileConnectedEvent(Profile.CSC)) } @@ -104,7 +97,6 @@ internal class CSCViewModel @Inject constructor( } private fun onDeviceSelected(device: ServerDevice) { - _state.value = _state.value.copy(deviceName = device.name) repository.launch(device) } @@ -119,7 +111,7 @@ internal class CSCViewModel @Inject constructor( } private fun setSpeedUnit(speedUnit: SpeedUnit) { - _state.value = _state.value.copy(speedUnit = speedUnit) + repository.setSpeedUnit(speedUnit) } private fun disconnect() {