From feb131c655b577dc0d8dc5827b8da7ecd018f379 Mon Sep 17 00:00:00 2001 From: himalia416 Date: Fri, 26 Sep 2025 16:40:17 +0200 Subject: [PATCH] Session closed message --- .../channelSounding/ChannelSoundingManager.kt | 17 ++++-- .../channelSounding/ChannelSoundingScreen.kt | 59 ++++++------------- .../ChannelSoundingUiMapper.kt | 20 +++++++ .../res/values/channelSoundingStrings.xml | 13 +++- .../data/ChannelSoundingServiceData.kt | 27 ++++++++- 5 files changed, 86 insertions(+), 50 deletions(-) diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/repository/channelSounding/ChannelSoundingManager.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/repository/channelSounding/ChannelSoundingManager.kt index fc89761b..707f9fea 100644 --- a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/repository/channelSounding/ChannelSoundingManager.kt +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/repository/channelSounding/ChannelSoundingManager.kt @@ -26,6 +26,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import no.nordicsemi.android.toolbox.profile.data.RangingSessionAction +import no.nordicsemi.android.toolbox.profile.data.RangingSessionFailedReason +import no.nordicsemi.android.toolbox.profile.data.SessionClosedReason import no.nordicsemi.android.toolbox.profile.data.UpdateRate import timber.log.Timber import java.util.UUID @@ -51,7 +53,7 @@ class ChannelSoundingManager @Inject constructor( object : RangingSession.Callback { override fun onClosed(reason: Int) { _rangingData.value = - RangingSessionAction.OnError(RangingSessionCloseReason.getReason(reason)) + RangingSessionAction.OnError(RangingSessionFailedReason.getReason(reason)) // Unregister the callback to avoid memory leaks rangingManager?.unregisterCapabilitiesCallback(rangingCapabilityCallback) // Cleanup previous data @@ -111,7 +113,8 @@ class ChannelSoundingManager @Inject constructor( updateRate: UpdateRate = UpdateRate.NORMAL ) { if (rangingManager == null) { - _rangingData.value = RangingSessionAction.OnError("RangingManager is not available") + _rangingData.value = + RangingSessionAction.OnError(SessionClosedReason.RANGING_NOT_AVAILABLE) return } val setRangingUpdateRate = when (updateRate) { @@ -177,17 +180,19 @@ class ChannelSoundingManager @Inject constructor( } } else { _rangingData.value = - RangingSessionAction.OnError("Missing Ranging permission") + RangingSessionAction.OnError( + SessionClosedReason.MISSING_PERMISSION + ) return@RangingCapabilitiesCallback } } else { _rangingData.value = - RangingSessionAction.OnError("Channel Sounding with required security level is not supported") + RangingSessionAction.OnError(SessionClosedReason.CS_SECURITY_NOT_AVAILABLE) closeSession() } } else { _rangingData.value = - RangingSessionAction.OnError("Channel Sounding Capabilities is not supported") + RangingSessionAction.OnError(SessionClosedReason.NOT_SUPPORTED) closeSession() } @@ -221,7 +226,7 @@ class ChannelSoundingManager @Inject constructor( } } } catch (e: Exception) { - _rangingData.value = RangingSessionAction.OnError(e.message ?: "Unknown error") + _rangingData.value = RangingSessionAction.OnError(SessionClosedReason.UNKNOWN) } } diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingScreen.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingScreen.kt index 6a876b9f..5d69b999 100644 --- a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingScreen.kt +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingScreen.kt @@ -43,6 +43,7 @@ import no.nordicsemi.android.toolbox.profile.data.ChannelSoundingServiceData import no.nordicsemi.android.toolbox.profile.data.ConfidenceLevel import no.nordicsemi.android.toolbox.profile.data.RangingSessionAction import no.nordicsemi.android.toolbox.profile.data.RangingTechnology +import no.nordicsemi.android.toolbox.profile.data.SessionClosedReason import no.nordicsemi.android.toolbox.profile.data.UpdateRate import no.nordicsemi.android.toolbox.profile.viewmodel.ChannelSoundingEvent import no.nordicsemi.android.toolbox.profile.viewmodel.ChannelSoundingViewModel @@ -165,14 +166,11 @@ private fun SessionClosed( title = stringResource(R.string.channel_sounding), ) } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text(stringResource(R.string.ranging_session_stopped)) - } + Text( + stringResource(R.string.ranging_session_stopped), + modifier = Modifier.padding(8.dp), + textAlign = TextAlign.Center, + ) } Button( modifier = Modifier.padding(16.dp), @@ -208,42 +206,21 @@ private fun SessionError( title = stringResource(R.string.channel_sounding), ) } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally, + Text( + text = stringResource(sessionData.reason.toUiString()), + modifier = Modifier.padding(8.dp), + textAlign = TextAlign.Center, + ) + } + if (sessionData.reason != SessionClosedReason.NOT_SUPPORTED || + sessionData.reason != SessionClosedReason.RANGING_NOT_AVAILABLE) { + Button( + modifier = Modifier.padding(16.dp), + onClick = { onClickEvent(ChannelSoundingEvent.RestartRangingSession) }, ) { - if (sessionData.reason.isNotEmpty()) { - Text( - stringResource( - R.string.ranging_session_closed_with_reason, - sessionData.reason - ), - modifier = Modifier.padding(8.dp) - ) - } else { - Text( - stringResource(R.string.ranging_session_closed), - modifier = Modifier.padding(8.dp) - ) - } + Text(text = stringResource(id = R.string.reconnect)) } } - Button( - modifier = Modifier.padding(16.dp), - onClick = { onClickEvent(ChannelSoundingEvent.RestartRangingSession) }, - ) { - Text(text = stringResource(id = R.string.reconnect)) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun SessionError_Preview() { - NordicTheme { - SessionError(RangingSessionAction.OnError("Sample Error"), onClickEvent = {}) } } diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingUiMapper.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingUiMapper.kt index d70da561..3fc7cea0 100644 --- a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingUiMapper.kt +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/channelSounding/ChannelSoundingUiMapper.kt @@ -2,7 +2,10 @@ package no.nordicsemi.android.toolbox.profile.view.channelSounding import androidx.annotation.StringRes import no.nordicsemi.android.toolbox.profile.R +import no.nordicsemi.android.toolbox.profile.data.RangingSessionFailedReason import no.nordicsemi.android.toolbox.profile.data.RangingTechnology +import no.nordicsemi.android.toolbox.profile.data.SessionCloseReasonProvider +import no.nordicsemi.android.toolbox.profile.data.SessionClosedReason import no.nordicsemi.android.toolbox.profile.data.UpdateRate import no.nordicsemi.android.toolbox.profile.data.UpdateRate.FREQUENT import no.nordicsemi.android.toolbox.profile.data.UpdateRate.INFREQUENT @@ -38,3 +41,20 @@ internal fun RangingTechnology.toUiString(): Int { } +@StringRes +internal fun SessionCloseReasonProvider.toUiString(): Int { + return when (this) { + SessionClosedReason.MISSING_PERMISSION -> R.string.cs_missing_permissions + SessionClosedReason.NOT_SUPPORTED -> R.string.channel_sounding_not_supported + SessionClosedReason.RANGING_NOT_AVAILABLE -> R.string.cs_ranging_not_available + SessionClosedReason.CS_SECURITY_NOT_AVAILABLE -> R.string.cs_security_not_available + SessionClosedReason.UNKNOWN -> R.string.cs_error_unknown + RangingSessionFailedReason.LOCAL_REQUEST -> R.string.cs_local_request + RangingSessionFailedReason.REMOTE_REQUEST -> R.string.cs_remote_request + RangingSessionFailedReason.UNSUPPORTED -> R.string.cs_params_unsupported + RangingSessionFailedReason.SYSTEM_POLICY -> R.string.cs_system_policy + RangingSessionFailedReason.NO_PEERS_FOUND -> R.string.cs_no_peers_found + RangingSessionFailedReason.UNKNOWN -> R.string.cs_error_unknown + } +} + diff --git a/profile/src/main/res/values/channelSoundingStrings.xml b/profile/src/main/res/values/channelSoundingStrings.xml index 09e0c59d..35d64f9d 100644 --- a/profile/src/main/res/values/channelSoundingStrings.xml +++ b/profile/src/main/res/values/channelSoundingStrings.xml @@ -4,8 +4,6 @@ Channel Sounding is not supported on this Android version. Initiating ranging - Ranging session closed because of %s. - Ranging session closed. Ranging session stopped Distance @@ -39,6 +37,17 @@ Recent measurements Details + Missing permissions. + Ranging service not available. + Channel Sounding with required security level is not supported. + Oops! Session just ghosted harder than your last Tinder date. Try reconnecting… + Session terminated by local request. + Session terminated by remote peer. + Peer terminated the session. + Local system policy forced the session to close. + Provided session parameters are not supported. + No peers found. + Confirm Cancel \ No newline at end of file diff --git a/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/ChannelSoundingServiceData.kt b/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/ChannelSoundingServiceData.kt index 56ed6ad1..7713b006 100644 --- a/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/ChannelSoundingServiceData.kt +++ b/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/ChannelSoundingServiceData.kt @@ -17,7 +17,7 @@ sealed interface RangingSessionAction { val previousData: List = emptyList() ) : RangingSessionAction - data class OnError(val reason: String) : RangingSessionAction + data class OnError(val reason: SessionCloseReasonProvider) : RangingSessionAction object OnClosed : RangingSessionAction } @@ -48,3 +48,28 @@ enum class RangingTechnology(val value: Int) { fun from(value: Int): RangingTechnology? = entries.find { it.value == value } } } + +enum class SessionClosedReason : SessionCloseReasonProvider { + MISSING_PERMISSION, + NOT_SUPPORTED, + RANGING_NOT_AVAILABLE, + CS_SECURITY_NOT_AVAILABLE, + UNKNOWN; +} + +sealed interface SessionCloseReasonProvider + +enum class RangingSessionFailedReason(val reason: Int):SessionCloseReasonProvider { + UNKNOWN(0), + LOCAL_REQUEST(1), + REMOTE_REQUEST(2), + UNSUPPORTED(3), + SYSTEM_POLICY(4), + NO_PEERS_FOUND(5), ; + + companion object { + fun getReason(value: Int): RangingSessionFailedReason { + return entries.firstOrNull { it.reason == value } ?: UNKNOWN + } + } +}