Skip to content

android: add batched and configurable Health Connect heart-rate export - #3

Open
maxboeer wants to merge 3 commits into
thibaup:heart-rate-monitoringfrom
maxboeer:heart-rate-monitoring
Open

android: add batched and configurable Health Connect heart-rate export#3
maxboeer wants to merge 3 commits into
thibaup:heart-rate-monitoringfrom
maxboeer:heart-rate-monitoring

Conversation

@maxboeer

Copy link
Copy Markdown

First of all, thank you for the great work on AirPods heart-rate monitoring. I have been using the v3 release APK for the past two days and am very happy with it. It is fantastic to finally have this feature available on Android.

Motivation

Writing every one-second heart-rate reading to Health Connect individually preserves the full detail and provides effectively live data, but it also requires a Health Connect write for every sample. These frequent phone-side writes can cause unnecessary battery usage.

The existing Average mode already avoids this, but it discards the individual readings. I wanted to retain the full one-second resolution; apart from the additional storage usage, there is little downside to keeping these samples when they can be written efficiently.

Changes

This PR adds a third storage mode:

  • Every second: writes each reading immediately for live Health Connect data.
  • Batched: preserves every reading and writes them together at configurable intervals.
  • Average: writes one averaged value per interval and remains the default mode.

Batched mode defaults to five minutes. Batch and average intervals can both be configured between 30 seconds and 15 minutes in 30-second steps; Average keeps its previous one-minute default.

Each batch is stored as one HeartRateRecord containing all timestamped samples. This requires only one set of record metadata per interval instead of separate metadata for every reading, slightly reducing the stored data in addition to reducing write operations.

The exporter continues to use its mutex-protected buffering and retry path. Pending samples are handled before mode or interval changes are applied, and stable record IDs keep retries idempotent.

UI

I reorganized the original Health Connect controls because the storage strategies are mutually exclusive modes rather than independent options. Multiple switches and changing descriptions made that relationship harder to understand.

Health Connect is now presented as one grouped section with:

  • one switch for enabling storage;
  • one Storage mode row showing the current selection;
  • a dedicated selection page modeled after existing settings such as Press and Hold.

This better matches LibrePods’ general navigation and grouping patterns in both the Liquid Glass and Material 3 Expressive designs.

Since an interval control was already needed for batching, I also made the Average interval configurable. This adds useful flexibility with very little additional UI or implementation complexity.

StyledSlider gained an optional onValueChangeFinished callback for both design implementations. The displayed value can update continuously while dragging, while preferences and exporter state are updated only after the gesture finishes. Existing slider call sites remain unchanged because the callback defaults to a no-op.

Unit tests cover preservation of individual samples and timestamps, average calculation, interval normalization and bounds, mode mapping, legacy settings, and the configured interval for every mode. The existing test suite and Foss/coexist debug builds pass.

Testing and AI disclosure

The implementation was developed with GPT-5.6 Codex assistance. I have reviewed the code extensively by hand and am currently testing it on my Pixel 6a. So far, I have not found any bugs and everything behaves as intended.

Additional testing, feedback, improvements, and bug reports would be very welcome.

@maxboeer

Copy link
Copy Markdown
Author

@thibaup It would be great if you could have a look at it and potentially merge this PR into your fork, so it can become part of your librepods PR. I've been personally using my fork with my Airpods Pro 3 since the time I created it and haven't had any issues yet.

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.

1 participant