Implement body-weight Health sync from Health Connect and HealthKit#515
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces one-way body weight synchronization from Google Health Connect (Android) and Apple HealthKit (iOS) into the application. It includes the implementation of a sync manager, a source classifier to filter out manual entries and identify eligible scale sources, foreground sync triggers, and UI updates to display the latest synced weight. The review feedback highlights two important improvements: first, avoiding the strict check on the overall granted permission flag in the view model to prevent blocking the integration when optional permissions are denied; second, falling back to metadata keyword matching on Android (similar to iOS) because many smart scales syncing to Health Connect do not properly populate the device type field.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| "hasWorkoutWritePermission=$hasWorkoutWritePermission, " + | ||
| "hasBodyWeightReadPermission=$hasBodyWeightReadPermission for ${provider.key}" | ||
| } | ||
| if (granted && hasWorkoutWritePermission && hasBodyWeightReadPermission) { |
There was a problem hiding this comment.
Checking the granted parameter here can prevent the integration from connecting if the user denies optional permissions (such as writing calories), even if they granted the required workout write and body weight read permissions. Since hasWorkoutWritePermission and hasBodyWeightReadPermission are the actual required permissions, we should only check those to determine if the integration is successfully connected.
| if (granted && hasWorkoutWritePermission && hasBodyWeightReadPermission) { | |
| if (hasWorkoutWritePermission && hasBodyWeightReadPermission) { |
| return when (evidence.platform) { | ||
| HealthBodyWeightSourcePlatform.ANDROID -> { | ||
| if (evidence.deviceType == HealthBodyWeightDeviceType.SCALE) { | ||
| HealthBodyWeightSourceClassification.ELIGIBLE_SCALE | ||
| } else { | ||
| HealthBodyWeightSourceClassification.UNKNOWN_SOURCE | ||
| } |
There was a problem hiding this comment.
On Android, only checking deviceType == HealthBodyWeightDeviceType.SCALE is highly restrictive. Many smart scales (e.g., Withings, Renpho) syncing to Health Connect do not populate the device metadata or device type properly, or Health Connect might not expose it if the record was synced via a cloud-to-cloud integration.
We should fall back to hasScaleLikeMetadata(evidence) on Android, just like we do on iOS, to support these popular smart scales whose apps sync to Health Connect but might not populate the device.type field.
HealthBodyWeightSourcePlatform.ANDROID -> {
if (evidence.deviceType == HealthBodyWeightDeviceType.SCALE || hasScaleLikeMetadata(evidence)) {
HealthBodyWeightSourceClassification.ELIGIBLE_SCALE
} else {
HealthBodyWeightSourceClassification.UNKNOWN_SOURCE
}
}There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a169f40629
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (healthIntegration.hasPermissions() && healthIntegration.hasBodyWeightReadPermission()) { | ||
| markHealthIntegrationConnected(provider, profileId) |
There was a problem hiding this comment.
Request HealthKit Body Mass for existing connections
On iOS this branch skips requestPermissions() whenever workout write access is already present, but hasBodyWeightReadPermission() in the iOS implementation only checks that HealthKit and the Body Mass type exist because HealthKit does not expose read authorization status. Existing Apple Health users who granted only workout permissions before this change will therefore be marked connected without ever seeing the new Body Mass read prompt, and body-weight queries will just return no samples. In the iOS path, force an authorization request when enabling so the new read type is requested even if workout write permission is already authorized.
Useful? React with 👍 / 👎.
Resolved conflicts between the body-weight Health sync feature (PR #515) and the structural Health Connect export refactor (PR #516) that landed on main. Kept both the body-weight read/sync functionality and the new unified HealthWorkoutData/segments architecture. Removed the obsolete writeRoutineWorkout from iOS since writeHealthWorkout now handles both standalone and routine exports. https://claude.ai/code/session_01AKWBtFX7AhSMKasky4TaSj
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb986d62c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| internal val requiredHealthPermissions = setOf( | ||
| HealthPermission.getWritePermission(ExerciseSessionRecord::class), | ||
| HealthPermission.getReadPermission(WeightRecord::class), |
There was a problem hiding this comment.
Keep body-weight read out of workout write checks
Adding READ_WEIGHT to requiredHealthPermissions also changes Android HealthWorkoutWriter.hasPermissions() and the writeHealthWorkout() guard to require body-weight read access. If a connected user later revokes only the Weight read permission in Health Connect while leaving WRITE_EXERCISE granted, completed workouts and backfills stop exporting even though the write permission needed for that path is still present; keep the workout-write permission check separate from the body-weight import permission check.
Useful? React with 👍 / 👎.
…ers (#552) PR #515 added `HealthPermission.getReadPermission(WeightRecord::class)` to `requiredHealthPermissions`. Because `HealthIntegration.hasPermissions()` is the only gate guarding `writeHealthWorkout()`, every Android user who had the Health Connect integration enabled before #515 shipped silently lost their post-workout export on upgrade: 1. `hasGrantedPermissions(requiredHealthPermissions)` checks the granted set contains `Write(ExerciseSession)` AND `Read(WeightRecord)`. 2. Pre-#515 users were only ever asked for `Write(ExerciseSession)`. 3. `hasPermissions()` therefore now returns false for those users. 4. `writeHealthWorkout()` returns `Result.failure(SecurityException)`. 5. The `onFailure` branch in `ActiveSessionEngine.{writeHealthData, writeRoutineHealthData}` only logs at `Logger.w` — there is no user-facing notification or status reset. Net effect: workouts complete normally in Phoenix but never reach Health Connect (and therefore Fitbit / Garmin / etc. via Health Connect), and the integration card keeps showing `CONNECTED`. The user has no signal that their data has stopped flowing. This patch restores the pre-#515 invariant by moving the body-weight read permission out of `requiredHealthPermissions` into its own `bodyWeightReadHealthPermissions` set, mirroring the iOS implementation where `hasPermissions()` only inspects `requiredWriteTypes` and the body- weight read is gated separately by `hasBodyWeightReadPermission()`. The launcher still requests body-weight read alongside workout write so new users get a single permission prompt for both capabilities. Adds `HealthPermissionScopesTest` to lock the partitioning down: - `requiredHealthPermissions` must contain only the workout-write permission. - The body-weight read permission must live in its own set. - The onboarding-only `workoutExportRequestedHealthPermissions` must not request body-weight read. - The integration-toggle launcher (`requestedHealthPermissions`) must still prompt for write, optional calories, and body-weight read together. Issue #531. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Devil <9thLevelSoftware@users.noreply.github.com>
No description provided.