diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/HealthConnectUtils.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/HealthConnectUtils.kt index 84e9b20389..1ed104a9ad 100755 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/HealthConnectUtils.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/HealthConnectUtils.kt @@ -238,7 +238,7 @@ class HealthConnectUtils { val recordsSyncedByType = mutableMapOf() // Track records per data type val dataTypesWithErrors = mutableSetOf() // Track which data types had errors - val offset = ZonedDateTime.now(TimeZone.getDefault().toZoneId()).offset + val zoneId = TimeZone.getDefault().toZoneId() val manager = GBApplication.app().deviceManager val syncIntervalInSeconds: Long = 24 * 60 * 60 // 1 day slices val lookBackInSeconds: Long = 24 * 60 * 60 @@ -263,7 +263,7 @@ class HealthConnectUtils { val manufacturer = deviceCoordinator.manufacturer var deviceName = context.getString(deviceCoordinator.deviceNameResource) if (deviceName.startsWith(manufacturer) && deviceName != manufacturer) { - deviceName = deviceName.replace(manufacturer, ""); + deviceName = deviceName.replace(manufacturer, "").trim(); } val device = Device( type = when (deviceCoordinator.getDeviceKind(gbDevice)) { @@ -393,7 +393,7 @@ class HealthConnectUtils { healthConnectClient = healthConnectClient, gbDevice = gbDevice, metadata = metadata, - offset = offset, + offset = zoneId, currentSliceStartTs = currentSliceStartTs, currentSliceEndTs = currentSliceEndTs, grantedPermissions = grantedPermissions, @@ -575,7 +575,7 @@ class HealthConnectUtils { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: java.time.ZoneOffset, + offset: java.time.ZoneId, currentSliceStartTs: Instant, currentSliceEndTs: Instant, grantedPermissions: Set, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractActivitySampleSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractActivitySampleSyncer.kt index f486f01e94..a31e015365 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractActivitySampleSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractActivitySampleSyncer.kt @@ -25,6 +25,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtils import org.slf4j.Logger import java.time.Instant +import java.time.ZoneId import java.time.ZoneOffset import java.time.temporal.ChronoUnit import kotlin.reflect.KClass @@ -44,7 +45,7 @@ internal abstract class AbstractActivitySampleSyncer : Activit healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, @@ -89,7 +90,7 @@ internal abstract class AbstractActivitySampleSyncer : Activit return@forEach } - val record = convertSample(sample = currentSample, offset, metadata, deviceName) + val record = convertSample(sample = currentSample, offset.rules.getOffset(endTs), metadata, deviceName) if (record == null) { skippedCount++ return@forEach diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt index c446a41dde..4df673700f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt @@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtil import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.SyncException import org.slf4j.Logger import java.time.Instant +import java.time.ZoneId import java.time.ZoneOffset import kotlin.reflect.KClass @@ -59,7 +60,7 @@ internal abstract class AbstractTimeSampleSyncer @@ -114,9 +115,10 @@ internal abstract class AbstractTimeSampleSyncer + val sampleOffset = offset.rules.getOffset(Instant.ofEpochMilli(sample.timestamp)) convertSample( sample, - offset, + sampleOffset, metadata, deviceName )?.also { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HealthConnectSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HealthConnectSyncer.kt index 661c507846..1ea2f76293 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HealthConnectSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HealthConnectSyncer.kt @@ -22,7 +22,7 @@ import androidx.health.connect.client.records.metadata.Metadata import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample import java.time.Instant -import java.time.ZoneOffset +import java.time.ZoneId /** * Statistics returned by a syncer after processing a slice. @@ -46,7 +46,7 @@ internal sealed interface HealthConnectSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set @@ -62,7 +62,7 @@ internal interface ActivitySampleSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, @@ -79,7 +79,7 @@ internal interface ContextualActivitySampleSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HeartRateSync.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HeartRateSync.kt index 75535459ad..726736766b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HeartRateSync.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/HeartRateSync.kt @@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtils import org.slf4j.LoggerFactory import java.time.Instant +import java.time.ZoneId import java.time.ZoneOffset import java.time.ZonedDateTime @@ -36,7 +37,7 @@ internal object HeartRateSyncer : ActivitySampleSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, @@ -99,7 +100,7 @@ internal object HeartRateSyncer : ActivitySampleSyncer { recordEndTime, currentHcSamples.size ) - heartRateRecordList.add(HeartRateRecord(recordStartTime, offset, recordEndTime, offset, ArrayList(currentHcSamples), metadata)) + heartRateRecordList.add(HeartRateRecord(recordStartTime, offset.rules.getOffset(recordStartTime), recordEndTime, offset.rules.getOffset(recordEndTime), ArrayList(currentHcSamples), metadata)) } else { LOG.warn("Skipping HeartRateRecord for device '$deviceName' from $recordStartTime to $recordEndTime due to invalid duration even after adjustment.") } @@ -126,7 +127,7 @@ internal object HeartRateSyncer : ActivitySampleSyncer { recordEndTime, currentHcSamples.size ) - heartRateRecordList.add(HeartRateRecord(recordStartTime, offset, recordEndTime, offset, ArrayList(currentHcSamples), metadata)) + heartRateRecordList.add(HeartRateRecord(recordStartTime, offset.rules.getOffset(recordStartTime), recordEndTime, offset.rules.getOffset(recordEndTime), ArrayList(currentHcSamples), metadata)) } else { LOG.warn("Skipping final HeartRateRecord for device '$deviceName' from $recordStartTime to $recordEndTime due to invalid duration even after adjustment.") } 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 13038d8158..01c871df85 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 @@ -52,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtils import org.slf4j.LoggerFactory import java.time.Instant +import java.time.ZoneId import java.time.ZoneOffset import java.util.Date @@ -69,7 +70,7 @@ internal object RecordedWorkoutSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + zoneId: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, @@ -116,6 +117,8 @@ internal object RecordedWorkoutSyncer { workoutsProcessedInThisSlice++ LOG.info("Processing workout for device '$deviceName' (Type: ${workout.activityKind}, Start: $workoutStartInstant, End: $workoutEndInstant).") + val offset = zoneId.rules.getOffset(workoutStartInstant) + val recordsToInsert = mutableListOf() val activityKind = ActivityKind.fromCode(workout.activityKind) val exerciseType = WorkoutSyncerUtils.mapActivityKindToExerciseType(activityKind) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/SleepSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/SleepSyncer.kt index 541d85971f..87b000fec3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/SleepSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/SleepSyncer.kt @@ -28,7 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtils import org.slf4j.LoggerFactory import java.time.Instant -import java.time.ZoneOffset +import java.time.ZoneId private val LOG = LoggerFactory.getLogger("SleepSyncer") @@ -38,7 +38,7 @@ internal object SleepSyncer : ContextualActivitySampleSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set, @@ -114,7 +114,7 @@ internal object SleepSyncer : ContextualActivitySampleSyncer { sortedDeviceSamples: List, sliceStartBoundary: Instant, sliceEndBoundary: Instant, - offset: ZoneOffset, + offset: ZoneId, metadata: Metadata, context: Context, deviceName: String @@ -182,9 +182,9 @@ internal object SleepSyncer : ContextualActivitySampleSyncer { return SleepSessionRecord( startTime = recordFinalStartTime, - startZoneOffset = offset, + startZoneOffset = offset.rules.getOffset(recordFinalStartTime), endTime = recordFinalEndTime, - endZoneOffset = offset, + endZoneOffset = offset.rules.getOffset(recordFinalEndTime), title = context.getString(nodomain.freeyourgadget.gadgetbridge.R.string.health_connect_sleep_session_title, deviceName), notes = context.getString(nodomain.freeyourgadget.gadgetbridge.R.string.health_connect_sleep_session_notes, deviceName), stages = stages, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/TemperatureSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/TemperatureSyncer.kt index fd1ebf6c2a..bf3bfce0c9 100755 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/TemperatureSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/TemperatureSyncer.kt @@ -31,7 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.HealthConnectUtil import nodomain.freeyourgadget.gadgetbridge.util.healthconnect.SyncException import org.slf4j.LoggerFactory import java.time.Instant -import java.time.ZoneOffset +import java.time.ZoneId import java.time.temporal.ChronoUnit private val LOG = LoggerFactory.getLogger("TemperatureSyncer") @@ -47,7 +47,7 @@ internal object TemperatureSyncer : HealthConnectSyncer { healthConnectClient: HealthConnectClient, gbDevice: GBDevice, metadata: Metadata, - offset: ZoneOffset, + offset: ZoneId, sliceStartBoundary: Instant, sliceEndBoundary: Instant, grantedPermissions: Set @@ -108,7 +108,7 @@ internal object TemperatureSyncer : HealthConnectSyncer { recordsToInsert.add( BodyTemperatureRecord( time = timestamp, - zoneOffset = offset, + zoneOffset = offset.rules.getOffset(timestamp), temperature = Temperature.celsius(sampleTemp), measurementLocation = sample.temperatureLocation, metadata = metadata @@ -178,9 +178,9 @@ internal object TemperatureSyncer : HealthConnectSyncer { recordsToInsert.add( SkinTemperatureRecord( startTime = recordStartTime, - startZoneOffset = offset, + startZoneOffset = offset.rules.getOffset(recordStartTime), endTime = recordEndTime, - endZoneOffset = offset, + endZoneOffset = offset.rules.getOffset(recordEndTime), deltas = deltas, baseline = Temperature.celsius(baselineForCurrentRecord), metadata = metadata