From 663e2d3b08cbc03752c11e97edd90fbef877517f Mon Sep 17 00:00:00 2001 From: b4shtirk1n Date: Tue, 5 Nov 2024 21:50:50 +0500 Subject: [PATCH] add support airpods max 2 & fix airpods max --- .../eu/darken/capod/pods/core/PodDevice.kt | 4 ++ .../pods/core/apple/AppleFactoryModule.kt | 2 + .../pods/core/apple/airpods/AirPodsMax.kt | 2 +- .../pods/core/apple/airpods/AirPodsMax2.kt | 69 +++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax2.kt 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 0065eb98..d58e14a5 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 @@ -107,6 +107,10 @@ interface PodDevice { "AirPods Max", R.drawable.devic_headphones_generic ), + @Json(name = "airpods.max2") AIRPODS_MAX2( + "AirPods Max 2", + R.drawable.devic_headphones_generic + ), @Json(name = "beats.flex") BEATS_FLEX( "Beats Flex" ), 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 424f53fd..da6de94f 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 @@ -11,6 +11,7 @@ import eu.darken.capod.pods.core.apple.airpods.AirPodsGen3 import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4 import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4Anc import eu.darken.capod.pods.core.apple.airpods.AirPodsMax +import eu.darken.capod.pods.core.apple.airpods.AirPodsMax2 import eu.darken.capod.pods.core.apple.airpods.AirPodsPro import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2 import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2Usbc @@ -42,6 +43,7 @@ abstract class AppleFactoryModule { @Binds @IntoSet abstract fun airPodsPro2(factory: AirPodsPro2.Factory): ApplePodsFactory @Binds @IntoSet abstract fun airPodsPro2Usbc(factory: AirPodsPro2Usbc.Factory): ApplePodsFactory @Binds @IntoSet abstract fun airPodsMax(factory: AirPodsMax.Factory): ApplePodsFactory + @Binds @IntoSet abstract fun airPodsMax2(factory: AirPodsMax2.Factory): ApplePodsFactory @Binds @IntoSet abstract fun beatsFlex(factory: BeatsFlex.Factory): ApplePodsFactory @Binds @IntoSet abstract fun beatsSolo3(factory: BeatsSolo3.Factory): ApplePodsFactory 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 b3e6ac9a..2ccd586f 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 @@ -63,7 +63,7 @@ data class AirPodsMax( } companion object { - private val DEVICE_CODE_DIRTY = 10.toUByte() + private val DEVICE_CODE_DIRTY = 0x200A.toUByte() private val TAG = logTag("PodDevice", "Apple", "AirPods", "Max") } } \ No newline at end of file diff --git a/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax2.kt b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax2.kt new file mode 100644 index 00000000..afe2b61d --- /dev/null +++ b/app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax2.kt @@ -0,0 +1,69 @@ +package eu.darken.capod.pods.core.apple.airpods + +import eu.darken.capod.common.bluetooth.BleScanResult +import eu.darken.capod.common.debug.logging.logTag +import eu.darken.capod.common.isBitSet +import eu.darken.capod.pods.core.HasChargeDetection +import eu.darken.capod.pods.core.HasEarDetection +import eu.darken.capod.pods.core.PodDevice +import eu.darken.capod.pods.core.apple.ApplePods +import eu.darken.capod.pods.core.apple.HasAppleColor +import eu.darken.capod.pods.core.apple.SingleApplePods +import eu.darken.capod.pods.core.apple.SingleApplePodsFactory +import eu.darken.capod.pods.core.apple.protocol.ProximityPairing +import java.time.Instant +import javax.inject.Inject + +data class AirPodsMax2( + override val identifier: PodDevice.Id = PodDevice.Id(), + override val seenLastAt: Instant = Instant.now(), + override val seenFirstAt: Instant = Instant.now(), + override val seenCounter: Int = 1, + override val scanResult: BleScanResult, + override val proximityMessage: ProximityPairing.Message, + override val reliability: Float = PodDevice.BASE_CONFIDENCE, + private val rssiAverage: Int? = null, +) : SingleApplePods, HasEarDetection, HasChargeDetection, HasAppleColor { + + override val model: PodDevice.Model = PodDevice.Model.AIRPODS_MAX2 + + override val rssi: Int + get() = rssiAverage ?: super.rssi + + override val isHeadsetBeingCharged: Boolean + get() = rawFlags.isBitSet(0) + + override val isBeingWorn: Boolean + get() = rawStatus.isBitSet(5) + + class Factory @Inject constructor() : SingleApplePodsFactory(TAG) { + + override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run { + getModelInfo().dirty == DEVICE_CODE_DIRTY && length == ProximityPairing.PAIRING_MESSAGE_LENGTH + } + + override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods { + var basic = AirPodsMax2(scanResult = scanResult, proximityMessage = message) + val result = searchHistory(basic) + + if (result != null) basic = basic.copy(identifier = result.id) + updateHistory(basic) + + if (result == null) return basic + + return basic.copy( + identifier = result.id, + seenFirstAt = result.seenFirstAt, + seenLastAt = scanResult.receivedAt, + seenCounter = result.seenCounter, + reliability = result.reliability, + rssiAverage = result.rssiSmoothed(basic.rssi), + ) + } + } + + companion object { + private val DEVICE_CODE_DIRTY = 0x201F.toUByte() + private val TAG = logTag("PodDevice", "Apple", "AirPods", "Max2") + } +}