From 0b27cb55dc01d7c003e35b0c3fe43bec2b0eeab1 Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 19 Dec 2022 16:40:19 +0100 Subject: [PATCH 1/3] Refactor fake airpods code and improve tests --- .../eu/darken/capod/pods/core/PodDevice.kt | 8 +- .../pods/core/apple/AppleFactoryModule.kt | 4 +- .../misc/{Twsi99999.kt => FakeAirPodsGen1.kt} | 11 +- .../pods/core/apple/misc/FakeAirPodsGen3.kt | 108 +++++++++++++++--- .../pods/core/apple/misc/FakeAirPodsPro.kt | 1 + .../core/apple/airpods/AirPodsGen1Test.kt | 3 + .../core/apple/airpods/AirPodsGen2Test.kt | 3 + .../core/apple/airpods/AirPodsGen3Test.kt | 3 + .../pods/core/apple/airpods/AirPodsMaxTest.kt | 3 + .../core/apple/airpods/AirPodsPro2Test.kt | 3 + .../pods/core/apple/airpods/AirPodsProTest.kt | 3 + .../pods/core/apple/beats/BeatsFlexText.kt | 3 + .../pods/core/apple/beats/BeatsSolo3Test.kt | 3 + .../pods/core/apple/beats/BeatsStudio3Test.kt | 3 + .../capod/pods/core/apple/beats/BeatsXTest.kt | 3 + .../pods/core/apple/beats/PowerBeats3Test.kt | 3 + .../core/apple/beats/PowerBeatsProTest.kt | 3 + ...wsi99999Test.kt => FakeAirPodsGen1Test.kt} | 7 +- .../core/apple/misc/FakeAirPodsGen3Test.kt | 22 ++-- .../core/apple/misc/FakeAirPodsProTest.kt | 3 + 20 files changed, 163 insertions(+), 37 deletions(-) rename app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/{Twsi99999.kt => FakeAirPodsGen1.kt} (92%) rename app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/{Twsi99999Test.kt => FakeAirPodsGen1Test.kt} (78%) diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt b/app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt index 28aefcd6..5272ede2 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt @@ -104,14 +104,14 @@ interface PodDevice { @Json(name = "beats.powerbeats.pro") POWERBEATS_PRO( "Power Beats Pro" ), - @Json(name = "fakes.tws.i99999") TWS_I99999( - "TWS i99999" + @Json(name = "fakes.tws.i99999") FAKE_AIRPODS_GEN1( + "AirPods (Gen 1)? \uD83C\uDFAD" ), @Json(name = "fakes.varunr.airpodspro") FAKE_AIRPODS_PRO( - "AirPods Pro?" + "AirPods Pro? \uD83C\uDFAD" ), @Json(name = "fakes.generic.airpods.gen3") FAKE_AIRPODS_GEN3( - "AirPods (Gen 3)?" + "AirPods (Gen 3)? \uD83C\uDFAD" ), @Json(name = "unknown") UNKNOWN( "Unknown" diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/AppleFactoryModule.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/AppleFactoryModule.kt index e4b49314..6e591111 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/AppleFactoryModule.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/AppleFactoryModule.kt @@ -7,9 +7,9 @@ import dagger.hilt.components.SingletonComponent import dagger.multibindings.IntoSet import eu.darken.capod.pods.core.apple.airpods.* import eu.darken.capod.pods.core.apple.beats.* +import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen1 import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen3 import eu.darken.capod.pods.core.apple.misc.FakeAirPodsPro -import eu.darken.capod.pods.core.apple.misc.Twsi99999 @InstallIn(SingletonComponent::class) @Module @@ -30,7 +30,7 @@ abstract class AppleFactoryModule { @Binds @IntoSet abstract fun powerBeats3(factory: PowerBeats3.Factory): ApplePodsFactory @Binds @IntoSet abstract fun powerBeatsPro(factory: PowerBeatsPro.Factory): ApplePodsFactory - @Binds @IntoSet abstract fun fakesTwsi999999(factory: Twsi99999.Factory): ApplePodsFactory + @Binds @IntoSet abstract fun fakeAirPodsGen1(factory: FakeAirPodsGen1.Factory): ApplePodsFactory @Binds @IntoSet abstract fun fakeAirPodsPro(factory: FakeAirPodsPro.Factory): ApplePodsFactory @Binds @IntoSet abstract fun fakeAirPodsGen3(factory: FakeAirPodsGen3.Factory): ApplePodsFactory } \ No newline at end of file diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/Twsi99999.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1.kt similarity index 92% rename from app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/Twsi99999.kt rename to app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1.kt index c8a319b3..449bca60 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/Twsi99999.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1.kt @@ -19,8 +19,9 @@ import javax.inject.Inject /** * Basically an AirPods GEN1 clone * Similar data structure but a lot of placeholder values or hardcoded values + * Marketed as TWS i99999 */ -data class Twsi99999 constructor( +data class FakeAirPodsGen1 constructor( override val identifier: PodDevice.Id = PodDevice.Id(), override val seenLastAt: Instant = Instant.now(), override val seenFirstAt: Instant = Instant.now(), @@ -32,7 +33,7 @@ data class Twsi99999 constructor( private val cachedBatteryPercentage: Float? = null, ) : ApplePods, DualPodDevice, HasDualMicrophone, HasCase { - override val model: PodDevice.Model = PodDevice.Model.TWS_I99999 + override val model: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_GEN1 override val rssi: Int get() = rssiAverage ?: super.rssi @@ -109,7 +110,7 @@ data class Twsi99999 constructor( override val isCaseCharging: Boolean get() = rawFlags.isBitSet(2) - class Factory @Inject constructor() : ApplePodsFactory(TAG) { + class Factory @Inject constructor() : ApplePodsFactory(TAG) { override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run { // Official message length is 19HEX, i.e. binary 25, did they copy this wrong? @@ -117,7 +118,7 @@ data class Twsi99999 constructor( } override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods { - var basic = Twsi99999(scanResult = scanResult, proximityMessage = message) + var basic = FakeAirPodsGen1(scanResult = scanResult, proximityMessage = message) val result = searchHistory(basic) if (result != null) basic = basic.copy(identifier = result.id) @@ -139,6 +140,6 @@ data class Twsi99999 constructor( companion object { private val DEVICE_CODE = 0x0220.toUShort() - private val TAG = logTag("PodDevice", "Apple", "TWS", "i99999") + private val TAG = logTag("PodDevice", "Apple", "Fake", "AirPods", "Gen1") } } \ No newline at end of file diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3.kt index 2ee3b7b6..62ec3b5b 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3.kt @@ -1,11 +1,14 @@ package eu.darken.capod.pods.core.apple.misc import eu.darken.capod.common.bluetooth.BleScanResult +import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.debug.logging.logTag -import eu.darken.capod.pods.core.PodDevice +import eu.darken.capod.common.isBitSet +import eu.darken.capod.common.lowerNibble +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.DualAirPods -import eu.darken.capod.pods.core.apple.DualApplePodsFactory +import eu.darken.capod.pods.core.apple.ApplePodsFactory import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant import javax.inject.Inject @@ -25,20 +28,98 @@ data class FakeAirPodsGen3 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 { +) : ApplePods, DualPodDevice, HasDualMicrophone, HasCase, HasChargeDetectionDual { + override val model: PodDevice.Model = PodDevice.Model.FAKE_AIRPODS_GEN3 - override val batteryCasePercent: Float? - get() = super.batteryCasePercent ?: cachedBatteryPercentage - - override val caseLidState: DualAirPods.LidState - get() = cachedCaseState ?: super.caseLidState - override val rssi: Int - get() = rssiAverage ?: super.rssi + get() = rssiAverage ?: super.rssi - class Factory @Inject constructor() : DualApplePodsFactory(TAG) { + /** + * Normally values for the left pod are in the lower nibbles, if the left pod is primary (microphone) + * If the right pod is the primary, the values are flipped. + */ + val areValuesFlipped: Boolean + get() = !rawStatus.isBitSet(5) + + override val batteryLeftPodPercent: Float? + get() { + val value = when (areValuesFlipped) { + true -> rawPodsBattery.upperNibble.toInt() + false -> rawPodsBattery.lowerNibble.toInt() + } + return when (value) { + 15 -> null + else -> if (value > 10) { + log { "Left pod: Above 100% battery: $value" } + 1.0f + } else { + (value / 10f) + } + } + } + + override val batteryRightPodPercent: Float? + get() { + val value = when (areValuesFlipped) { + true -> rawPodsBattery.lowerNibble.toInt() + false -> rawPodsBattery.upperNibble.toInt() + } + return when (value) { + 15 -> null + else -> if (value > 10) { + log { "Right pod: Above 100% battery: $value" } + 1.0f + } else { + value / 10f + } + } + } + + override val isLeftPodCharging: Boolean + get() = when (areValuesFlipped) { + false -> rawFlags.isBitSet(0) + true -> rawFlags.isBitSet(1) + } + + override val isRightPodCharging: Boolean + get() = when (areValuesFlipped) { + false -> rawFlags.isBitSet(1) + true -> rawFlags.isBitSet(0) + } + + val isThisPodInThecase: Boolean + get() = rawStatus.isBitSet(6) + + /** + * The data flip bit is set if the left pod is primary. + * For the pod that is in the case, this is flipped again though. + */ + override val isLeftPodMicrophone: Boolean + get() = rawStatus.isBitSet(5) xor isThisPodInThecase + + /** + * The data flip bit is UNset if the right pod is primary. + * For the pod that is in the case, this is flipped again though. + */ + override val isRightPodMicrophone: Boolean + get() = !rawStatus.isBitSet(5) xor isThisPodInThecase + + override val batteryCasePercent: Float? + get() = when (val value = rawCaseBattery.toInt()) { + 15 -> cachedBatteryPercentage + else -> if (value > 10) { + log { "Case: Above 100% battery: $value" } + 1.0f + } else { + value / 10f + } + } + + override val isCaseCharging: Boolean + get() = rawFlags.isBitSet(2) + + class Factory @Inject constructor() : ApplePodsFactory(TAG) { override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run { // Official message length is 19HEX, i.e. binary 25, did they copy this wrong? @@ -62,7 +143,6 @@ data class FakeAirPodsGen3 constructor( confidence = result.confidence, cachedBatteryPercentage = result.getLatestCaseBattery(), rssiAverage = result.averageRssi(basic.rssi), - cachedCaseState = result.getLatestCaseLidState(basic) ) } diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro.kt index f28cece1..ef622ff5 100644 --- a/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro.kt +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsPro.kt @@ -19,6 +19,7 @@ import javax.inject.Inject /** * AirPods Pro clone similar to Twsi999999. * Shorter data structure. + * https://discord.com/channels/548521543039189022/927235844127993866/962068944196358234 */ data class FakeAirPodsPro constructor( override val identifier: PodDevice.Id = PodDevice.Id(), 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 316989a4..8bcb23e9 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 @@ -1,5 +1,6 @@ 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.HasAppleColor @@ -39,6 +40,8 @@ class AirPodsGen1Test : BaseAirPodsTest() { state shouldBe DualAirPods.ConnectionState.DISCONNECTED podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.AIRPODS_GEN1 } } } \ No newline at end of file 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 c8a9e5bd..b4ce5960 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 @@ -1,5 +1,6 @@ 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.HasAppleColor @@ -38,6 +39,8 @@ class AirPodsGen2Test : BaseAirPodsTest() { state shouldBe DualAirPods.ConnectionState.MUSIC podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.AIRPODS_GEN2 } } } \ No newline at end of file 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 92a69489..fd42ac2c 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 @@ -1,5 +1,6 @@ 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.HasAppleColor @@ -38,6 +39,8 @@ class AirPodsGen3Test : BaseAirPodsTest() { state shouldBe DualAirPods.ConnectionState.IDLE podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.AIRPODS_GEN3 } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxTest.kt index 842dd256..9ca5d6b1 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxTest.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.airpods +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -26,6 +27,8 @@ class AirPodsMaxTest : BaseAirPodsTest() { isHeadsetBeingCharged shouldBe false isHeadphonesBeingWorn shouldBe true + + model shouldBe PodDevice.Model.AIRPODS_MAX } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2Test.kt index e297b296..03600f07 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro2Test.kt @@ -1,5 +1,6 @@ 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.HasAppleColor import io.kotest.matchers.shouldBe @@ -40,6 +41,8 @@ class AirPodsPro2Test : BaseAirPodsTest() { batteryCasePercent shouldBe 0.9f podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.AIRPODS_PRO2 } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsProTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsProTest.kt index 9a94e283..c131a090 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsProTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsProTest.kt @@ -1,5 +1,6 @@ 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.HasAppleColor import io.kotest.matchers.shouldBe @@ -34,6 +35,8 @@ class AirPodsProTest : BaseAirPodsTest() { batteryCasePercent shouldBe 0.5f podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.AIRPODS_PRO } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsFlexText.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsFlexText.kt index 4cb64433..0f591c34 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsFlexText.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsFlexText.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -22,6 +23,8 @@ class BeatsFlexText : BaseAirPodsTest() { rawSuffix shouldBe 0x00.toUByte() batteryHeadsetPercent shouldBe 0.4f + + model shouldBe PodDevice.Model.BEATS_FLEX } } diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3Test.kt index bee7c5cc..1287e0ec 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3Test.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -22,6 +23,8 @@ class BeatsSolo3Test : BaseAirPodsTest() { rawSuffix shouldBe 0x40.toUByte() batteryHeadsetPercent shouldBe 0.4f + + model shouldBe PodDevice.Model.BEATS_SOLO_3 } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3Test.kt index 8bbcec61..1e0c2b11 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3Test.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -22,6 +23,8 @@ class BeatsStudio3Test : BaseAirPodsTest() { rawSuffix shouldBe 0x40.toUByte() batteryHeadsetPercent shouldBe 0.4f + + model shouldBe PodDevice.Model.BEATS_STUDIO_3 } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsXTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsXTest.kt index b917bb98..a645d751 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsXTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/BeatsXTest.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -22,6 +23,8 @@ class BeatsXTest : BaseAirPodsTest() { rawSuffix shouldBe 0x00.toUByte() batteryHeadsetPercent shouldBe 0.5f + + model shouldBe PodDevice.Model.BEATS_X } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3Test.kt index 8a14f17a..ea4c7928 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3Test.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -22,6 +23,8 @@ class PowerBeats3Test : BaseAirPodsTest() { rawSuffix shouldBe 0x40.toUByte() batteryHeadsetPercent shouldBe 0.4f + + model shouldBe PodDevice.Model.POWERBEATS_3 } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsProTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsProTest.kt index b3e5a10a..bad843f0 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsProTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsProTest.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.beats +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import eu.darken.capod.pods.core.apple.HasAppleColor import io.kotest.matchers.shouldBe @@ -34,6 +35,8 @@ class PowerBeatsProTest : BaseAirPodsTest() { batteryCasePercent shouldBe 0.5f podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name + + model shouldBe PodDevice.Model.POWERBEATS_PRO } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/Twsi99999Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1Test.kt similarity index 78% rename from app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/Twsi99999Test.kt rename to app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1Test.kt index cdfce42f..25e62a3a 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/Twsi99999Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen1Test.kt @@ -1,15 +1,16 @@ package eu.darken.capod.pods.core.apple.misc +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test -class Twsi99999Test : BaseAirPodsTest() { +class FakeAirPodsGen1Test : BaseAirPodsTest() { @Test fun `charging in box`() = runTest { - create("07 13 01 02 20 71 AA 37 32 00 10 00 64 64 FF 00 00 00 00 00 00") { + create("07 13 01 02 20 71 AA 37 32 00 10 00 64 64 FF 00 00 00 00 00 00") { rawPrefix shouldBe 0x01.toUByte() rawDeviceModel shouldBe 0x0220.toUShort() rawStatus shouldBe 0x71.toUByte() @@ -26,6 +27,8 @@ class Twsi99999Test : BaseAirPodsTest() { isCaseCharging shouldBe false batteryCasePercent shouldBe 0.7f + + model shouldBe PodDevice.Model.FAKE_AIRPODS_GEN1 } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3Test.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3Test.kt index 7994b48b..49ec6245 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3Test.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsGen3Test.kt @@ -1,8 +1,7 @@ package eu.darken.capod.pods.core.apple.misc +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.HasAppleColor import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test @@ -12,6 +11,16 @@ class FakeAirPodsGen3Test : BaseAirPodsTest() { @Test fun `charging in case`() = runTest { create("07 13 01 13 20 75 AA 37 34 00 10 00 E4 E4 64 00 00 00 00 00 00") { + rawPrefix shouldBe 0x01.toUByte() + rawDeviceModel shouldBe 0x1320.toUShort() + rawStatus shouldBe 0x75.toUByte() + rawPodsBattery shouldBe 0xAA.toUByte() + rawFlags shouldBe 0x3.toUShort() + rawCaseBattery shouldBe 0x7.toUShort() + rawCaseLidState shouldBe 0x34.toUByte() + rawDeviceColor shouldBe 0x00.toUByte() + rawSuffix shouldBe 0x10.toUByte() + batteryLeftPodPercent shouldBe 1f batteryRightPodPercent shouldBe 1f @@ -19,16 +28,9 @@ class FakeAirPodsGen3Test : BaseAirPodsTest() { isLeftPodCharging shouldBe true isRightPodCharging shouldBe true - isLeftPodInEar shouldBe false - isRightPodInEar shouldBe false batteryCasePercent shouldBe 0.7f - caseLidState shouldBe DualAirPods.LidState.OPEN - - state shouldBe DualAirPods.ConnectionState.UNKNOWN - - podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name - + model shouldBe PodDevice.Model.FAKE_AIRPODS_GEN3 } } } \ No newline at end of file diff --git a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsProTest.kt b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsProTest.kt index 4bc8837b..a9935522 100644 --- a/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsProTest.kt +++ b/app-common/src/test/java/eu/darken/capod/pods/core/apple/misc/FakeAirPodsProTest.kt @@ -1,5 +1,6 @@ package eu.darken.capod.pods.core.apple.misc +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BaseAirPodsTest import io.kotest.matchers.shouldBe import kotlinx.coroutines.test.runTest @@ -26,6 +27,8 @@ class FakeAirPodsProTest : BaseAirPodsTest() { isCaseCharging shouldBe false batteryCasePercent shouldBe 0.7f + + model shouldBe PodDevice.Model.FAKE_AIRPODS_PRO } } } \ No newline at end of file From 51fb4c7a2900a1863f9327f350788e40578a64cf Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 19 Dec 2022 17:02:05 +0100 Subject: [PATCH 2/3] Update translations --- app/src/main/res/values-it/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index f59f6e3f..a0c16ad0 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -9,6 +9,7 @@ Chiudi Aggiorna CAPod Ottieni funzionalità aggiuntive e supporta lo sviluppatore. + Modalità monitor Sotto quali circostanze questa applicazione monitora i dati Bluetooth. Modalità di scansione Il bluetooth a basso consumo energetico dovrebbe dare priorità alle performance o al risparmio della batteria? @@ -50,6 +51,7 @@ Le segnalazioni automatiche degli errori sono anonime. Condividi il tuo ID di installazione con lo sviluppatore se necessità di trovare la tua segnalazione all\'interno del registro segnalazioni. Supporto Se ti serve un aiuto. + Tracker problemi Un issue tracker pubblico per segnalare i problemi e le richieste per aggiungere nuove funzionalità (solo in inglese). Discord Un posto dove poter fare domande. From 454d76e3056d5390b2e55977531e552c0f2cc39b Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 19 Dec 2022 17:10:30 +0100 Subject: [PATCH 3/3] Release: 2.4.0-rc0 --- VERSION | 2 +- version.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 29e8a975..48cf6f9a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.1-rc0 20301000 +2.4.0-rc0 20400000 diff --git a/version.properties b/version.properties index c9d91bf5..415ef6ae 100644 --- a/version.properties +++ b/version.properties @@ -1,6 +1,6 @@ ### Updated by release.sh ### project.versioning.major=2 -project.versioning.minor=3 -project.versioning.patch=1 +project.versioning.minor=4 +project.versioning.patch=0 project.versioning.build=0 #############################