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.
This commit is contained in:
Gideon Zenz
2026-03-12 18:30:52 +01:00
parent cb5634dcfe
commit f07779f249
@@ -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)