From f07779f2490e72513256855ad4bd785dc5f71ea7 Mon Sep 17 00:00:00 2001 From: Gideon Zenz Date: Sun, 1 Mar 2026 22:36:06 +0100 Subject: [PATCH] Health Connect: Fix duplicate records from workout syncer overlapping ACTIVITY sync RecordedWorkoutSyncer was writing heart rate, steps, and calorie records that overlap with the per-minute data already synced by HeartRateSyncer, StepsSyncer, and ActiveCaloriesSyncer in the ACTIVITY data type sync. The supportsActiveCalories guard from 8c575535b only covered processDetailedWorkout but not processAggregateWorkout, which is the code path hit when no track file is available. No guards existed for heart rate or steps in either path. Skip workout-level aggregate HR and steps when supportsActivityTracking (covered by ACTIVITY sync), and skip workout-level calories when supportsActiveCalories (covered by ActiveCaloriesSyncer). Per-second HR from detailed workout track data is always synced as it is more granular than the per-minute activity HR. --- .../syncers/RecordedWorkoutSyncer.kt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/RecordedWorkoutSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/RecordedWorkoutSyncer.kt index 936761465d..42532d074a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/RecordedWorkoutSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/RecordedWorkoutSyncer.kt @@ -355,6 +355,8 @@ internal object RecordedWorkoutSyncer { ) ) + val supportsActivityTracking = device.deviceCoordinator.supportsActivityTracking(device) + addDetailedHeartRateRecords(activityPoints, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) addDetailedSpeedRecords(activityPoints, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) addDetailedPowerRecords(activityPoints, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) @@ -367,7 +369,9 @@ internal object RecordedWorkoutSyncer { addCaloriesRecords(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) } addElevationGainedRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) - addStepsRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + if (!supportsActivityTracking) { + addStepsRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + } addCadenceRecords(summaryData, activityKind, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) } } @@ -398,14 +402,22 @@ internal object RecordedWorkoutSyncer { ) ) + val supportsActivityTracking = gbDevice.deviceCoordinator.supportsActivityTracking(gbDevice) + val summaryData = parseSummaryData(workout.summaryData) if (summaryData != null) { addDistanceRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) - addHeartRateRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + if (!supportsActivityTracking) { + addHeartRateRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + } addSpeedRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) - addCaloriesRecords(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + if (!gbDevice.deviceCoordinator.supportsActiveCalories(gbDevice)) { + addCaloriesRecords(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + } addElevationGainedRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) - addStepsRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + if (!supportsActivityTracking) { + addStepsRecord(summaryData, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) + } addCadenceRecords(summaryData, activityKind, workoutStartInstant, workoutEndInstant, offset, metadata, grantedPermissions, recordsToInsert, deviceName) } else { LOG.warn("No summary data available for workout on device '{}' at {}", deviceName, workoutStartInstant)