Fix crashes observed on Firebase console (#130)

* Switch getParcelableExtra to IntentCompat

* Fix MissingForegroundServiceTypeException

* Fix UART server

* Move foreground service permissions to one place
This commit is contained in:
Sylwester Zieliński
2023-10-16 15:41:41 +02:00
committed by GitHub
parent 9c1ac06894
commit 391a4e0b6d
18 changed files with 67 additions and 184 deletions

View File

@@ -51,5 +51,7 @@ class NrfToolboxApplication : Application() {
super.onCreate()
analytics.logEvent(AppOpenEvent)
uartServer.start(this)
}
}

View File

@@ -34,7 +34,9 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
</manifest>

View File

@@ -37,8 +37,6 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Parcelable
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
@@ -135,11 +133,6 @@ abstract class NotificationService : LifecycleService() {
nm.cancel(NOTIFICATION_ID)
}
inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
SDK_INT >= 33 -> getParcelableExtra(key, T::class.java)
else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T
}
companion object {
private const val NOTIFICATION_ID = 200
}

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -31,8 +30,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".repository.CGMService" />
<service
android:name=".repository.CGMService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.cgms.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -107,7 +108,7 @@ internal class CGMService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -37,7 +36,10 @@
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<application>
<service android:name=".repository.CSCService" />
<service
android:name=".repository.CSCService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.csc.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -73,7 +74,7 @@ internal class CSCService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -33,7 +32,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".service.HRSService" />
<service
android:name=".service.HRSService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.hrs.service
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -75,7 +76,7 @@ internal class HRSService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -33,7 +32,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".repository.HTSService" />
<service
android:name=".repository.HTSService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.hts.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -73,7 +74,7 @@ internal class HTSService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -33,6 +32,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".repository.PRXService"/>
<service
android:name=".repository.PRXService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.prx.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -92,7 +93,7 @@ internal class PRXService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startServer(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -33,6 +32,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".repository.RSCSService"/>
<service
android:name=".repository.RSCSService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.rscs.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -73,7 +74,7 @@ internal class RSCSService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.getParcelableExtra<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2022, Nordic Semiconductor
~ All rights reserved.
~
@@ -33,7 +32,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name=".repository.UARTService" />
<service
android:name=".repository.UARTService"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
</application>
</manifest>

View File

@@ -14,7 +14,6 @@ import no.nordicsemi.android.kotlin.ble.core.MockServerDevice
import no.nordicsemi.android.kotlin.ble.core.advertiser.BleAdvertisingConfig
import no.nordicsemi.android.kotlin.ble.core.data.BleGattPermission
import no.nordicsemi.android.kotlin.ble.core.data.BleGattProperty
import no.nordicsemi.android.kotlin.ble.profile.gls.RecordAccessControlPointInputParser
import no.nordicsemi.android.kotlin.ble.server.main.ServerBleGatt
import no.nordicsemi.android.kotlin.ble.server.main.service.ServerBleGattCharacteristic
import no.nordicsemi.android.kotlin.ble.server.main.service.ServerBleGattCharacteristicConfig
@@ -39,116 +38,20 @@ class UartServer @Inject constructor(
lateinit var server: ServerBleGatt
lateinit var glsCharacteristic: ServerBleGattCharacteristic
lateinit var glsContextCharacteristic: ServerBleGattCharacteristic
lateinit var racpCharacteristic: ServerBleGattCharacteristic
lateinit var rxCharacteristic: ServerBleGattCharacteristic
lateinit var txCharacteristic: ServerBleGattCharacteristic
lateinit var batteryLevelCharacteristic: ServerBleGattCharacteristic
private var lastRequest = DataByteArray()
val YOUNGEST_RECORD = DataByteArray.from(
0x07,
0x00,
0x00,
0xDC.toByte(),
0x07,
0x01,
0x01,
0x0C,
0x1E,
0x05,
0x00,
0x00,
0x26,
0xD2.toByte(),
0x11
)
val OLDEST_RECORD = DataByteArray.from(
0x07,
0x04,
0x00,
0xDC.toByte(),
0x07,
0x01,
0x01,
0x0C,
0x1E,
0x11,
0x00,
0x00,
0x82.toByte(),
0xD2.toByte(),
0x11
)
val records = listOf(
YOUNGEST_RECORD,
DataByteArray.from(
0x07,
0x01,
0x00,
0xDC.toByte(),
0x07,
0x01,
0x01,
0x0C,
0x1E,
0x08,
0x00,
0x00,
0x3D,
0xD2.toByte(),
0x11
),
DataByteArray.from(
0x07,
0x02,
0x00,
0xDC.toByte(),
0x07,
0x01,
0x01,
0x0C,
0x1E,
0x0B,
0x00,
0x00,
0x54,
0xD2.toByte(),
0x11
),
DataByteArray.from(
0x07,
0x03,
0x00,
0xDC.toByte(),
0x07,
0x01,
0x01,
0x0C,
0x1E,
0x0E,
0x00,
0x00,
0x6B,
0xD2.toByte(),
0x11
),
OLDEST_RECORD
)
val racp = DataByteArray.from(0x06, 0x00, 0x01, 0x01)
fun start(
context: Context,
device: MockServerDevice = MockServerDevice(
name = "GLS Server",
name = "UART Server",
address = "55:44:33:22:11"
),
) = scope.launch {
val rxCharacteristic = ServerBleGattCharacteristicConfig(
UART_RX_CHARACTERISTIC_UUID,
listOf(BleGattProperty.PROPERTY_NOTIFY),
listOf(BleGattProperty.PROPERTY_NOTIFY, BleGattProperty.PROPERTY_WRITE),
listOf()
)
@@ -197,57 +100,20 @@ class UartServer @Inject constructor(
}
private fun setUpConnection(connection: ServerBluetoothGattConnection) {
// val glsService = connection.services.findService(GLS_SERVICE_UUID)!!
// glsCharacteristic = glsService.findCharacteristic(GLUCOSE_MEASUREMENT_CHARACTERISTIC)!!
// glsContextCharacteristic = glsService.findCharacteristic(GLUCOSE_MEASUREMENT_CONTEXT_CHARACTERISTIC)!!
// racpCharacteristic = glsService.findCharacteristic(RACP_CHARACTERISTIC)!!
val glsService = connection.services.findService(UART_SERVICE_UUID)!!
rxCharacteristic = glsService.findCharacteristic(UART_RX_CHARACTERISTIC_UUID)!!
txCharacteristic = glsService.findCharacteristic(UART_TX_CHARACTERISTIC_UUID)!!
rxCharacteristic.value.onEach {
txCharacteristic.setValue(it)
}.launchIn(scope)
val batteryService = connection.services.findService(BATTERY_SERVICE_UUID)!!
batteryLevelCharacteristic = batteryService.findCharacteristic(
BATTERY_LEVEL_CHARACTERISTIC_UUID
)!!
// startGlsService(connection)
// startBatteryService(connection)
}
private fun startGlsService(connection: ServerBluetoothGattConnection) {
racpCharacteristic.value
.onEach { lastRequest = it }
.launchIn(scope)
}
internal fun continueWithResponse() {
sendResponse(lastRequest)
}
private fun sendResponse(request: DataByteArray) {
if (request == RecordAccessControlPointInputParser.reportNumberOfAllStoredRecords()) {
sendAll(glsCharacteristic)
racpCharacteristic.setValue(racp)
} else if (request == RecordAccessControlPointInputParser.reportLastStoredRecord()) {
sendLast(glsCharacteristic)
racpCharacteristic.setValue(racp)
} else if (request == RecordAccessControlPointInputParser.reportFirstStoredRecord()) {
sendFirst(glsCharacteristic)
racpCharacteristic.setValue(racp)
}
}
private fun sendFirst(characteristics: ServerBleGattCharacteristic) {
characteristics.setValue(records.first())
}
private fun sendLast(characteristics: ServerBleGattCharacteristic) {
characteristics.setValue(records.last())
}
private fun sendAll(characteristics: ServerBleGattCharacteristic) = scope.launch {
records.forEach {
characteristics.setValue(it)
delay(100)
}
startBatteryService(connection)
}
private fun startBatteryService(connection: ServerBluetoothGattConnection) {

View File

@@ -33,6 +33,7 @@ package no.nordicsemi.android.uart.repository
import android.annotation.SuppressLint
import android.content.Intent
import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.catch
@@ -78,7 +79,7 @@ internal class UARTService : NotificationService() {
repository.setServiceRunning(true)
val device = intent!!.parcelable<ServerDevice>(DEVICE_DATA)!!
val device = IntentCompat.getParcelableExtra(intent!!, DEVICE_DATA, ServerDevice::class.java)!!
startGattClient(device)