From 15141c85283c86faa38ebd4ddb8bb8fdebb08851 Mon Sep 17 00:00:00 2001 From: Matthias Urhahn Date: Wed, 18 Jan 2023 22:15:38 +0100 Subject: [PATCH] More granular pod features (#76) * Make pod features more granular Don't assume all AirPods/Beats return a correct connection state. * Refactoring * Fix refactoring regression * AirPods Gen1 don't support state detection --- .../capod/pods/core/apple/ApplePodsFactory.kt | 6 +- .../{DualAirPods.kt => DualApplePods.kt} | 24 +---- .../pods/core/apple/DualApplePodsFactory.kt | 10 +- .../pods/core/apple/airpods/AirPodsGen1.kt | 8 +- .../pods/core/apple/airpods/AirPodsGen2.kt | 10 +- .../pods/core/apple/airpods/AirPodsGen3.kt | 11 ++- .../pods/core/apple/airpods/AirPodsMax.kt | 4 +- .../pods/core/apple/airpods/AirPodsPro.kt | 8 +- .../pods/core/apple/airpods/AirPodsPro2.kt | 8 +- .../apple/airpods/HasStateDetectionAirPods.kt | 27 ++++++ .../pods/core/apple/beats/BeatsFitPro.kt | 8 +- .../pods/core/apple/beats/PowerBeatsPro.kt | 8 +- .../pods/core/apple/misc/FakeAirPodsPro2.kt | 4 +- .../reaction/core/autoconnect/AutoConnect.kt | 4 +- .../reaction/core/popup/PopUpReaction.kt | 12 +-- .../pods/core/apple/AirPodsFactoryTest.kt | 4 +- .../pods/core/apple/DualApplePodsTest.kt | 95 ++++++++++--------- .../core/apple/airpods/AirPodsGen1Test.kt | 6 +- .../core/apple/airpods/AirPodsGen2Test.kt | 6 +- .../core/apple/airpods/AirPodsGen3Test.kt | 10 +- .../ui/overview/cards/pods/DualPodsCardVH.kt | 4 +- .../ui/overview/cards/pods/DualPodsCardVH.kt | 8 +- .../ui/MonitorNotificationViewFactory.kt | 6 +- .../reaction/ui/popup/PopUpPodViewFactory.kt | 6 +- 24 files changed, 152 insertions(+), 145 deletions(-) rename app-common/src/main/java/eu/darken/capod/pods/core/apple/{DualAirPods.kt => DualApplePods.kt} (78%) create mode 100644 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/HasStateDetectionAirPods.kt diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/ApplePodsFactory.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/ApplePodsFactory.kt index a3ed4a86..5eedcb60 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/ApplePodsFactory.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/ApplePodsFactory.kt @@ -79,13 +79,13 @@ abstract class ApplePodsFactory(private val tag: String) { .mapNotNull { it.batteryCasePercent } .lastOrNull() - fun KnownDevice.getLatestCaseLidState(basic: DualAirPods): DualAirPods.LidState? { - val definitive = setOf(DualAirPods.LidState.OPEN, DualAirPods.LidState.CLOSED) + fun KnownDevice.getLatestCaseLidState(basic: DualApplePods): DualApplePods.LidState? { + val definitive = setOf(DualApplePods.LidState.OPEN, DualApplePods.LidState.CLOSED) if (definitive.contains(basic.caseLidState)) return null return history .filterIsInstance() // TODO why is this AirPodsPro specific here? - .lastOrNull { it.caseLidState != DualAirPods.LidState.NOT_IN_CASE } + .lastOrNull { it.caseLidState != DualApplePods.LidState.NOT_IN_CASE } ?.caseLidState } diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualAirPods.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt similarity index 78% rename from app-common/src/main/java/eu/darken/capod/pods/core/apple/DualAirPods.kt rename to app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt index 754f3c84..3cc17948 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualAirPods.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt @@ -1,8 +1,5 @@ package eu.darken.capod.pods.core.apple -import android.content.Context -import androidx.annotation.StringRes -import eu.darken.capod.common.R import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.isBitSet import eu.darken.capod.common.lowerNibble @@ -10,8 +7,8 @@ import eu.darken.capod.common.upperNibble import eu.darken.capod.pods.core.* import eu.darken.capod.pods.core.DualPodDevice.Pod -interface DualAirPods : ApplePods, HasChargeDetectionDual, DualPodDevice, HasEarDetectionDual, HasCase, - HasStateDetection, HasDualMicrophone, HasAppleColor { +interface DualApplePods : ApplePods, HasChargeDetectionDual, DualPodDevice, HasEarDetectionDual, HasCase, + HasDualMicrophone, HasAppleColor { val primaryPod: Pod get() = when (rawStatus.isBitSet(5)) { @@ -142,21 +139,4 @@ interface DualAirPods : ApplePods, HasChargeDetectionDual, DualPodDevice, HasEar UNKNOWN(0xFF..0xFF); } - override val state: ConnectionState - get() = ConnectionState.values().firstOrNull { rawSuffix == it.raw } ?: ConnectionState.UNKNOWN - - enum class ConnectionState(val raw: UByte?, @StringRes val labelRes: Int) : HasStateDetection.State { - DISCONNECTED(0x00, R.string.pods_connection_state_disconnected_label), - IDLE(0x04, R.string.pods_connection_state_idle_label), - MUSIC(0x05, R.string.pods_connection_state_music_label), - CALL(0x06, R.string.pods_connection_state_call_label), - RINGING(0x07, R.string.pods_connection_state_ringing_label), - HANGING_UP(0x09, R.string.pods_connection_state_hanging_up_label), - UNKNOWN(null, R.string.pods_connection_state_unknown_label); - - override fun getLabel(context: Context): String = context.getString(labelRes) - - constructor(raw: Int, @StringRes labelRes: Int) : this(raw.toUByte(), labelRes) - } - } \ No newline at end of file diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePodsFactory.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePodsFactory.kt index 423d4d56..c67d50f0 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePodsFactory.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/DualApplePodsFactory.kt @@ -4,9 +4,9 @@ import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG import eu.darken.capod.common.debug.logging.log import eu.darken.capod.pods.core.PodDevice -abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory(tag) { +abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory(tag) { - fun DualAirPods.getCaseMatchMarkings() = SplitPodsMarkings( + fun DualApplePods.getCaseMatchMarkings() = SplitPodsMarkings( leftPodBattery = batteryLeftPodPercent, rightPodBattery = batteryRightPodPercent, microPhoneLeft = isLeftPodMicrophone, @@ -31,17 +31,17 @@ abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory< val model: PodDevice.Model, ) - private fun Collection.findSplitPodsMatch(device: DualAirPods): Collection { + private fun Collection.findSplitPodsMatch(device: DualApplePods): Collection { val target = device.getCaseMatchMarkings() return filter { known -> known.history - .filterIsInstance() + .filterIsInstance() .any { it.getCaseMatchMarkings() == target } } } - override fun searchHistory(current: DualAirPods): KnownDevice? { + override fun searchHistory(current: DualApplePods): KnownDevice? { val basicResult = super.searchHistory(current) val caseIgnored = knownDevices.values.findSplitPodsMatch(current) diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt index 2de5284d..68e9d362 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt @@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -20,15 +20,15 @@ data class AirPodsGen1 constructor( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null -) : DualAirPods { + private val cachedCaseState: DualApplePods.LidState? = null +) : DualApplePods { override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN1 override val batteryCasePercent: Float? get() = super.batteryCasePercent ?: cachedBatteryPercentage - override val caseLidState: DualAirPods.LidState + override val caseLidState: DualApplePods.LidState get() = cachedCaseState ?: super.caseLidState override val rssi: Int diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt index 515fbf06..10b69825 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt @@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -20,19 +20,19 @@ data class AirPodsGen2 constructor( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null -) : DualAirPods { + private val cachedCaseState: DualApplePods.LidState? = null +) : DualApplePods, HasStateDetectionAirPods { override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN2 override val batteryCasePercent: Float? get() = super.batteryCasePercent ?: cachedBatteryPercentage - override val caseLidState: DualAirPods.LidState + override val caseLidState: DualApplePods.LidState get() = cachedCaseState ?: super.caseLidState override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi class Factory @Inject constructor() : DualApplePodsFactory(TAG) { diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3.kt index 3d343c13..bbe7b9fa 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3.kt @@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -20,18 +20,19 @@ data class AirPodsGen3 constructor( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null -) : DualAirPods { + private val cachedCaseState: DualApplePods.LidState? = null +) : DualApplePods, HasStateDetectionAirPods { + override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN3 override val batteryCasePercent: Float? get() = super.batteryCasePercent ?: cachedBatteryPercentage - override val caseLidState: DualAirPods.LidState + override val caseLidState: DualApplePods.LidState get() = cachedCaseState ?: super.caseLidState override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi class Factory @Inject constructor() : DualApplePodsFactory(TAG) { diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt index a33a5c44..0d718fa2 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt @@ -21,12 +21,12 @@ data class AirPodsMax( override val proximityMessage: ProximityPairing.Message, override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, -) : SingleApplePods, HasEarDetection { +) : SingleApplePods, HasEarDetection, HasStateDetectionAirPods { override val model: PodDevice.Model = PodDevice.Model.AIRPODS_MAX override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi val isHeadphonesBeingWorn: Boolean get() = rawStatus.isBitSet(1) diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt index 29163a2b..35c82a2e 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt @@ -6,8 +6,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods -import eu.darken.capod.pods.core.apple.DualAirPods.LidState +import eu.darken.capod.pods.core.apple.DualApplePods +import eu.darken.capod.pods.core.apple.DualApplePods.LidState import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -24,7 +24,7 @@ data class AirPodsPro( private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, private val cachedCaseState: LidState? = null -) : DualAirPods { +) : DualApplePods, HasStateDetectionAirPods { override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO @@ -51,7 +51,7 @@ data class AirPodsPro( get() = cachedCaseState ?: super.caseLidState override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi class Factory @Inject constructor() : DualApplePodsFactory(TAG) { diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2.kt index fcf59908..c6de800e 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2.kt @@ -6,8 +6,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods -import eu.darken.capod.pods.core.apple.DualAirPods.LidState +import eu.darken.capod.pods.core.apple.DualApplePods +import eu.darken.capod.pods.core.apple.DualApplePods.LidState import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -24,7 +24,7 @@ data class AirPodsPro2( private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, private val cachedCaseState: LidState? = null -) : DualAirPods { +) : DualApplePods, HasStateDetectionAirPods { override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO2 @@ -51,7 +51,7 @@ data class AirPodsPro2( get() = cachedCaseState ?: super.caseLidState override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi class Factory @Inject constructor() : DualApplePodsFactory(TAG) { diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/HasStateDetectionAirPods.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/HasStateDetectionAirPods.kt new file mode 100644 index 00000000..92781a74 --- /dev/null +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/HasStateDetectionAirPods.kt @@ -0,0 +1,27 @@ +package eu.darken.capod.pods.core.apple.airpods + +import android.content.Context +import androidx.annotation.StringRes +import eu.darken.capod.common.R +import eu.darken.capod.pods.core.HasStateDetection +import eu.darken.capod.pods.core.apple.ApplePods + +interface HasStateDetectionAirPods : HasStateDetection, ApplePods { + + override val state: ConnectionState + get() = ConnectionState.values().firstOrNull { rawSuffix == it.raw } ?: ConnectionState.UNKNOWN + + enum class ConnectionState(val raw: UByte?, @StringRes val labelRes: Int) : HasStateDetection.State { + DISCONNECTED(0x00, R.string.pods_connection_state_disconnected_label), + IDLE(0x04, R.string.pods_connection_state_idle_label), + MUSIC(0x05, R.string.pods_connection_state_music_label), + CALL(0x06, R.string.pods_connection_state_call_label), + RINGING(0x07, R.string.pods_connection_state_ringing_label), + HANGING_UP(0x09, R.string.pods_connection_state_hanging_up_label), + UNKNOWN(null, R.string.pods_connection_state_unknown_label); + + override fun getLabel(context: Context): String = context.getString(labelRes) + + constructor(raw: Int, @StringRes labelRes: Int) : this(raw.toUByte(), labelRes) + } +} \ No newline at end of file diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFitPro.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFitPro.kt index 14e102dd..c38597ba 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFitPro.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFitPro.kt @@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -20,15 +20,15 @@ data class BeatsFitPro( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null -) : DualAirPods { + private val cachedCaseState: DualApplePods.LidState? = null +) : DualApplePods { override val model: PodDevice.Model = PodDevice.Model.BEATS_FIT_PRO override val batteryCasePercent: Float? get() = super.batteryCasePercent ?: cachedBatteryPercentage - override val caseLidState: DualAirPods.LidState + override val caseLidState: DualApplePods.LidState get() = cachedCaseState ?: super.caseLidState override val rssi: Int diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt index 4792a081..ce3e3045 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt @@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.ApplePods -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.DualApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant @@ -20,15 +20,15 @@ data class PowerBeatsPro( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null -) : DualAirPods { + private val cachedCaseState: DualApplePods.LidState? = null +) : DualApplePods { override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_PRO override val batteryCasePercent: Float? get() = super.batteryCasePercent ?: cachedBatteryPercentage - override val caseLidState: DualAirPods.LidState + override val caseLidState: DualApplePods.LidState get() = cachedCaseState ?: super.caseLidState override val rssi: Int diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro2.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro2.kt index 3f6188f1..8179e208 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro2.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro2.kt @@ -11,7 +11,7 @@ import eu.darken.capod.common.upperNibble import eu.darken.capod.pods.core.* import eu.darken.capod.pods.core.apple.ApplePods import eu.darken.capod.pods.core.apple.ApplePodsFactory -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant import javax.inject.Inject @@ -30,7 +30,7 @@ data class FakeAirPodsPro2 constructor( override val confidence: Float = PodDevice.BASE_CONFIDENCE, private val rssiAverage: Int? = null, private val cachedBatteryPercentage: Float? = null, - private val cachedCaseState: DualAirPods.LidState? = null, + private val cachedCaseState: DualApplePods.LidState? = null, ) : ApplePods, HasChargeDetectionDual, DualPodDevice, HasEarDetectionDual, HasCase { override val model: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_PRO2 diff --git a/app-common/src/main/java/eu/darken/capod/reaction/core/autoconnect/AutoConnect.kt b/app-common/src/main/java/eu/darken/capod/reaction/core/autoconnect/AutoConnect.kt index 7fc7a8b6..5df1994a 100644 --- a/app-common/src/main/java/eu/darken/capod/reaction/core/autoconnect/AutoConnect.kt +++ b/app-common/src/main/java/eu/darken/capod/reaction/core/autoconnect/AutoConnect.kt @@ -10,7 +10,7 @@ import eu.darken.capod.main.core.GeneralSettings import eu.darken.capod.monitor.core.PodMonitor import eu.darken.capod.pods.core.HasEarDetection import eu.darken.capod.pods.core.HasEarDetectionDual -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.reaction.core.ReactionSettings import kotlinx.coroutines.flow.* import javax.inject.Inject @@ -69,7 +69,7 @@ class AutoConnect @Inject constructor( val conditionFulfilled = when (condition) { AutoConnectCondition.WHEN_SEEN -> true AutoConnectCondition.CASE_OPEN -> when (mainDevice) { - is DualAirPods -> mainDevice.caseLidState == DualAirPods.LidState.OPEN + is DualApplePods -> mainDevice.caseLidState == DualApplePods.LidState.OPEN else -> true } AutoConnectCondition.IN_EAR -> when (mainDevice) { diff --git a/app-common/src/main/java/eu/darken/capod/reaction/core/popup/PopUpReaction.kt b/app-common/src/main/java/eu/darken/capod/reaction/core/popup/PopUpReaction.kt index 834e6d0c..015470f5 100644 --- a/app-common/src/main/java/eu/darken/capod/reaction/core/popup/PopUpReaction.kt +++ b/app-common/src/main/java/eu/darken/capod/reaction/core/popup/PopUpReaction.kt @@ -7,7 +7,7 @@ import eu.darken.capod.common.flow.setupCommonEventHandlers import eu.darken.capod.common.flow.withPrevious import eu.darken.capod.monitor.core.PodMonitor import eu.darken.capod.pods.core.PodDevice -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.reaction.core.ReactionSettings import kotlinx.coroutines.flow.* import java.time.Duration @@ -34,7 +34,7 @@ class PopUpReaction @Inject constructor( .withPrevious() .setupCommonEventHandlers(TAG) { "monitor" } .mapNotNull { (previous, current) -> - if (previous !is DualAirPods? || current !is DualAirPods) { + if (previous !is DualApplePods? || current !is DualApplePods) { return@mapNotNull null } log(TAG, VERBOSE) { @@ -57,8 +57,8 @@ class PopUpReaction @Inject constructor( tryPopWindow(current) } - private suspend fun tryPopWindow(current: DualAirPods): Event? = when { - current.caseLidState == DualAirPods.LidState.OPEN -> { + private suspend fun tryPopWindow(current: DualApplePods): Event? = when { + current.caseLidState == DualApplePods.LidState.OPEN -> { log(TAG, INFO) { "Show popup" } val now = Instant.now() @@ -74,9 +74,9 @@ class PopUpReaction @Inject constructor( null } } - current.caseLidState != DualAirPods.LidState.OPEN -> { + current.caseLidState != DualApplePods.LidState.OPEN -> { when (current.caseLidState) { - DualAirPods.LidState.CLOSED -> { + DualApplePods.LidState.CLOSED -> { log(TAG, INFO) { "Lid was actively closed, resetting cooldown." } coolDowns.remove(current.identifier) } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/AirPodsFactoryTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/AirPodsFactoryTest.kt index 870fe33f..7a589158 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/AirPodsFactoryTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/AirPodsFactoryTest.kt @@ -14,14 +14,14 @@ class AirPodsFactoryTest : BaseAirPodsTest() { @Test fun `create AirPodsGen1`() = runTest { - create("07 19 01 02 20 55 AA 56 31 00 00 6F E4 DF 10 AF 10 60 81 03 3B 76 D9 C7 11 22 88") { + create("07 19 01 02 20 55 AA 56 31 00 00 6F E4 DF 10 AF 10 60 81 03 3B 76 D9 C7 11 22 88") { this shouldBe instanceOf() } } @Test fun `create AirPodsPro`() = runTest { - create("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") { + create("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") { this shouldBe instanceOf() } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/DualApplePodsTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/DualApplePodsTest.kt index 0c531391..25570ba6 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/DualApplePodsTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/DualApplePodsTest.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple +import eu.darken.capod.pods.core.apple.airpods.HasStateDetectionAirPods import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test @@ -8,7 +9,7 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test bit mapping`() = runTest { - create("07 19 01 0E 20 54 AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 54 AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { rawPrefix shouldBe 0x01.toUByte() rawDeviceModel shouldBe 0x0e20.toUShort() @@ -24,13 +25,13 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - active microphone`() = runTest { - create("07 19 01 0E 20 >2B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >2B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00101011 // --^----- isLeftPodMicrophone shouldBe true isRightPodMicrophone shouldBe false } - create("07 19 01 0E 20 >0B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >0B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00001011 // --^----- isLeftPodMicrophone shouldBe false @@ -41,24 +42,24 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - left pod ear status`() = runTest { // Left Pod primary - create("07 19 01 0E 20 >22< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >22< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00100010 // 765432¹0 isLeftPodInEar shouldBe true } - create("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00100000 // 765432¹0 isLeftPodInEar shouldBe false } // Right Pod is primary - create("07 19 01 0E 20 >09< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >09< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00001001 // 7654³210 isLeftPodInEar shouldBe true } - create("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00000001 // 7654³210 isLeftPodInEar shouldBe false @@ -68,24 +69,24 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - right pod ear status`() = runTest { // Left Pod primary - create("07 19 01 0E 20 >29< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >29< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00101001 // 7654³210 isRightPodInEar shouldBe true } - create("07 19 01 0E 20 >21< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >21< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00100001 // 7654³210 isRightPodInEar shouldBe false } // Right Pod is primary - create("07 19 01 0E 20 >03< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >03< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00000011 // 765432¹0 isRightPodInEar shouldBe true } - create("07 19 01 0E 20 >01< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { + create("07 19 01 0E 20 >01< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") { // 00000001 // 765432¹0 isRightPodInEar shouldBe false @@ -95,13 +96,13 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - battery status`() = runTest { // Right Pod is primary - create("07 19 01 0E 20 0B >98< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") { + create("07 19 01 0E 20 0B >98< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") { // 88 10001000 batteryLeftPodPercent shouldBe 0.9f batteryRightPodPercent shouldBe 0.8f } // Left Pod primary - create("07 19 01 0E 20 2B >89< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") { + create("07 19 01 0E 20 2B >89< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") { // F8 11111000 batteryLeftPodPercent shouldBe 0.9f batteryRightPodPercent shouldBe 0.8f @@ -114,13 +115,13 @@ class DualApplePodsTest : BaseAirPodsTest() { * Right pod is charging */ // This is the left - create("07 19 01 0E 20 51 89 >94< 52 00 00 F4 89 82 6D 3E 27 7F 26 62 57 D0 E2 A6 49 E9 35") { + create("07 19 01 0E 20 51 89 >94< 52 00 00 F4 89 82 6D 3E 27 7F 26 62 57 D0 E2 A6 49 E9 35") { // 1001 0100 isLeftPodCharging shouldBe false isRightPodCharging shouldBe true } // This is the right - create("07 19 01 0E 20 31 98 >A4< 01 00 00 31 B9 A0 C4 80 CD D1 CF B9 3A 9A 6D 48 31 08 EB") { + create("07 19 01 0E 20 31 98 >A4< 01 00 00 31 B9 A0 C4 80 CD D1 CF B9 3A 9A 6D 48 31 08 EB") { // 1010 0100 isLeftPodCharging shouldBe false isRightPodCharging shouldBe true @@ -130,26 +131,26 @@ class DualApplePodsTest : BaseAirPodsTest() { * Left pod is charging */ // This is the left - create("07 19 01 0E 20 71 98 >94< 52 00 05 A5 37 31 B2 BD 42 68 0C 64 FD 00 99 4A E5 3E F4") { + create("07 19 01 0E 20 71 98 >94< 52 00 05 A5 37 31 B2 BD 42 68 0C 64 FD 00 99 4A E5 3E F4") { // 1001 0100 isLeftPodCharging shouldBe true isRightPodCharging shouldBe false } // This is the right - create("07 19 01 0E 20 11 89 >A4< 04 00 04 BA 79 1B C0 65 69 C6 9F 19 6E 37 7D 6D 86 8D D9") { + create("07 19 01 0E 20 11 89 >A4< 04 00 04 BA 79 1B C0 65 69 C6 9F 19 6E 37 7D 6D 86 8D D9") { // 1010 0100 isLeftPodCharging shouldBe true isRightPodCharging shouldBe false } // Both charging - create("07 19 01 0E 20 55 88 >B4< 59 00 05 4B FC DF 68 28 A5 45 52 65 9C FE 51 86 3A B5 DB") { + create("07 19 01 0E 20 55 88 >B4< 59 00 05 4B FC DF 68 28 A5 45 52 65 9C FE 51 86 3A B5 DB") { // 1011 0100 isLeftPodCharging shouldBe true isRightPodCharging shouldBe true } // Both not charging - create("07 19 01 0E 20 00 F8 >8F< 03 00 05 4C 0F A0 C4 05 24 DD EB AF 92 99 FD 54 B1 06 48") { + create("07 19 01 0E 20 00 F8 >8F< 03 00 05 4C 0F A0 C4 05 24 DD EB AF 92 99 FD 54 B1 06 48") { // 1000 1111 isLeftPodCharging shouldBe false isRightPodCharging shouldBe false @@ -158,11 +159,11 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - case charging`() = runTest { - create("07 19 01 0E 20 75 99 >B4< 31 00 05 77 C8 BA 0C 4E 1F BE AD 70 C5 40 71 D2 E9 17 A2") { + create("07 19 01 0E 20 75 99 >B4< 31 00 05 77 C8 BA 0C 4E 1F BE AD 70 C5 40 71 D2 E9 17 A2") { // 0011 0011 isCaseCharging shouldBe false } - create("07 19 01 0E 20 75 A9 >F4< 51 00 05 A0 37 92 35 49 79 CC DC 27 94 8E FB 72 12 94 52") { + create("07 19 01 0E 20 75 A9 >F4< 51 00 05 A0 37 92 35 49 79 CC DC 27 94 8E FB 72 12 94 52") { // 0101 0011 isCaseCharging shouldBe true } @@ -171,75 +172,75 @@ class DualApplePodsTest : BaseAirPodsTest() { @Test fun `test AirPodDevice - case lid test`() = runTest { // Lid open - create("07 19 01 0E 20 55 AA B4 >31< 00 00 A1 D0 BD 82 D3 52 86 CA FC 11 62 DC 42 C6 92 8E") { + create("07 19 01 0E 20 55 AA B4 >31< 00 00 A1 D0 BD 82 D3 52 86 CA FC 11 62 DC 42 C6 92 8E") { // 31 0011 0001 - caseLidState shouldBe DualAirPods.LidState.OPEN + caseLidState shouldBe DualApplePods.LidState.OPEN } // Lid open, left pod in case - create("07 19 01 0E 20 51 9A 93 >31< 00 00 95 D0 A5 D7 E3 F4 F1 38 38 99 61 3B 57 95 37 B7") { + create("07 19 01 0E 20 51 9A 93 >31< 00 00 95 D0 A5 D7 E3 F4 F1 38 38 99 61 3B 57 95 37 B7") { // 31 0011 0001 - caseLidState shouldBe DualAirPods.LidState.OPEN + caseLidState shouldBe DualApplePods.LidState.OPEN } // Lid open, left pod in case - create("07 19 01 0E 20 71 A9 92 31 00 00 DB 48 7F 32 8C CE 80 6F D9 27 98 D6 76 45 9D 62") { + create("07 19 01 0E 20 71 A9 92 31 00 00 DB 48 7F 32 8C CE 80 6F D9 27 98 D6 76 45 9D 62") { // 31 0011 0001 - caseLidState shouldBe DualAirPods.LidState.OPEN + caseLidState shouldBe DualApplePods.LidState.OPEN } // Lid just closed - create("07 19 01 0E 20 55 AA B4 >39< 00 00 08 A6 DB 99 E0 5E 14 85 E5 C2 0B 68 D7 FF C3 A1") { + create("07 19 01 0E 20 55 AA B4 >39< 00 00 08 A6 DB 99 E0 5E 14 85 E5 C2 0B 68 D7 FF C3 A1") { // 39 0011 1001 - caseLidState shouldBe DualAirPods.LidState.CLOSED + caseLidState shouldBe DualApplePods.LidState.CLOSED } // Lid closed - create("07 19 01 0E 20 55 AA B4 38 00 00 F3 F7 08 3B 98 09 C0 DD E4 BD BD 84 55 56 8B 81") { + create("07 19 01 0E 20 55 AA B4 38 00 00 F3 F7 08 3B 98 09 C0 DD E4 BD BD 84 55 56 8B 81") { // 38 0011 1000 - caseLidState shouldBe DualAirPods.LidState.CLOSED + caseLidState shouldBe DualApplePods.LidState.CLOSED } // Lid closed, right pod in case - create("07 19 01 0E 20 51 9A 93 >38< 00 00 3A D8 85 76 B0 91 48 31 DA FF 6C 4A 2B C2 67 F4") { + create("07 19 01 0E 20 51 9A 93 >38< 00 00 3A D8 85 76 B0 91 48 31 DA FF 6C 4A 2B C2 67 F4") { // 38 0011 1000 - caseLidState shouldBe DualAirPods.LidState.CLOSED + caseLidState shouldBe DualApplePods.LidState.CLOSED } // Lid closed, left pod in case - create("07 19 01 0E 20 71 A9 92 38 00 00 44 91 C4 8B 85 98 DD 55 4E 6A CA BC B5 CA 8D 37") { + create("07 19 01 0E 20 71 A9 92 38 00 00 44 91 C4 8B 85 98 DD 55 4E 6A CA BC B5 CA 8D 37") { // 38 0011 1000 - caseLidState shouldBe DualAirPods.LidState.CLOSED + caseLidState shouldBe DualApplePods.LidState.CLOSED } } @Test fun `test AirPodDevice - connection state`() = runTest { // Disconnected - create("07 19 01 0E 20 2B AA 8F 01 00 >00< 62 D4 BB F1 A7 F8 64 98 D2 C8 BD 7B 3A EF 2E 15") { + create("07 19 01 0E 20 2B AA 8F 01 00 >00< 62 D4 BB F1 A7 F8 64 98 D2 C8 BD 7B 3A EF 2E 15") { // 31 0011 0001 - state shouldBe DualAirPods.ConnectionState.DISCONNECTED + state shouldBe HasStateDetectionAirPods.ConnectionState.DISCONNECTED } // Connected idle - create("07 19 01 0E 20 2B AA 8F 01 00 >04< 1D 69 69 9C C2 51 F3 1F BF 6E 45 DA 90 4A A3 E3") { + create("07 19 01 0E 20 2B AA 8F 01 00 >04< 1D 69 69 9C C2 51 F3 1F BF 6E 45 DA 90 4A A3 E3") { // 39 0011 1001 - state shouldBe DualAirPods.ConnectionState.IDLE + state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE } // Connected and playing music - create("07 19 01 0E 20 2B A9 8F 01 00 >05< 14 F7 CB 49 9F D3 B3 22 77 D2 22 F1 74 8C AC A6") { + create("07 19 01 0E 20 2B A9 8F 01 00 >05< 14 F7 CB 49 9F D3 B3 22 77 D2 22 F1 74 8C AC A6") { // 38 0011 1000 - state shouldBe DualAirPods.ConnectionState.MUSIC + state shouldBe HasStateDetectionAirPods.ConnectionState.MUSIC } // Connected and call active - create("07 19 01 0E 20 2B 99 8F 01 00 >06< 0F 4B 43 25 E0 4A 73 63 14 22 C2 3C 89 13 BD 97") { + create("07 19 01 0E 20 2B 99 8F 01 00 >06< 0F 4B 43 25 E0 4A 73 63 14 22 C2 3C 89 13 BD 97") { // 38 0011 1000 - state shouldBe DualAirPods.ConnectionState.CALL + state shouldBe HasStateDetectionAirPods.ConnectionState.CALL } // Connected and call active - create("07 19 01 0E 20 2B 99 8F 01 00 >07< E7 DF 76 44 85 B5 30 F4 95 14 02 DC A1 A4 8A 09") { + create("07 19 01 0E 20 2B 99 8F 01 00 >07< E7 DF 76 44 85 B5 30 F4 95 14 02 DC A1 A4 8A 09") { // 38 0011 1000 - state shouldBe DualAirPods.ConnectionState.RINGING + state shouldBe HasStateDetectionAirPods.ConnectionState.RINGING } // Switching? - create("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") { + create("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") { // 38 0011 1000 - state shouldBe DualAirPods.ConnectionState.HANGING_UP + state shouldBe HasStateDetectionAirPods.ConnectionState.HANGING_UP } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1Test.kt index 8bcb23e9..d1cdf035 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1Test.kt @@ -2,7 +2,7 @@ package eu.darken.capod.pods.core.apple.airpods import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.HasAppleColor import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -35,9 +35,7 @@ class AirPodsGen1Test : BaseAirPodsTest() { isRightPodInEar shouldBe false batteryCasePercent shouldBe 0.6f - caseLidState shouldBe DualAirPods.LidState.OPEN - - state shouldBe DualAirPods.ConnectionState.DISCONNECTED + caseLidState shouldBe DualApplePods.LidState.OPEN podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2Test.kt index b4ce5960..fac830a4 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2Test.kt @@ -2,7 +2,7 @@ package eu.darken.capod.pods.core.apple.airpods import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.HasAppleColor import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -34,9 +34,9 @@ class AirPodsGen2Test : BaseAirPodsTest() { isRightPodInEar shouldBe true batteryCasePercent shouldBe null - caseLidState shouldBe DualAirPods.LidState.NOT_IN_CASE + caseLidState shouldBe DualApplePods.LidState.NOT_IN_CASE - state shouldBe DualAirPods.ConnectionState.MUSIC + state shouldBe HasStateDetectionAirPods.ConnectionState.MUSIC podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3Test.kt index fd42ac2c..95a80bab 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen3Test.kt @@ -2,7 +2,7 @@ package eu.darken.capod.pods.core.apple.airpods import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.HasAppleColor import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -34,9 +34,9 @@ class AirPodsGen3Test : BaseAirPodsTest() { isRightPodInEar shouldBe false batteryCasePercent shouldBe 0.9f - caseLidState shouldBe DualAirPods.LidState.OPEN + caseLidState shouldBe DualApplePods.LidState.OPEN - state shouldBe DualAirPods.ConnectionState.IDLE + state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name @@ -58,9 +58,9 @@ class AirPodsGen3Test : BaseAirPodsTest() { isRightPodInEar shouldBe true batteryCasePercent shouldBe null - caseLidState shouldBe DualAirPods.LidState.NOT_IN_CASE + caseLidState shouldBe DualApplePods.LidState.NOT_IN_CASE - state shouldBe DualAirPods.ConnectionState.UNKNOWN + state shouldBe HasStateDetectionAirPods.ConnectionState.UNKNOWN podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name } diff --git a/app-wear/src/main/java/eu/darken/capod/wear/ui/overview/cards/pods/DualPodsCardVH.kt b/app-wear/src/main/java/eu/darken/capod/wear/ui/overview/cards/pods/DualPodsCardVH.kt index 09b1d87c..3b5dc08e 100644 --- a/app-wear/src/main/java/eu/darken/capod/wear/ui/overview/cards/pods/DualPodsCardVH.kt +++ b/app-wear/src/main/java/eu/darken/capod/wear/ui/overview/cards/pods/DualPodsCardVH.kt @@ -8,7 +8,7 @@ import eu.darken.capod.R import eu.darken.capod.common.lists.binding import eu.darken.capod.databinding.OverviewPodsDualItemBinding import eu.darken.capod.pods.core.* -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import java.time.Instant class DualPodsCardVH(parent: ViewGroup) : @@ -32,7 +32,7 @@ class DualPodsCardVH(parent: ViewGroup) : if (item.isMainPod) setTypeface(null, Typeface.BOLD) else setTypeface(null, Typeface.NORMAL) - if (device is DualAirPods && item.showDebug) { + if (device is DualApplePods && item.showDebug) { append(" [${device.primaryPod.name}]") } } diff --git a/app/src/main/java/eu/darken/capod/main/ui/overview/cards/pods/DualPodsCardVH.kt b/app/src/main/java/eu/darken/capod/main/ui/overview/cards/pods/DualPodsCardVH.kt index a14dece9..9883c2d3 100644 --- a/app/src/main/java/eu/darken/capod/main/ui/overview/cards/pods/DualPodsCardVH.kt +++ b/app/src/main/java/eu/darken/capod/main/ui/overview/cards/pods/DualPodsCardVH.kt @@ -8,8 +8,8 @@ import eu.darken.capod.R import eu.darken.capod.common.lists.binding import eu.darken.capod.databinding.OverviewPodsDualItemBinding import eu.darken.capod.pods.core.* -import eu.darken.capod.pods.core.apple.DualAirPods -import eu.darken.capod.pods.core.apple.DualAirPods.LidState +import eu.darken.capod.pods.core.apple.DualApplePods +import eu.darken.capod.pods.core.apple.DualApplePods.LidState import java.time.Duration import java.time.Instant @@ -34,7 +34,7 @@ class DualPodsCardVH(parent: ViewGroup) : if (item.isMainPod) setTypeface(null, Typeface.BOLD) else setTypeface(null, Typeface.NORMAL) - if (device is DualAirPods && item.showDebug) { + if (device is DualApplePods && item.showDebug) { append(" [${device.primaryPod.name}]") } } @@ -129,7 +129,7 @@ class DualPodsCardVH(parent: ViewGroup) : // Case lid state device.apply { - if (this is DualAirPods) { + if (this is DualApplePods) { podCaseLidLabel.text = when (caseLidState) { LidState.OPEN -> context.getString(R.string.pods_case_status_open_label) LidState.CLOSED -> context.getString(R.string.pods_case_status_closed_label) diff --git a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt index d1289df5..e63f570f 100644 --- a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt +++ b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt @@ -6,7 +6,7 @@ import android.widget.RemoteViews import dagger.hilt.android.qualifiers.ApplicationContext import eu.darken.capod.R import eu.darken.capod.pods.core.* -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.SingleApplePods import javax.inject.Inject @@ -16,12 +16,12 @@ class MonitorNotificationViewFactory @Inject constructor( ) { fun createContentView(device: PodDevice): RemoteViews = when (device) { - is DualAirPods -> createDualApplePods(device) + is DualApplePods -> createDualApplePods(device) is SingleApplePods -> createSingleApplePods(device) else -> createUnknownDevice(device) } - private fun createDualApplePods(device: DualAirPods): RemoteViews = RemoteViews( + private fun createDualApplePods(device: DualApplePods): RemoteViews = RemoteViews( context.packageName, R.layout.monitor_notification_dual_pods_small ).apply { diff --git a/app/src/main/java/eu/darken/capod/reaction/ui/popup/PopUpPodViewFactory.kt b/app/src/main/java/eu/darken/capod/reaction/ui/popup/PopUpPodViewFactory.kt index cfdd0946..034471b4 100644 --- a/app/src/main/java/eu/darken/capod/reaction/ui/popup/PopUpPodViewFactory.kt +++ b/app/src/main/java/eu/darken/capod/reaction/ui/popup/PopUpPodViewFactory.kt @@ -12,7 +12,7 @@ import eu.darken.capod.common.debug.autoreport.DebugSettings import eu.darken.capod.databinding.PopupNotificationDualPodsBinding import eu.darken.capod.databinding.PopupNotificationSinglePodsBinding import eu.darken.capod.pods.core.* -import eu.darken.capod.pods.core.apple.DualAirPods +import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.SingleApplePods import javax.inject.Inject @@ -26,13 +26,13 @@ class PopUpPodViewFactory @Inject constructor( private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater fun createContentView(parent: ViewGroup, device: PodDevice): View = when (device) { - is DualAirPods -> createDualApplePods(parent, device) + is DualApplePods -> createDualApplePods(parent, device) // Unused, has no case to trigger reaction? is SingleApplePods -> createSingleApplePods(parent, device) else -> throw IllegalArgumentException("Unexpected device: $device") } - private fun createDualApplePods(parent: ViewGroup, device: DualAirPods): View = + private fun createDualApplePods(parent: ViewGroup, device: DualApplePods): View = PopupNotificationDualPodsBinding.inflate(layoutInflater, parent, false).apply { device.apply { podIcon.setImageResource(iconRes)