From a5306eaf71d88076b2cf4c1f2336dbc58340b77a Mon Sep 17 00:00:00 2001 From: Sylwester Zielinski Date: Tue, 21 Mar 2023 10:40:31 +0100 Subject: [PATCH] Migrate PRX module to the new BLE library --- .../nordicsemi/android/prx/data/PRXManager.kt | 179 ------------------ .../prx/data/ProximityServerManager.kt | 76 -------- .../android/prx/repository/AlarmHandler.kt | 2 +- .../android/prx/repository/PRXRepository.kt | 28 +-- .../android/prx/repository/PRXService.kt | 81 ++++++-- .../android/prx/view/PRXContentView.kt | 7 +- .../nordicsemi/android/prx/view/PRXMapper.kt | 2 +- .../nordicsemi/android/prx/view/PRXScreen.kt | 45 ++--- .../android/prx/viewmodel/PRXViewModel.kt | 7 +- 9 files changed, 104 insertions(+), 323 deletions(-) delete mode 100644 profile_prx/src/main/java/no/nordicsemi/android/prx/data/PRXManager.kt delete mode 100644 profile_prx/src/main/java/no/nordicsemi/android/prx/data/ProximityServerManager.kt diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/data/PRXManager.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/data/PRXManager.kt deleted file mode 100644 index d5a11630..00000000 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/data/PRXManager.kt +++ /dev/null @@ -1,179 +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.prx.data - -import android.bluetooth.BluetoothDevice -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCharacteristic -import android.bluetooth.BluetoothGattServer -import android.content.Context -import android.util.Log -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import no.nordicsemi.android.ble.BleManager -import no.nordicsemi.android.ble.common.callback.alert.AlertLevelDataCallback -import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelResponse -import no.nordicsemi.android.ble.common.data.alert.AlertLevelData -import no.nordicsemi.android.ble.ktx.asValidResponseFlow -import no.nordicsemi.android.ble.ktx.suspend -import no.nordicsemi.android.common.logger.NordicLogger -import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel -import no.nordicsemi.android.service.ConnectionObserverAdapter -import no.nordicsemi.android.utils.launchWithCatch -import java.util.* - -val PRX_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb") -val LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb") -val ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-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 PRXManager( - context: Context, - private val scope: CoroutineScope, - private val logger: NordicLogger -) : BleManager(context) { - - private var batteryLevelCharacteristic: BluetoothGattCharacteristic? = null - private var alertLevelCharacteristic: BluetoothGattCharacteristic? = null - private var linkLossCharacteristic: BluetoothGattCharacteristic? = null - - private var localAlertLevelCharacteristic: BluetoothGattCharacteristic? = null - private var linkLossServerCharacteristic: BluetoothGattCharacteristic? = null - - private var isAlertEnabled = false - - private val data = MutableStateFlow(PRXData()) - val dataHolder = ConnectionObserverAdapter() - - init { - connectionObserver = dataHolder - - data.onEach { - dataHolder.setValue(it) - }.launchIn(scope) - } - - override fun log(priority: Int, message: String) { - logger.log(priority, message) - } - - override fun getMinLogPriority(): Int { - return Log.VERBOSE - } - - private inner class ProximityManagerGattCallback : BleManagerGattCallback() { - override fun initialize() { - super.initialize() - - setWriteCallback(localAlertLevelCharacteristic) - .with(object : AlertLevelDataCallback() { - override fun onAlertLevelChanged(device: BluetoothDevice, level: Int) { - data.value = data.value.copy(localAlarmLevel = AlarmLevel.create(level)) - } - }) - - setWriteCallback(linkLossServerCharacteristic) - .with(object : AlertLevelDataCallback() { - override fun onAlertLevelChanged(device: BluetoothDevice, level: Int) { - data.value = data.value.copy(linkLossAlarmLevel = AlarmLevel.create(level)) - } - }) - - writeCharacteristic( - linkLossCharacteristic, - AlertLevelData.highAlert(), - BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT - ).enqueue() - - setNotificationCallback(batteryLevelCharacteristic) - .asValidResponseFlow() - .onEach { - data.value = data.value.copy(batteryLevel = it.batteryLevel) - }.launchIn(scope) - enableNotifications(batteryLevelCharacteristic).enqueue() - } - - override fun onServerReady(server: BluetoothGattServer) { - val immediateAlertService = server.getService(PRX_SERVICE_UUID) - if (immediateAlertService != null) { - localAlertLevelCharacteristic = immediateAlertService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID) - } - val linkLossService = server.getService(LINK_LOSS_SERVICE_UUID) - if (linkLossService != null) { - linkLossServerCharacteristic = linkLossService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID) - } - } - - override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean { - gatt.getService(LINK_LOSS_SERVICE_UUID)?.run { - linkLossCharacteristic = getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID) - } - gatt.getService(BATTERY_SERVICE_UUID)?.run { - batteryLevelCharacteristic = getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID) - } - gatt.getService(PRX_SERVICE_UUID)?.run { - alertLevelCharacteristic = getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID) - } - return linkLossCharacteristic != null - } - - override fun onServicesInvalidated() { - batteryLevelCharacteristic = null - alertLevelCharacteristic = null - linkLossCharacteristic = null - localAlertLevelCharacteristic = null - linkLossServerCharacteristic = null - isAlertEnabled = false - } - } - - fun writeImmediateAlert(on: Boolean) { - if (!isConnected) return - scope.launchWithCatch { - writeCharacteristic( - alertLevelCharacteristic, - if (on) AlertLevelData.highAlert() else AlertLevelData.noAlert(), - BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - ).suspend() - - isAlertEnabled = on - data.value = data.value.copy(isRemoteAlarm = on) - } - } - - override fun getGattCallback(): BleManagerGattCallback { - return ProximityManagerGattCallback() - } -} diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/data/ProximityServerManager.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/data/ProximityServerManager.kt deleted file mode 100644 index b355086b..00000000 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/data/ProximityServerManager.kt +++ /dev/null @@ -1,76 +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.prx.data - -import android.bluetooth.BluetoothGattCharacteristic -import android.bluetooth.BluetoothGattService -import android.content.Context -import android.util.Log -import dagger.hilt.android.qualifiers.ApplicationContext -import no.nordicsemi.android.ble.BleServerManager -import no.nordicsemi.android.ble.common.data.alert.AlertLevelData -import javax.inject.Inject - -internal class ProximityServerManager @Inject constructor( - @ApplicationContext - context: Context -) : BleServerManager(context) { - - override fun log(priority: Int, message: String) { - Log.println(priority, "BleManager", message) - } - - override fun initializeServer(): List { - val services: MutableList = ArrayList() - services.add( - service( - PRX_SERVICE_UUID, - characteristic( - ALERT_LEVEL_CHARACTERISTIC_UUID, - BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, - BluetoothGattCharacteristic.PERMISSION_WRITE - ) - ) - ) - services.add( - service( - LINK_LOSS_SERVICE_UUID, - characteristic( - ALERT_LEVEL_CHARACTERISTIC_UUID, - BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_READ, - BluetoothGattCharacteristic.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ, - AlertLevelData.highAlert() - ) - ) - ) - return services - } -} diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/AlarmHandler.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/AlarmHandler.kt index 2d779909..eccef2ee 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/AlarmHandler.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/AlarmHandler.kt @@ -35,7 +35,7 @@ import android.content.Context import android.media.RingtoneManager import android.os.Build import dagger.hilt.android.qualifiers.ApplicationContext -import no.nordicsemi.android.prx.data.AlarmLevel +import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import javax.inject.Inject internal class AlarmHandler @Inject constructor( diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXRepository.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXRepository.kt index c420435a..58acccbb 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXRepository.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXRepository.kt @@ -42,11 +42,9 @@ import no.nordicsemi.android.common.logger.NordicLogger import no.nordicsemi.android.common.logger.NordicLoggerFactory import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState -import no.nordicsemi.android.kotlin.ble.profile.hrs.data.HRSData import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import no.nordicsemi.android.kotlin.ble.profile.prx.PRXData import no.nordicsemi.android.prx.data.PRXServiceData -import no.nordicsemi.android.prx.data.ProximityServerManager import no.nordicsemi.android.service.BleManagerResult import no.nordicsemi.android.service.DisconnectAndStopEvent import no.nordicsemi.android.service.LinkLossResult @@ -61,10 +59,7 @@ class PRXRepository @Inject internal constructor( @ApplicationContext private val context: Context, private val serviceManager: ServiceManager, - private val proximityServerManager: ProximityServerManager, private val alarmHandler: AlarmHandler, - private val loggerFactory: NordicLoggerFactory, - private val stringConst: StringConst ) { private val _data = MutableStateFlow(PRXServiceData()) @@ -73,6 +68,9 @@ class PRXRepository @Inject internal constructor( private val _stopEvent = simpleSharedFlow() internal val stopEvent = _stopEvent.asSharedFlow() + private val _remoteAlarmLevel = simpleSharedFlow() + internal val remoteAlarmLevel = _remoteAlarmLevel.asSharedFlow() + val isRunning = data.map { it.connectionState == GattConnectionState.STATE_CONNECTED } fun launch(device: ServerDevice) { @@ -87,6 +85,14 @@ class PRXRepository @Inject internal constructor( _data.value = _data.value.copy(connectionState = connectionState) } + fun setLocalAlarmLevel(alarmLevel: AlarmLevel) { + _data.value = _data.value.copy(localAlarmLevel = alarmLevel) + } + + fun setLinkLossAlarmLevel(alarmLevel: AlarmLevel) { + _data.value = _data.value.copy(linkLossAlarmLevel = alarmLevel) + } + private fun handleLocalAlarm(result: BleManagerResult) { (result as? SuccessResult)?.let { if (it.data.localAlarmLevel != AlarmLevel.NONE) { @@ -105,20 +111,20 @@ class PRXRepository @Inject internal constructor( _data.value = _data.value.copy(batteryLevel = batteryLevel) } - fun enableAlarm() { - manager?.writeImmediateAlert(true) + fun setRemoteAlarmLevel(alarmLevel: AlarmLevel) { + _remoteAlarmLevel.tryEmit(alarmLevel) } - fun disableAlarm() { - manager?.writeImmediateAlert(false) + fun onRemoteAlarmLevelSet(alarmLevel: AlarmLevel) { + _data.value = _data.value.copy(isRemoteAlarm = alarmLevel != AlarmLevel.NONE) } fun openLogger() { - NordicLogger.launch(context, logger) + TODO() } fun release() { - disableAlarm() + _remoteAlarmLevel.tryEmit(AlarmLevel.NONE) _stopEvent.tryEmit(DisconnectAndStopEvent()) } } diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXService.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXService.kt index 7dbf20b7..707b0207 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXService.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/repository/PRXService.kt @@ -33,6 +33,7 @@ package no.nordicsemi.android.prx.repository import android.annotation.SuppressLint import android.content.Intent +import android.util.Log import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.filterNotNull @@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import no.nordicsemi.android.kotlin.ble.core.ServerDevice +import no.nordicsemi.android.kotlin.ble.core.client.BleWriteType import no.nordicsemi.android.kotlin.ble.core.client.callback.BleGattClient import no.nordicsemi.android.kotlin.ble.core.client.service.BleGattCharacteristic import no.nordicsemi.android.kotlin.ble.core.client.service.BleGattServices @@ -51,8 +53,11 @@ import no.nordicsemi.android.kotlin.ble.core.server.BleGattServer import no.nordicsemi.android.kotlin.ble.core.server.service.service.BleGattServerServiceType import no.nordicsemi.android.kotlin.ble.core.server.service.service.BleServerGattCharacteristicConfig import no.nordicsemi.android.kotlin.ble.core.server.service.service.BleServerGattServiceConfig +import no.nordicsemi.android.kotlin.ble.core.server.service.service.BluetoothGattServerConnection import no.nordicsemi.android.kotlin.ble.profile.battery.BatteryLevelParser -import no.nordicsemi.android.kotlin.ble.profile.hts.HTSDataParser +import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel +import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevelParser +import no.nordicsemi.android.kotlin.ble.profile.prx.AlertLevelInputParser import no.nordicsemi.android.service.DEVICE_DATA import no.nordicsemi.android.service.NotificationService import java.util.* @@ -60,6 +65,7 @@ import javax.inject.Inject val PRX_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb") private val LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb") + private val ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb") private val BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb") @@ -73,6 +79,7 @@ internal class PRXService : NotificationService() { lateinit var repository: PRXRepository private lateinit var client: BleGattClient + private lateinit var server: BleGattServer private lateinit var alertLevelCharacteristic: BleGattCharacteristic @@ -81,37 +88,69 @@ internal class PRXService : NotificationService() { val device = intent!!.getParcelableExtra(DEVICE_DATA)!! + startServer() + startGattClient(device) repository.stopEvent .onEach { disconnect() } .launchIn(lifecycleScope) + repository.remoteAlarmLevel + .onEach { writeAlertLevel(it) } + .launchIn(lifecycleScope) + return START_REDELIVER_INTENT } private fun startServer() { val alertLevelCharacteristic = BleServerGattCharacteristicConfig( - ALERT_LEVEL_CHARACTERISTIC_UUID, - listOf(BleGattProperty.PROPERTY_WRITE_NO_RESPONSE), - listOf(BleGattPermission.PERMISSION_WRITE) + uuid = ALERT_LEVEL_CHARACTERISTIC_UUID, + properties = listOf(BleGattProperty.PROPERTY_WRITE_NO_RESPONSE), + permissions = listOf(BleGattPermission.PERMISSION_WRITE) + ) + val prxServiceConfig = BleServerGattServiceConfig( + uuid = PRX_SERVICE_UUID, + type = BleGattServerServiceType.SERVICE_TYPE_PRIMARY, + characteristicConfigs = listOf(alertLevelCharacteristic) ) val linkLossCharacteristic = BleServerGattCharacteristicConfig( - LINK_LOSS_SERVICE_UUID, - listOf(BleGattProperty.PROPERTY_WRITE, BleGattProperty.PROPERTY_READ), - listOf(BleGattPermission.PERMISSION_WRITE, BleGattPermission.PERMISSION_READ) + uuid = ALERT_LEVEL_CHARACTERISTIC_UUID, + properties = listOf(BleGattProperty.PROPERTY_WRITE, BleGattProperty.PROPERTY_READ), + permissions = listOf(BleGattPermission.PERMISSION_WRITE, BleGattPermission.PERMISSION_READ), + initialValue = AlertLevelInputParser.parse(AlarmLevel.HIGH) ) - val serviceConfig = BleServerGattServiceConfig( - PRX_SERVICE_UUID, - BleGattServerServiceType.SERVICE_TYPE_PRIMARY, - listOf(alertLevelCharacteristic, linkLossCharacteristic) + val linkLossServiceConfig = BleServerGattServiceConfig( + uuid = LINK_LOSS_SERVICE_UUID, + type = BleGattServerServiceType.SERVICE_TYPE_PRIMARY, + characteristicConfigs = listOf(linkLossCharacteristic) ) - val server = BleGattServer.create(this@PRXService, serviceConfig) + server = BleGattServer.create(this@PRXService, prxServiceConfig, linkLossServiceConfig) - TODO("Initialize characteristic with value") + server.onNewConnection + .onEach { setUpServerConnection(it.second) } + .launchIn(lifecycleScope) + } + + private fun setUpServerConnection(connection: BluetoothGattServerConnection) { + val prxService = connection.services.findService(PRX_SERVICE_UUID)!! + val linkLossService = connection.services.findService(LINK_LOSS_SERVICE_UUID)!! + + val prxCharacteristic = prxService.findCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID)!! + val linkLossCharacteristic = linkLossService.findCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID)!! + + prxCharacteristic.value + .mapNotNull { AlarmLevelParser.parse(it) } + .onEach { repository.setLocalAlarmLevel(it) } + .launchIn(lifecycleScope) + + linkLossCharacteristic.value + .mapNotNull { AlarmLevelParser.parse(it) } + .onEach { repository.setLocalAlarmLevel(it) } + .launchIn(lifecycleScope) } private fun startGattClient(device: ServerDevice) = lifecycleScope.launch { @@ -132,7 +171,8 @@ internal class PRXService : NotificationService() { private suspend fun configureGatt(services: BleGattServices, device: ServerDevice) { val prxService = services.findService(PRX_SERVICE_UUID)!! alertLevelCharacteristic = prxService.findCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID)!! - val linkLossCharacteristic = prxService.findCharacteristic(LINK_LOSS_SERVICE_UUID)!! + val linkLossService = services.findService(LINK_LOSS_SERVICE_UUID)!! + val linkLossCharacteristic = linkLossService.findCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID)!! val batteryService = services.findService(BATTERY_SERVICE_UUID)!! val batteryLevelCharacteristic = batteryService.findCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID)!! @@ -141,16 +181,16 @@ internal class PRXService : NotificationService() { .onEach { repository.onBatteryLevelChanged(it) } .launchIn(lifecycleScope) - linkLossCharacteristic.write(Alert) - - htsMeasurementCharacteristic.getNotifications() - .mapNotNull { HTSDataParser.parse(it) } - .onEach { repository.onHTSDataChanged(it) } - .launchIn(lifecycleScope) + linkLossCharacteristic.write(AlertLevelInputParser.parse(AlarmLevel.HIGH)) repository.onInitComplete(device) } + private suspend fun writeAlertLevel(alarmLevel: AlarmLevel) { + alertLevelCharacteristic.write(AlertLevelInputParser.parse(alarmLevel), BleWriteType.NO_RESPONSE) + repository.onRemoteAlarmLevelSet(alarmLevel) + } + private fun stopIfDisconnected(connectionState: GattConnectionState) { if (connectionState == GattConnectionState.STATE_DISCONNECTED) { stopSelf() @@ -159,5 +199,6 @@ internal class PRXService : NotificationService() { private fun disconnect() { client.disconnect() + server.stopServer() } } diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXContentView.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXContentView.kt index 16fd4a71..1f2a13f8 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXContentView.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXContentView.kt @@ -44,13 +44,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import no.nordicsemi.android.prx.R +import no.nordicsemi.android.prx.data.PRXServiceData import no.nordicsemi.android.ui.view.BatteryLevelView import no.nordicsemi.android.ui.view.KeyValueField import no.nordicsemi.android.ui.view.ScreenSection import no.nordicsemi.android.ui.view.SectionTitle @Composable -internal fun ContentView(state: PRXData, onEvent: (PRXScreenViewEvent) -> Unit) { +internal fun ContentView(state: PRXServiceData, onEvent: (PRXScreenViewEvent) -> Unit) { Column( horizontalAlignment = Alignment.CenterHorizontally ) { @@ -77,7 +78,7 @@ internal fun ContentView(state: PRXData, onEvent: (PRXScreenViewEvent) -> Unit) } @Composable -private fun SettingsSection(state: PRXData, onEvent: (PRXScreenViewEvent) -> Unit) { +private fun SettingsSection(state: PRXServiceData, onEvent: (PRXScreenViewEvent) -> Unit) { ScreenSection { SectionTitle(icon = Icons.Default.Settings, title = stringResource(R.string.prx_settings)) @@ -110,7 +111,7 @@ private fun TurnAlarmOffButton(onEvent: (PRXScreenViewEvent) -> Unit) { } @Composable -private fun RecordsSection(state: PRXData) { +private fun RecordsSection(state: PRXServiceData) { ScreenSection { SectionTitle(resId = R.drawable.ic_records, title = stringResource(id = R.string.prx_records)) diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXMapper.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXMapper.kt index f687a018..4f9bf5d2 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXMapper.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXMapper.kt @@ -33,8 +33,8 @@ package no.nordicsemi.android.prx.view import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource +import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import no.nordicsemi.android.prx.R -import no.nordicsemi.android.prx.data.AlarmLevel @Composable internal fun Boolean.toDisplayString(): String { diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXScreen.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXScreen.kt index b20d2f3c..0a453206 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXScreen.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/view/PRXScreen.kt @@ -46,17 +46,10 @@ import androidx.hilt.navigation.compose.hiltViewModel 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.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.prx.R +import no.nordicsemi.android.prx.data.PRXServiceData import no.nordicsemi.android.prx.viewmodel.PRXViewModel -import no.nordicsemi.android.service.ConnectedResult -import no.nordicsemi.android.service.ConnectingResult -import no.nordicsemi.android.service.DeviceHolder -import no.nordicsemi.android.service.DisconnectedResult -import no.nordicsemi.android.service.IdleResult -import no.nordicsemi.android.service.LinkLossResult -import no.nordicsemi.android.service.MissingServiceResult -import no.nordicsemi.android.service.SuccessResult -import no.nordicsemi.android.service.UnknownErrorResult import no.nordicsemi.android.ui.view.BackIconAppBar import no.nordicsemi.android.ui.view.LoggerIconAppBar import no.nordicsemi.android.ui.view.NavigateUpButton @@ -78,17 +71,15 @@ fun PRXScreen() { .padding(16.dp) .verticalScroll(rememberScrollState()) ) { - when (state) { - NoDeviceState -> DeviceConnectingView() - is WorkingState -> when (state.result) { - is IdleResult, - is ConnectingResult -> DeviceConnectingView { NavigateUpButton(navigateUp) } - is ConnectedResult -> DeviceConnectingView { NavigateUpButton(navigateUp) } - is DisconnectedResult -> DeviceDisconnectedView(Reason.USER) { NavigateUpButton(navigateUp) } - is LinkLossResult -> DeviceDisconnectedView(Reason.LINK_LOSS) { NavigateUpButton(navigateUp) } - is MissingServiceResult -> DeviceDisconnectedView(Reason.MISSING_SERVICE) { NavigateUpButton(navigateUp) } - is UnknownErrorResult -> DeviceDisconnectedView(Reason.UNKNOWN) { NavigateUpButton(navigateUp) } - is SuccessResult -> ContentView(state.result.data) { viewModel.onEvent(it) } + 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 -> ContentView(state) { viewModel.onEvent(it) } } } } @@ -96,16 +87,12 @@ fun PRXScreen() { } @Composable -private fun AppBar(state: PRXViewState, navigateUp: () -> Unit, viewModel: PRXViewModel) { - val toolbarName = (state as? WorkingState)?.let { - (it.result as? DeviceHolder)?.deviceName() - } - - if (toolbarName == null) { - BackIconAppBar(stringResource(id = R.string.prx_title), navigateUp) - } else { - LoggerIconAppBar(toolbarName, navigateUp, { viewModel.onEvent(DisconnectEvent) }) { +private fun AppBar(state: PRXServiceData, navigateUp: () -> Unit, viewModel: PRXViewModel) { + if (state.deviceName?.isNotBlank() == true) { + LoggerIconAppBar(state.deviceName, navigateUp, { viewModel.onEvent(DisconnectEvent) }) { viewModel.onEvent(OpenLoggerEvent) } + } else { + BackIconAppBar(stringResource(id = R.string.prx_title), navigateUp) } } diff --git a/profile_prx/src/main/java/no/nordicsemi/android/prx/viewmodel/PRXViewModel.kt b/profile_prx/src/main/java/no/nordicsemi/android/prx/viewmodel/PRXViewModel.kt index 093be6e7..080a86aa 100644 --- a/profile_prx/src/main/java/no/nordicsemi/android/prx/viewmodel/PRXViewModel.kt +++ b/profile_prx/src/main/java/no/nordicsemi/android/prx/viewmodel/PRXViewModel.kt @@ -46,8 +46,9 @@ import no.nordicsemi.android.common.navigation.NavigationResult import no.nordicsemi.android.common.navigation.Navigator import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState -import no.nordicsemi.android.prx.data.PRX_SERVICE_UUID +import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import no.nordicsemi.android.prx.repository.PRXRepository +import no.nordicsemi.android.prx.repository.PRX_SERVICE_UUID import no.nordicsemi.android.prx.view.DisconnectEvent import no.nordicsemi.android.prx.view.NavigateUpEvent import no.nordicsemi.android.prx.view.OpenLoggerEvent @@ -98,8 +99,8 @@ internal class PRXViewModel @Inject constructor( fun onEvent(event: PRXScreenViewEvent) { when (event) { DisconnectEvent -> disconnect() - TurnOffAlert -> repository.disableAlarm() - TurnOnAlert -> repository.enableAlarm() + TurnOffAlert -> repository.setRemoteAlarmLevel(AlarmLevel.NONE) + TurnOnAlert -> repository.setRemoteAlarmLevel(AlarmLevel.HIGH) NavigateUpEvent -> navigationManager.navigateUp() OpenLoggerEvent -> repository.openLogger() }