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
+ }
+ }
+}