Skip to content

linux: show battery for all connected AirPods in the tray#674

Open
bissamiftikhar wants to merge 2 commits into
librepods-org:mainfrom
bissamiftikhar:fix/linux-tray-multi-device-status
Open

linux: show battery for all connected AirPods in the tray#674
bissamiftikhar wants to merge 2 commits into
librepods-org:mainfrom
bissamiftikhar:fix/linux-tray-multi-device-status

Conversation

@bissamiftikhar

Copy link
Copy Markdown

Fixes #670

Problem

The tray tracked battery as a single global string. With two AirPods connected at the same time, whichever device updated last simply overwrote the other one in the tooltip, and on top of that bleDeviceFound() let a BLE proximity broadcast that matches the stored IRK override the state of the device the app is actually connected to — the broadcast is anonymized, so it may well belong to a different paired device sitting in its case nearby. That's the "AirPods Pro 2 superseding the AirPods 4" behavior described in the issue.

What changed

TrayIconManager now keeps a small per-device registry (keyed by Bluetooth address) instead of one status string:

  • updateDeviceBattery(key, name, status) upserts a device's entry and re-renders the tooltip.
  • The tooltip lists every known device, active device first — with a single device the tooltip text is unchanged from before, so nothing moves for the common case.
  • The icon percentage is driven only by the active device (the one with the AACP connection).
  • A device's entry is removed only when that device disconnects, never by another device's update.

main.cpp wiring:

  • Battery updates are recorded under the device's address together with its name; disconnect events (bluezDeviceDisconnected fires per device) remove exactly that device's entry.
  • When the AACP connection switches to another device, DeviceInfo is reset so the new device doesn't inherit the previous device's name/battery in the UI. The previous device's last-known status stays visible in the tray until it actually disconnects.
  • While an AACP connection is up, BLE broadcasts are ignored: the live connection is authoritative for battery/ear state, and an IRK-matched broadcast can belong to another paired device (this is the override the issue reporter observed).
  • The BlueZ device name is used as the tray label until the AACP metadata packet provides the canonical name, so entries are labeled correctly from the first battery update.

Result

Hovering the tray icon with two connected devices now shows e.g.:

AirPods Pro 2: Left: 100%, Right: 100%, Case: 87%
AirPods 4: Left: 89%, Right: 89%, Case: 45%

With one device connected the tooltip is identical to current behavior (Battery Status: Left: …).

Notes / limitations

  • The app still opens a single AACP (L2CAP) socket at a time, so the non-active device shows its last-known values rather than live updates; making the whole app truly multi-connection is a much bigger refactor and feels like a separate discussion (as is the "one tray circle per device" idea from the issue).
  • Compile-verified against the CI toolchain (Ubuntu 24.04, Qt 6, cmake -G Ninja). I'd appreciate a hands-on test from someone with two sets of AirPods — @GarrettGR's setup from the issue is exactly the scenario this targets.

Replace the single global tooltip string with a small per-device registry
keyed by Bluetooth address. Each entry stores the device's last known name
and formatted battery status. The tooltip lists every known device (active
device first); with a single device the tooltip format is unchanged. The
icon percentage is driven only by the active device, and resetTrayIcon()
now clears the registry as well.
Previously the tray tracked a single global battery status, so with two
AirPods connected the most recent update simply overwrote the other
device's status, and BLE broadcasts matching the stored IRK could
override the AACP-connected device's state with data from a different
(paired but not connected) device.

- Battery updates are now recorded per device (keyed by Bluetooth
  address) and the tooltip lists every known device, active device
  first. A device's entry is only removed when that device disconnects.
- Switching the AACP connection to another device resets DeviceInfo so
  the new device doesn't inherit the previous device's name/battery;
  the previous device's last known status stays visible in the tray.
- BLE broadcasts are ignored while an AACP connection is up: the live
  connection is authoritative, and an IRK-matched broadcast may belong
  to another paired device.
- The BlueZ device name is used as the tray label until the AACP
  metadata packet provides the canonical name.

Fixes librepods-org#670
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Linux] Tray application can only show status of one device when multiple devices are connected

1 participant