Introduce BluetoothAddress typealias

This commit introduces a typealias `BluetoothAddress` for `String` to improve code clarity and type safety when dealing with Bluetooth MAC addresses.

The following changes were made:
- Created `BluetoothAddress.kt` defining the typealias.
- Updated various classes to use `BluetoothAddress` instead of `String` for Bluetooth addresses:
    - `RPAChecker`
    - `PopUpReaction`
    - `DeviceSelectionDialogFactory`
    - `MonitorWorker`
    - `GeneralSettings`
    - `BluetoothDevice2`
This commit is contained in:
darken
2025-06-06 06:03:41 +02:00
committed by Matthias Urhahn
parent 11a19da0b8
commit 877c5d9013
7 changed files with 27 additions and 24 deletions
@@ -0,0 +1,3 @@
package eu.darken.capod.common.bluetooth
typealias BluetoothAddress = String
@@ -7,7 +7,7 @@ data class BluetoothDevice2(
internal val internal: BluetoothDevice,
val seenFirstAt: Instant,
) {
val address: String
val address: BluetoothAddress
get() = internal.address
val name: String?
@@ -5,6 +5,7 @@ import android.content.SharedPreferences
import androidx.preference.PreferenceDataStore
import com.squareup.moshi.Moshi
import dagger.hilt.android.qualifiers.ApplicationContext
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.bluetooth.ScannerMode
import eu.darken.capod.common.debug.DebugSettings
import eu.darken.capod.common.preferences.PreferenceStoreMapper
@@ -33,7 +34,7 @@ class GeneralSettings @Inject constructor(
val minimumSignalQuality = preferences.createFlowPreference("core.signal.minimum", 0.20f)
val mainDeviceAddress = preferences.createFlowPreference<String?>("core.maindevice.address", null)
val mainDeviceAddress = preferences.createFlowPreference<BluetoothAddress?>("core.maindevice.address", null)
val mainDeviceModel = preferences.createFlowPreference("core.maindevice.model", PodDevice.Model.UNKNOWN, moshi)
val mainDeviceIdentityKey = preferences.createFlowPreference<ByteArray?>("core.maindevice.identitykey", null, moshi)
val mainDeviceEncryptionKey =
@@ -1,6 +1,7 @@
package eu.darken.capod.monitor.core
import android.annotation.SuppressLint
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.debug.logging.Logging.Priority.ERROR
import eu.darken.capod.common.debug.logging.asLog
import eu.darken.capod.common.debug.logging.log
@@ -13,7 +14,7 @@ import javax.inject.Inject
class RPAChecker @Inject constructor() {
// Resolvable-Private-Address
fun verify(address: String, irk: ByteArray): Boolean = try {
fun verify(address: BluetoothAddress, irk: ByteArray): Boolean = try {
val rpa = address.split(":").map { it.toInt(16).toByte() }.reversed().toByteArray()
val prand = rpa.copyOfRange(3, 6)
val hash = rpa.copyOfRange(0, 3)
@@ -1,5 +1,6 @@
package eu.darken.capod.reaction.core.popup
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
@@ -109,7 +110,7 @@ class PopUpReaction @Inject constructor(
else -> null
}
private val connectionCoolDowns = mutableMapOf<String, Instant>()
private val connectionCoolDowns = mutableMapOf<BluetoothAddress, Instant>()
private fun monitorConnection(): Flow<Event> = reactionSettings.showPopUpOnConnection.flow
.flatMapLatest { isEnabled ->
@@ -1,37 +1,33 @@
package eu.darken.capod.main.ui.settings.general
import android.content.Context
import android.content.DialogInterface
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.darken.capod.R
import eu.darken.capod.common.bluetooth.BluetoothDevice2
class DeviceSelectionDialogFactory constructor(private val context: Context) {
class DeviceSelectionDialogFactory(private val context: Context) {
fun create(
devices: List<BluetoothDevice2>,
current: BluetoothDevice2?,
callback: (BluetoothDevice2?) -> Unit
): AlertDialog {
return MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.settings_maindevice_address_label)
): AlertDialog = MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.settings_maindevice_address_label)
val pairing = devices
.map { (it.name ?: "?") to it.address }
.plus(context.getString(R.string.settings_maindevice_address_none) to "")
val pairing = devices
.map { (it.name ?: "?") to it.address }
.plus(context.getString(R.string.settings_maindevice_address_none) to "")
setSingleChoiceItems(
pairing.map { it.first }.toTypedArray(),
pairing.indexOfFirst { it.second == current?.address ?: "" },
DialogInterface.OnClickListener { dialog, which ->
val selected = devices.firstOrNull { it.address == pairing[which].second }
callback(selected)
dialog.dismiss()
}
)
setSingleChoiceItems(
pairing.map { it.first }.toTypedArray(),
pairing.indexOfFirst { it.second == current?.address }
) { dialog, which ->
val selected = devices.firstOrNull { it.address == pairing[which].second }
callback(selected)
dialog.dismiss()
}
}.create()
}
}.create()
}
@@ -8,6 +8,7 @@ import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.bluetooth.BluetoothDevice2
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.coroutine.DispatcherProvider
@@ -146,7 +147,7 @@ class MonitorWorker @AssistedInject constructor(
.setupCommonEventHandlers(TAG) { "MonitorMode" }
.flatMapLatest { arguments ->
val monitorMode = arguments[0] as MonitorMode
val mainAddress = arguments[1] as String?
val mainAddress = arguments[1] as BluetoothAddress?
@Suppress("UNCHECKED_CAST")
val devices = arguments[2] as Collection<BluetoothDevice2>