From 900eaebdb128153210cc6443c37fa1c8af1cf233 Mon Sep 17 00:00:00 2001 From: hiar Date: Wed, 1 Oct 2025 16:36:26 +0200 Subject: [PATCH] dfu redirection --- .../android/toolbox/profile/ProfileScreen.kt | 2 +- .../profile/view/{ => dfu}/DFUScreen.kt | 46 +++++++++++++++++-- .../toolbox/profile/view/dfu/DfuUiMapper.kt | 32 +++++++++++++ .../toolbox/profile/data/DFUServiceData.kt | 12 ++++- .../toolbox/profile/manager/DFUManager.kt | 19 +++++--- .../manager/repository/DFURepository.kt | 3 +- 6 files changed, 100 insertions(+), 14 deletions(-) rename profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/{ => dfu}/DFUScreen.kt (59%) create mode 100644 profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DfuUiMapper.kt diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/ProfileScreen.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/ProfileScreen.kt index e95c4730..62370305 100644 --- a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/ProfileScreen.kt +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/ProfileScreen.kt @@ -29,7 +29,7 @@ import no.nordicsemi.android.common.permissions.ble.RequireLocation import no.nordicsemi.android.common.permissions.notification.RequestNotificationPermission import no.nordicsemi.android.toolbox.lib.utils.Profile import no.nordicsemi.android.toolbox.profile.data.displayMessage -import no.nordicsemi.android.toolbox.profile.view.DFUScreen +import no.nordicsemi.android.toolbox.profile.view.dfu.DFUScreen import no.nordicsemi.android.toolbox.profile.view.battery.BatteryScreen import no.nordicsemi.android.toolbox.profile.view.bps.BPSScreen import no.nordicsemi.android.toolbox.profile.view.cgms.CGMScreen diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/DFUScreen.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DFUScreen.kt similarity index 59% rename from profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/DFUScreen.kt rename to profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DFUScreen.kt index e3ed6b8a..94d7682c 100644 --- a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/DFUScreen.kt +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DFUScreen.kt @@ -1,12 +1,16 @@ -package no.nordicsemi.android.toolbox.profile.view +package no.nordicsemi.android.toolbox.profile.view.dfu import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Download +import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedCard @@ -14,6 +18,8 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -29,7 +35,8 @@ internal fun DFUScreen( modifier = Modifier .fillMaxSize() .then(modifier), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) ) { OutlinedCard( modifier = Modifier @@ -55,13 +62,46 @@ internal fun DFUScreen( ) Text( - text = "DFU service is not not available in the current version of the app." + + text = "DFU service is not available in the current version of the app. " + "Please use the DFU app from Nordic Semiconductor to update your device’s firmware.", textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyMedium ) } } + + val uriHandler = LocalUriHandler.current + val context = LocalContext.current + val packageManger = context.packageManager + val intent = packageManger.getLaunchIntentForPackage(DFU_PACKAGE_NAME) + + val description = intent?.let { + "Open DFU" + } ?: "Download from Play Store" + + Button( + onClick = { + if (intent != null) { + context.startActivity(intent) + } else { + uriHandler.openUri(DFU_APP_LINK) + } + }, + ) { + Row { + intent?.let { + Icon( + painter = painterResource(R.drawable.ic_dfu), + contentDescription = null, + modifier = Modifier + .size(24.dp) + .padding(end = 8.dp) + ) + } ?: Icon(imageVector = Icons.Default.Download, contentDescription = null) + Text(text = description) + } + + } } } diff --git a/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DfuUiMapper.kt b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DfuUiMapper.kt new file mode 100644 index 00000000..d57f3579 --- /dev/null +++ b/profile/src/main/java/no/nordicsemi/android/toolbox/profile/view/dfu/DfuUiMapper.kt @@ -0,0 +1,32 @@ +package no.nordicsemi.android.toolbox.profile.view.dfu + +import no.nordicsemi.android.toolbox.profile.data.DFUsAvailable + + +internal const val DFU_PACKAGE_NAME = "no.nordicsemi.android.dfu" +internal const val DFU_APP_LINK = + "https://play.google.com/store/apps/details?id=no.nordicsemi.android.dfu" + +internal const val SMP_PACKAGE_NAME = "no.nordicsemi.android.nrfconnectdevicemanager" +internal const val SMP_APP_LINK = + "https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrfconnectdevicemanager" + +internal fun DFUsAvailable.getApp(): String { + return when (this) { + DFUsAvailable.DFU_SERVICE -> DFU_APP_LINK + DFUsAvailable.SMP_SERVICE -> SMP_APP_LINK + DFUsAvailable.MDS_SERVICE -> SMP_APP_LINK + DFUsAvailable.LEGACY_DFU_SERVICE -> DFU_APP_LINK + DFUsAvailable.EXPERIMENTAL_BUTTONLESS_DFU_SERVICE -> DFU_APP_LINK + } +} + +internal fun DFUsAvailable.getPackageName(): String { + return when (this) { + DFUsAvailable.DFU_SERVICE -> DFU_PACKAGE_NAME + DFUsAvailable.SMP_SERVICE -> SMP_PACKAGE_NAME + DFUsAvailable.MDS_SERVICE -> SMP_PACKAGE_NAME + DFUsAvailable.LEGACY_DFU_SERVICE -> DFU_PACKAGE_NAME + DFUsAvailable.EXPERIMENTAL_BUTTONLESS_DFU_SERVICE -> DFU_PACKAGE_NAME + } +} diff --git a/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/DFUServiceData.kt b/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/DFUServiceData.kt index ebc1512d..45698a2a 100644 --- a/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/DFUServiceData.kt +++ b/profile_data/src/main/java/no/nordicsemi/android/toolbox/profile/data/DFUServiceData.kt @@ -4,5 +4,13 @@ import no.nordicsemi.android.toolbox.lib.utils.Profile data class DFUServiceData( override val profile: Profile = Profile.DFU, - val dfuAppName : String? = null, -): ProfileServiceData() \ No newline at end of file + val dfuAppName : DFUsAvailable? = null, +): ProfileServiceData() + +enum class DFUsAvailable { + DFU_SERVICE, + SMP_SERVICE, + MDS_SERVICE, + LEGACY_DFU_SERVICE, + EXPERIMENTAL_BUTTONLESS_DFU_SERVICE; +} \ No newline at end of file diff --git a/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/DFUManager.kt b/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/DFUManager.kt index fa972f5e..837ae970 100644 --- a/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/DFUManager.kt +++ b/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/DFUManager.kt @@ -5,12 +5,15 @@ import no.nordicsemi.android.toolbox.lib.utils.Profile import no.nordicsemi.android.toolbox.lib.utils.spec.DFU_SERVICE_UUID import no.nordicsemi.android.toolbox.lib.utils.spec.EXPERIMENTAL_BUTTONLESS_DFU_SERVICE_UUID import no.nordicsemi.android.toolbox.lib.utils.spec.LEGACY_DFU_SERVICE_UUID +import no.nordicsemi.android.toolbox.lib.utils.spec.MDS_SERVICE_UUID import no.nordicsemi.android.toolbox.lib.utils.spec.SMP_SERVICE_UUID +import no.nordicsemi.android.toolbox.profile.data.DFUsAvailable +import no.nordicsemi.android.toolbox.profile.manager.repository.DFURepository import no.nordicsemi.kotlin.ble.client.RemoteService import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.toKotlinUuid -internal class DFUManager :ServiceManager{ +internal class DFUManager : ServiceManager { override val profile: Profile get() = Profile.DFU @@ -20,15 +23,17 @@ internal class DFUManager :ServiceManager{ remoteService: RemoteService, scope: CoroutineScope ) { - when (remoteService.uuid) { - DFU_SERVICE_UUID.toKotlinUuid(), - SMP_SERVICE_UUID.toKotlinUuid(), - LEGACY_DFU_SERVICE_UUID.toKotlinUuid(), - EXPERIMENTAL_BUTTONLESS_DFU_SERVICE_UUID.toKotlinUuid() -> this + val appName = when (remoteService.uuid) { + DFU_SERVICE_UUID.toKotlinUuid() -> DFUsAvailable.DFU_SERVICE + SMP_SERVICE_UUID.toKotlinUuid() -> DFUsAvailable.SMP_SERVICE + LEGACY_DFU_SERVICE_UUID.toKotlinUuid() -> DFUsAvailable.LEGACY_DFU_SERVICE + EXPERIMENTAL_BUTTONLESS_DFU_SERVICE_UUID.toKotlinUuid() -> DFUsAvailable.EXPERIMENTAL_BUTTONLESS_DFU_SERVICE + MDS_SERVICE_UUID.toKotlinUuid() -> DFUsAvailable.MDS_SERVICE else -> null - } + if (appName != null) + DFURepository.updateAppName(deviceId, appName) } } \ No newline at end of file diff --git a/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/repository/DFURepository.kt b/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/repository/DFURepository.kt index 36057f67..8bbea587 100644 --- a/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/repository/DFURepository.kt +++ b/profile_manager/src/main/java/no/nordicsemi/android/toolbox/profile/manager/repository/DFURepository.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import no.nordicsemi.android.toolbox.profile.data.DFUServiceData +import no.nordicsemi.android.toolbox.profile.data.DFUsAvailable object DFURepository { private val _dataMap = mutableMapOf>() @@ -12,7 +13,7 @@ object DFURepository { return _dataMap.getOrPut(deviceId) { MutableStateFlow(DFUServiceData()) } } - fun updateAppName(deviceId: String, appName: String) { + fun updateAppName(deviceId: String, appName: DFUsAvailable) { _dataMap[deviceId]?.update { it.copy(dfuAppName = appName) } }