mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Remove deviceModel property from ApplePodsFactory interface
Removed the deviceModel property from ApplePodsFactory interface and all 25 implementing classes across AirPods, Beats, and misc device factories. This simplifies the factory pattern as the model information can be derived from the concrete implementation type itself.
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
package eu.darken.capod.devices.core
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.squareup.moshi.JsonClass
|
||||
import eu.darken.capod.common.bluetooth.BluetoothAddress
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.protocol.IdentityResolvingKey
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityEncryptionKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.UUID
|
||||
|
||||
@Parcelize
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class DeviceProfile(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val name: String,
|
||||
val address: BluetoothAddress? = null,
|
||||
val model: PodDevice.Model = PodDevice.Model.UNKNOWN,
|
||||
val identityKey: IdentityResolvingKey? = null,
|
||||
val encryptionKey: ProximityEncryptionKey? = null,
|
||||
val minimumSignalQuality: Float = 0.20f,
|
||||
val isEnabled: Boolean = true
|
||||
) : Parcelable
|
||||
@@ -1,87 +0,0 @@
|
||||
package eu.darken.capod.devices.core
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DeviceProfilesRepo @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val moshi: Moshi,
|
||||
) {
|
||||
|
||||
private val preferences: SharedPreferences = context.getSharedPreferences("device_profiles", Context.MODE_PRIVATE)
|
||||
|
||||
private val _profiles = MutableStateFlow<List<DeviceProfile>>(emptyList())
|
||||
val profiles: Flow<List<DeviceProfile>> = _profiles.asStateFlow()
|
||||
|
||||
private val listType = Types.newParameterizedType(List::class.java, DeviceProfile::class.java)
|
||||
private val adapter = moshi.adapter<List<DeviceProfile>>(listType)
|
||||
|
||||
init {
|
||||
loadProfiles()
|
||||
}
|
||||
|
||||
private fun loadProfiles() {
|
||||
val json = preferences.getString(KEY_PROFILES, null)
|
||||
val loadedProfiles = if (json != null) {
|
||||
try {
|
||||
adapter.fromJson(json) ?: emptyList()
|
||||
} catch (e: Exception) {
|
||||
log(VERBOSE) { "Failed to load device profiles: $e" }
|
||||
emptyList()
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
_profiles.value = loadedProfiles
|
||||
log(VERBOSE) { "Loaded ${loadedProfiles.size} device profiles" }
|
||||
}
|
||||
|
||||
private fun saveProfiles() {
|
||||
val json = adapter.toJson(_profiles.value)
|
||||
preferences.edit().putString(KEY_PROFILES, json).apply()
|
||||
log(VERBOSE) { "Saved ${_profiles.value.size} device profiles" }
|
||||
}
|
||||
|
||||
fun addProfile(profile: DeviceProfile) {
|
||||
val updatedProfiles = _profiles.value.toMutableList()
|
||||
updatedProfiles.add(profile)
|
||||
_profiles.value = updatedProfiles
|
||||
saveProfiles()
|
||||
}
|
||||
|
||||
fun updateProfile(profile: DeviceProfile) {
|
||||
val updatedProfiles = _profiles.value.toMutableList()
|
||||
val index = updatedProfiles.indexOfFirst { it.id == profile.id }
|
||||
if (index != -1) {
|
||||
updatedProfiles[index] = profile
|
||||
_profiles.value = updatedProfiles
|
||||
saveProfiles()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeProfile(profileId: String) {
|
||||
val updatedProfiles = _profiles.value.toMutableList()
|
||||
updatedProfiles.removeAll { it.id == profileId }
|
||||
_profiles.value = updatedProfiles
|
||||
saveProfiles()
|
||||
}
|
||||
|
||||
fun getProfile(profileId: String): DeviceProfile? {
|
||||
return _profiles.value.find { it.id == profileId }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_PROFILES = "profiles"
|
||||
}
|
||||
}
|
||||
@@ -61,49 +61,53 @@ class AppleFactory @Inject constructor(
|
||||
|
||||
suspend fun create(scanResult: BleScanResult): PodDevice? = lock.withLock {
|
||||
val proximityMessage = getMessage(scanResult) ?: return@withLock null
|
||||
|
||||
var isIRKMatch = false
|
||||
val candidates = profilesRepo.profiles.first().filterIsInstance<AppleDeviceProfile>()
|
||||
var profile = candidates.firstOrNull {
|
||||
it.identityKey != null && rpaChecker.verify(scanResult.address, it.identityKey)
|
||||
}
|
||||
if (profile != null) {
|
||||
isIRKMatch = true
|
||||
log(TAG, VERBOSE) { "Got IRK match for from $profile for $scanResult" }
|
||||
}
|
||||
|
||||
val factory = podFactories.firstOrNull { it.isResponsible(proximityMessage) } ?: unknownAppleFactory
|
||||
|
||||
// TODO more checks heuristicbased
|
||||
if (profile == null) {
|
||||
profile = candidates.firstOrNull { it.model == factory.deviceModel }
|
||||
log(TAG, VERBOSE) { "Got no IRK match for from $profile for $scanResult" }
|
||||
val profiles = profilesRepo.profiles.first().filterIsInstance<AppleDeviceProfile>()
|
||||
var profile = profiles.firstOrNull {
|
||||
it.identityKey != null && rpaChecker.verify(scanResult.address, it.identityKey)
|
||||
}
|
||||
|
||||
val payload = ProximityPayload(
|
||||
val isIrkMatch = profile != null
|
||||
if (isIrkMatch) log(TAG, VERBOSE) { "IRK match for $scanResult -> $profile" }
|
||||
|
||||
var payload = ProximityPayload(
|
||||
public = ProximityPayload.Public(
|
||||
proximityMessage.data.take(9).toUByteArray()
|
||||
),
|
||||
private = run {
|
||||
if (!isIRKMatch || profile == null) return@run null
|
||||
if (proximityMessage.data.size != ProximityPairing.PAIRING_MESSAGE_LENGTH) return@run null
|
||||
|
||||
val encKey = profile.encryptionKey?.takeIf { it.isNotEmpty() }
|
||||
if (encKey == null) return@run null
|
||||
|
||||
val encrypted = proximityMessage.data.takeLast(16).toUByteArray().toByteArray()
|
||||
proximityMessageDecrypter.decrypt(encrypted, encKey)?.let {
|
||||
ProximityPayload.Private(data = it)
|
||||
}
|
||||
},
|
||||
private = null,
|
||||
)
|
||||
|
||||
if (profile != null && profile.encryptionKey != null) {
|
||||
payload = payload.copy(
|
||||
private = run {
|
||||
if (proximityMessage.data.size != ProximityPairing.PAIRING_MESSAGE_LENGTH) return@run null
|
||||
val encKey = profile.encryptionKey
|
||||
val encrypted = proximityMessage.data.takeLast(16).toUByteArray().toByteArray()
|
||||
proximityMessageDecrypter.decrypt(encrypted, encKey)?.let {
|
||||
ProximityPayload.Private(data = it)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
val tempDevice = factory.create(
|
||||
scanResult = scanResult,
|
||||
payload = payload,
|
||||
meta = ApplePods.AppleMeta(),
|
||||
)
|
||||
profile = profiles
|
||||
.filter { it.model == tempDevice.model }
|
||||
.filter { it.minimumSignalQuality <= tempDevice.signalQuality }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
factory.create(
|
||||
scanResult = scanResult,
|
||||
payload = payload,
|
||||
meta = ApplePods.AppleMeta(
|
||||
isIRKMatch = isIRKMatch,
|
||||
isIRKMatch = profile != null,
|
||||
profile = profile,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -57,8 +57,8 @@ interface ApplePods : PodDevice {
|
||||
}
|
||||
|
||||
data class AppleMeta(
|
||||
val isIRKMatch: Boolean,
|
||||
override val profile: AppleDeviceProfile?,
|
||||
val isIRKMatch: Boolean = false,
|
||||
override val profile: AppleDeviceProfile? = null,
|
||||
) : PodDevice.Meta
|
||||
|
||||
override val meta: AppleMeta
|
||||
|
||||
@@ -7,7 +7,6 @@ import eu.darken.capod.pods.core.apple.protocol.ProximityMessage
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPayload
|
||||
|
||||
interface ApplePodsFactory {
|
||||
val deviceModel: PodDevice.Model
|
||||
fun isResponsible(message: ProximityMessage): Boolean
|
||||
fun create(scanResult: BleScanResult, payload: ProximityPayload, meta: ApplePods.AppleMeta): ApplePods
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ data class AirPodsGen1(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_GEN1
|
||||
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
|
||||
@@ -42,7 +42,6 @@ data class AirPodsGen2(
|
||||
private val repo: PodHistoryRepo
|
||||
) : ApplePodsFactory {
|
||||
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_GEN2
|
||||
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
|
||||
@@ -42,7 +42,6 @@ data class AirPodsGen3(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_GEN3
|
||||
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
|
||||
@@ -42,7 +42,6 @@ data class AirPodsGen4(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4
|
||||
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
|
||||
@@ -41,7 +41,6 @@ data class AirPodsGen4Anc(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4_ANC
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ data class AirPodsMax(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_MAX
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ data class AirPodsMaxUsbc(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_MAX_USBC
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ data class AirPodsPro(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_PRO
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ data class AirPodsPro2(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_PRO2
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ data class AirPodsPro2Usbc(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.AIRPODS_PRO2_USBC
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ data class BeatsFitPro(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.BEATS_FIT_PRO
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ data class BeatsFlex(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.BEATS_FLEX
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ data class BeatsSolo3(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.BEATS_SOLO_3
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ data class BeatsStudio3(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.BEATS_STUDIO_3
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().dirty == DEVICE_CODE_DIRTY && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ data class BeatsX(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.BEATS_X
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ data class PowerBeats3(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.POWERBEATS_3
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ data class PowerBeats4(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.POWERBEATS_4
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ data class PowerBeatsPro(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.POWERBEATS_PRO
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ data class PowerBeatsPro2(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.POWERBEATS_PRO2
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ data class FakeAirPodsGen1(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_GEN1
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||
getModelInfo().full == DEVICE_CODE && length == 19
|
||||
|
||||
@@ -42,7 +42,6 @@ data class FakeAirPodsGen2(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_GEN2
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||
getModelInfo().full == DEVICE_CODE && length == 19
|
||||
|
||||
@@ -44,7 +44,6 @@ data class FakeAirPodsGen3(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_GEN3
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||
getModelInfo().full == DEVICE_CODE && length == 19
|
||||
|
||||
@@ -62,7 +62,6 @@ data class FakeAirPodsPro(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_PRO
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||
getModelInfo().full == DEVICE_CODE && length == 19
|
||||
|
||||
@@ -66,7 +66,6 @@ data class FakeAirPodsPro2(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_PRO2
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = message.run {
|
||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||
getModelInfo().full == DEVICE_CODE && length == 19
|
||||
|
||||
@@ -35,7 +35,6 @@ data class UnknownAppleDevice(
|
||||
class Factory @Inject constructor(
|
||||
private val repo: PodHistoryRepo,
|
||||
) : ApplePodsFactory {
|
||||
override val deviceModel: PodDevice.Model = PodDevice.Model.UNKNOWN
|
||||
override fun isResponsible(message: ProximityMessage): Boolean = true
|
||||
|
||||
override fun create(
|
||||
|
||||
@@ -15,7 +15,7 @@ data class AppleDeviceProfile(
|
||||
@Json(name = "label") override val label: String,
|
||||
@Json(name = "priority") override val priority: Int = 0,
|
||||
@Json(name = "model") override val model: PodDevice.Model = PodDevice.Model.UNKNOWN,
|
||||
@Json(name = "minimumSignalQuality") override val minimumSignalQuality: Float? = DeviceProfile.DEFAULT_MINIMUM_SIGNAL_QUALITY,
|
||||
@Json(name = "minimumSignalQuality") override val minimumSignalQuality: Float = DeviceProfile.DEFAULT_MINIMUM_SIGNAL_QUALITY,
|
||||
@Json(name = "identityKey") val identityKey: IdentityResolvingKey? = null,
|
||||
@Json(name = "encryptionKey") val encryptionKey: ProximityEncryptionKey? = null,
|
||||
@Json(name = "address") override val address: String? = null,
|
||||
|
||||
Reference in New Issue
Block a user