Add AirPods Max support - #767
Open
Spottq wants to merge 1 commit into
Open
Conversation
The AirPods Max were recognised as ordinary AirPods: their model number was absent from the model table, so the lookup returned null and the UI fell back to a hardcoded AirPods Pro 2. They also have a single battery and no Adaptive listening mode, neither of which the app accounted for. Fixes librepods-org#30. - Register the AirPods Max (A2096), AirPods Max USB-C (A3184) and AirPods Max 2 (A3454) with real product artwork, so the icon follows the connected model everywhere: the device image, the notification, the QS tile and the popup. - Give AirPodsBase a form factor, a small icon and the BLE proximity-pairing ids, and resolve the model from the model number, the BLE id or the Bluetooth name rather than only the first of those. - Parse battery packets by their entry count instead of requiring the 22-byte three-battery layout, which the Max never send. Their packet is 12 bytes with a single component, as captured in librepods-org#30: 040004000400 01 01 01 64 02 01 The one battery is mirrored onto both sides so existing callers keep working, and the UI collapses it back into a single reading with no case. - Hide the Adaptive mode on models without it, and build the listening-mode control from the supported modes instead of a fixed set of four. This also drops Adaptive from the AirPods Pro 1, which never had it. - Show the Off Listening Mode toggle for every model with listening modes; it was gated on Loud Sound Reduction, which hid it on the Max. - Report over-ear models to the system as a plain headset rather than an untethered one, so the system stops expecting three batteries. - Use the real package name for resource URIs; the hardcoded one broke the connection popup whenever the application id differed. Tested on an AirPods Max USB-C (A3184): correct model name and number, a single battery reading, no Adaptive segment, and the Max icon in the status bar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wj2BSzNmCLkXpcS7YsttjZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #30.
The AirPods Max were recognised as ordinary AirPods. Their model number is absent from
AirPodsModels, sogetModelByModelNumberreturns null,airpodsInstancestays null, andloadInstance()falls back to a hardcodedA3049— an AirPods Pro 2 USB-C. That is why the Max show Pro artwork, a fictitious L/R/case battery and an Adaptive segment they do not have.What this changes
Model identification. Registers the AirPods Max (
A2096), AirPods Max USB-C (A3184) and AirPods Max 2 (A3454).AirPodsBasegains a form factor, a small icon and the BLE proximity-pairing ids thatBLEManageralready parsed but discarded, andAirPodsModels.resolveModel()falls back from the model number to the BLE id to the Bluetooth name, so an unknown Max is still not mistaken for earbuds.Battery.
isBatteryDatarequired exactly 22 bytes, so the Max packet was rejected outright and no battery ever appeared. It is now parsed by the entry count indata[6], which matches the capture from this thread:A single battery is mirrored onto both sides so the existing index-based callers of
getBattery()keep working, and the UI collapses the two equal readings into one and drops the case.Listening modes. The Apple-style segmented control hardcoded four buttons with index arithmetic branching on
showOffListeningMode. It is now built from the list of supported modes, so Adaptive can be dropped without a second layer of conditionals. Adaptive is gated onCapability.ADAPTIVE_AUDIO, which also removes it from the AirPods Pro 1, which never had it. The QS tile cycle and the Quick Settings dialog skip it too.Off Listening Mode toggle was gated on
Capability.LOUD_SOUND_REDUCTION, so it disappeared on every model without that feature, the Max included. It is gated onLISTENING_MODEnow, and falls back to the stored preference when the device does not report the control state.System metadata. Over-ear models are reported as
DEVICE_TYPE_DEFAULTrather thanDEVICE_TYPE_UNTETHERED_HEADSET, and the untethered case/left/right icons and thresholds are skipped, so the system stops expecting three batteries.Unrelated bug found on the way.
PopupWindowandresToUrihardcoded"me.kavishdevar.librepods"in resource URIs. With any other application id the video URI resolves to a missing package,VideoViewshows an error dialog from a non-activity context and the app dies withBadTokenException. Both now usepackageName.Testing
Hardware-tested on an AirPods Max USB-C (
A3184, firmware 74.2256106001000000.83) on a Galaxy Z Fold 7, Android 16, rootless. Correct model name and number, a single 57% battery with no case, no Adaptive segment, the Off toggle present, and the Max silhouette in the status bar.Status bar icon, traced from the product render so it stays crisp at 24dp:
Things worth your call
android/rewrite. This targetsmain, since that is what the RC codebase is. If the rewrite is meant to replace it, say so and I will port this across instead of you carrying it twice — @tobomobo asked the same question in Support for Airpods Max #30 and it is still open.res-apple/alongside the existing AirPods Pro renders, following that source set's convention. Swap them if you would rather not add more.