@cariva-dev/exercise-sdk 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CarivaExerciseSdk.podspec +20 -0
- package/README.md +374 -0
- package/android/build.gradle +66 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/com/carivaexercisesdk/CarivaExerciseSdkPackage.kt +30 -0
- package/android/src/main/java/com/carivaexercisesdk/HealthConnectModule.kt +222 -0
- package/android/src/main/java/com/carivaexercisesdk/HealthConnectPermissionUsageActivity.kt +11 -0
- package/android/src/main/java/com/carivaexercisesdk/HealthConnectPermissionsRationaleActivity.kt +11 -0
- package/android/src/main/java/com/carivaexercisesdk/Pagination.kt +23 -0
- package/android/src/main/java/com/carivaexercisesdk/application/connection/command/ConnectCommand.kt +12 -0
- package/android/src/main/java/com/carivaexercisesdk/application/connection/dto/ConnectResultDto.kt +13 -0
- package/android/src/main/java/com/carivaexercisesdk/application/connection/handler/ConnectHandler.kt +79 -0
- package/android/src/main/java/com/carivaexercisesdk/application/connection/port/HealthConnectConnectionPort.kt +16 -0
- package/android/src/main/java/com/carivaexercisesdk/application/connection/port/PermissionRequestPort.kt +5 -0
- package/android/src/main/java/com/carivaexercisesdk/application/datasource/command/SetDatasourcePolicyCommand.kt +6 -0
- package/android/src/main/java/com/carivaexercisesdk/application/datasource/handler/GetDatasourcePolicyHandler.kt +10 -0
- package/android/src/main/java/com/carivaexercisesdk/application/datasource/handler/SetDatasourcePolicyHandler.kt +22 -0
- package/android/src/main/java/com/carivaexercisesdk/application/datasource/port/DatasourcePolicyRepository.kt +9 -0
- package/android/src/main/java/com/carivaexercisesdk/application/exercise/dto/BasalReadResultDto.kt +11 -0
- package/android/src/main/java/com/carivaexercisesdk/application/exercise/dto/ExerciseDataDto.kt +41 -0
- package/android/src/main/java/com/carivaexercisesdk/application/exercise/handler/GetExerciseDataHandler.kt +346 -0
- package/android/src/main/java/com/carivaexercisesdk/application/exercise/port/ExerciseRecordPort.kt +45 -0
- package/android/src/main/java/com/carivaexercisesdk/application/exercise/query/GetExerciseDataQuery.kt +9 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/connection/entity/ConnectionAggregate.kt +13 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/connection/service/ConnectionDecisionService.kt +37 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/connection/valueobject/ConnectionNextAction.kt +8 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/connection/valueobject/HealthConnectStatus.kt +8 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/connection/valueobject/PermissionScope.kt +36 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/datasource/entity/DatasourcePolicy.kt +8 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/datasource/valueobject/DatasourceType.kt +14 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/ExerciseDomainService.kt +89 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectCaloriesFallbackMerger.kt +351 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectInternalsConstants.kt +55 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectModuleInternals.kt +316 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectOverlapNormalizer.kt +400 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectSourceTrust.kt +249 -0
- package/android/src/main/java/com/carivaexercisesdk/domain/exercise/services/HealthConnectUnifiedRecordBuilder.kt +316 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/healthconnect/HealthConnectConnectionAdapter.kt +156 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/healthconnect/HealthConnectExerciseRecordAdapter.kt +464 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/persistence/InMemoryDatasourcePolicyRepository.kt +21 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/reactnative/ConnectResultMapper.kt +23 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/reactnative/DatasourcePolicyJsonParser.kt +51 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/reactnative/DatasourcePolicyMapper.kt +46 -0
- package/android/src/main/java/com/carivaexercisesdk/infrastructure/reactnative/ExerciseDataMapper.kt +99 -0
- package/android/src/test/java/com/carivaexercisesdk/ArchitectureDependencyRuleTest.kt +60 -0
- package/android/src/test/java/com/carivaexercisesdk/HealthConnectModuleDatasourceParserTest.kt +69 -0
- package/android/src/test/java/com/carivaexercisesdk/HealthConnectModuleInternalsTest.kt +406 -0
- package/android/src/test/java/com/carivaexercisesdk/application/connection/handler/ConnectHandlerTest.kt +153 -0
- package/android/src/test/java/com/carivaexercisesdk/application/datasource/handler/DatasourcePolicyRoundTripTest.kt +63 -0
- package/android/src/test/java/com/carivaexercisesdk/application/datasource/handler/SetDatasourcePolicyHandlerTest.kt +42 -0
- package/android/src/test/java/com/carivaexercisesdk/domain/connection/service/ConnectionDecisionServiceTest.kt +68 -0
- package/android/src/test/java/com/carivaexercisesdk/infrastructure/reactnative/DatasourcePolicyMapperTest.kt +22 -0
- package/ios/CarivaExerciseSdk.h +5 -0
- package/ios/CarivaExerciseSdk.mm +7 -0
- package/lib/module/connect/index.js +7 -0
- package/lib/module/connect/index.js.map +1 -0
- package/lib/module/datasource/index.js +10 -0
- package/lib/module/datasource/index.js.map +1 -0
- package/lib/module/exercise/index.js +7 -0
- package/lib/module/exercise/index.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/module.js +13 -0
- package/lib/module/native/module.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/connect/index.d.ts +16 -0
- package/lib/typescript/src/connect/index.d.ts.map +1 -0
- package/lib/typescript/src/datasource/index.d.ts +12 -0
- package/lib/typescript/src/datasource/index.d.ts.map +1 -0
- package/lib/typescript/src/exercise/index.d.ts +64 -0
- package/lib/typescript/src/exercise/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/native/module.d.ts +14 -0
- package/lib/typescript/src/native/module.d.ts.map +1 -0
- package/package.json +127 -0
- package/src/connect/index.ts +34 -0
- package/src/datasource/index.ts +20 -0
- package/src/exercise/index.ts +75 -0
- package/src/index.tsx +22 -0
- package/src/native/module.ts +23 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
package com.carivaexercisesdk.domain.exercise.services
|
|
2
|
+
|
|
3
|
+
import java.time.Duration
|
|
4
|
+
import java.time.Instant
|
|
5
|
+
import java.time.ZoneId
|
|
6
|
+
import java.time.format.DateTimeFormatter
|
|
7
|
+
import kotlin.math.pow
|
|
8
|
+
import kotlin.math.round
|
|
9
|
+
|
|
10
|
+
internal object HealthConnectModuleInternals {
|
|
11
|
+
enum class MetricType {
|
|
12
|
+
STEPS,
|
|
13
|
+
ACTIVE_TIME,
|
|
14
|
+
CALORIES,
|
|
15
|
+
DISTANCE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
data class IntervalInput(
|
|
19
|
+
val startMs: Long,
|
|
20
|
+
val endMs: Long,
|
|
21
|
+
val totalValue: Double,
|
|
22
|
+
val sourceType: String,
|
|
23
|
+
val packageName: String,
|
|
24
|
+
val deviceModel: String = ""
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
data class NormalizedSegment(
|
|
28
|
+
val startMs: Long,
|
|
29
|
+
val endMs: Long,
|
|
30
|
+
val value: Double,
|
|
31
|
+
val sourceType: String,
|
|
32
|
+
val packageName: String,
|
|
33
|
+
val deviceModel: String = "",
|
|
34
|
+
val normalized: Boolean = true
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
data class NormalizationStats(
|
|
38
|
+
val droppedNonPositiveCount: Int = 0,
|
|
39
|
+
val unknownSourceCount: Int = 0,
|
|
40
|
+
val observedIntervals: Int = 0
|
|
41
|
+
) {
|
|
42
|
+
operator fun plus(other: NormalizationStats): NormalizationStats {
|
|
43
|
+
return NormalizationStats(
|
|
44
|
+
droppedNonPositiveCount = droppedNonPositiveCount + other.droppedNonPositiveCount,
|
|
45
|
+
unknownSourceCount = unknownSourceCount + other.unknownSourceCount,
|
|
46
|
+
observedIntervals = observedIntervals + other.observedIntervals
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
data class NormalizationResult(
|
|
52
|
+
val segments: List<NormalizedSegment>,
|
|
53
|
+
val stats: NormalizationStats,
|
|
54
|
+
val overlapStrategy: String,
|
|
55
|
+
val warnings: List<String> = emptyList(),
|
|
56
|
+
val diagnostics: Diagnostics? = null
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
data class Diagnostics(
|
|
60
|
+
val fallbackUsedSegments: Int = 0,
|
|
61
|
+
val fallbackSuppressedSegments: Int = 0,
|
|
62
|
+
val idleGateSuppressedSegments: Int = 0,
|
|
63
|
+
val basalSeedApplied: Boolean = false,
|
|
64
|
+
val seededFromBeforeSince: Boolean = false,
|
|
65
|
+
val basalSeedAgeHours: Double? = null,
|
|
66
|
+
val directActiveCaloriesKcal: Double = 0.0,
|
|
67
|
+
val totalCaloriesKcal: Double = 0.0,
|
|
68
|
+
val basalCaloriesKcal: Double = 0.0,
|
|
69
|
+
val mergedActiveCaloriesKcal: Double = 0.0,
|
|
70
|
+
val fallbackContributionKcal: Double = 0.0
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
data class UnifiedIntervalRecord(
|
|
74
|
+
val steps: Double,
|
|
75
|
+
val activeCalories: Double,
|
|
76
|
+
val activeCaloriesUnit: String,
|
|
77
|
+
val distance: Double,
|
|
78
|
+
val distanceUnit: String,
|
|
79
|
+
val activeTime: Double,
|
|
80
|
+
val activeTimeUnit: String,
|
|
81
|
+
val startDate: String,
|
|
82
|
+
val endDate: String,
|
|
83
|
+
val meta: UnifiedRecordMeta
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
data class UnifiedRecordMeta(
|
|
87
|
+
val source: String,
|
|
88
|
+
val device: String,
|
|
89
|
+
val deviceModel: String,
|
|
90
|
+
val trustLevel: String
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
data class UnifiedRecordsBuildResult(
|
|
94
|
+
val records: List<UnifiedIntervalRecord>,
|
|
95
|
+
val warnings: List<String>,
|
|
96
|
+
val projectionPreserved: Boolean,
|
|
97
|
+
val roundingScale: Int
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
data class RecordTrustResult(
|
|
101
|
+
val allowed: Boolean,
|
|
102
|
+
val reason: String,
|
|
103
|
+
val sourceType: String,
|
|
104
|
+
val trustLevel: String
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
fun isSupportedBucketPeriod(bucketPeriod: String): Boolean {
|
|
108
|
+
val normalized = bucketPeriod.trim().lowercase()
|
|
109
|
+
return normalized == HealthConnectInternalsConstants.SUPPORTED_HOURLY ||
|
|
110
|
+
normalized == HealthConnectInternalsConstants.SUPPORTED_DAILY
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fun normalizeBucketPeriod(bucketPeriod: String): String {
|
|
114
|
+
return bucketPeriod.trim().lowercase()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fun normalizePermissionScope(scopeValue: String): String? {
|
|
118
|
+
return when (scopeValue.trim().lowercase()) {
|
|
119
|
+
HealthConnectInternalsConstants.SCOPE_STEPS -> HealthConnectInternalsConstants.SCOPE_STEPS
|
|
120
|
+
HealthConnectInternalsConstants.SCOPE_ACTIVE_TIMES ->
|
|
121
|
+
HealthConnectInternalsConstants.SCOPE_ACTIVE_TIMES
|
|
122
|
+
HealthConnectInternalsConstants.SCOPE_CALORIES ->
|
|
123
|
+
HealthConnectInternalsConstants.SCOPE_CALORIES
|
|
124
|
+
HealthConnectInternalsConstants.SCOPE_DISTANCES ->
|
|
125
|
+
HealthConnectInternalsConstants.SCOPE_DISTANCES
|
|
126
|
+
else -> null
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fun normalizePermissionScopes(scopeValues: List<String>?): Set<String> {
|
|
131
|
+
if (scopeValues.isNullOrEmpty()) {
|
|
132
|
+
return emptySet()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return scopeValues.mapNotNull { normalizePermissionScope(it) }.toSet()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fun findUnsupportedPermissionScopes(scopeValues: List<String>?): Set<String> {
|
|
139
|
+
if (scopeValues.isNullOrEmpty()) {
|
|
140
|
+
return emptySet()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return scopeValues
|
|
144
|
+
.map { it.trim() }
|
|
145
|
+
.filter { normalizePermissionScope(it) == null }
|
|
146
|
+
.toSet()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
fun defaultPermissionScopes(): Set<String> {
|
|
150
|
+
return setOf(
|
|
151
|
+
HealthConnectInternalsConstants.SCOPE_STEPS,
|
|
152
|
+
HealthConnectInternalsConstants.SCOPE_ACTIVE_TIMES,
|
|
153
|
+
HealthConnectInternalsConstants.SCOPE_CALORIES,
|
|
154
|
+
HealthConnectInternalsConstants.SCOPE_DISTANCES
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
fun toKilometers(distanceMeters: Double): Double {
|
|
159
|
+
return distanceMeters / 1000.0
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fun roundToScale(value: Double, scale: Int = 5): Double {
|
|
163
|
+
val factor = 10.0.pow(scale.toDouble())
|
|
164
|
+
return round(value * factor) / factor
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
fun toIsoOffsetString(epochMillis: Long, zoneId: ZoneId): String {
|
|
168
|
+
return Instant.ofEpochMilli(epochMillis)
|
|
169
|
+
.atZone(zoneId)
|
|
170
|
+
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fun buildUnifiedIntervalRecords(
|
|
174
|
+
stepsSegments: List<NormalizedSegment>,
|
|
175
|
+
activeTimeSegments: List<NormalizedSegment>,
|
|
176
|
+
caloriesSegments: List<NormalizedSegment>,
|
|
177
|
+
distanceSegments: List<NormalizedSegment>,
|
|
178
|
+
zoneId: ZoneId,
|
|
179
|
+
roundingScale: Int = 5
|
|
180
|
+
): List<UnifiedIntervalRecord> {
|
|
181
|
+
return HealthConnectUnifiedRecordBuilder.buildUnifiedIntervalRecords(
|
|
182
|
+
stepsSegments = stepsSegments,
|
|
183
|
+
activeTimeSegments = activeTimeSegments,
|
|
184
|
+
caloriesSegments = caloriesSegments,
|
|
185
|
+
distanceSegments = distanceSegments,
|
|
186
|
+
zoneId = zoneId,
|
|
187
|
+
roundingScale = roundingScale
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fun buildUnifiedRecordsResult(
|
|
192
|
+
stepsSegments: List<NormalizedSegment>,
|
|
193
|
+
activeTimeSegments: List<NormalizedSegment>,
|
|
194
|
+
caloriesSegments: List<NormalizedSegment>,
|
|
195
|
+
distanceSegments: List<NormalizedSegment>,
|
|
196
|
+
zoneId: ZoneId,
|
|
197
|
+
roundingScale: Int = 5
|
|
198
|
+
): UnifiedRecordsBuildResult {
|
|
199
|
+
return HealthConnectUnifiedRecordBuilder.buildUnifiedRecordsResult(
|
|
200
|
+
stepsSegments = stepsSegments,
|
|
201
|
+
activeTimeSegments = activeTimeSegments,
|
|
202
|
+
caloriesSegments = caloriesSegments,
|
|
203
|
+
distanceSegments = distanceSegments,
|
|
204
|
+
zoneId = zoneId,
|
|
205
|
+
roundingScale = roundingScale
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fun isValidPeriod(startInstant: Instant, endInstant: Instant, maxDays: Long = 90): Boolean {
|
|
210
|
+
if (startInstant.isAfter(endInstant)) {
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
val duration = Duration.between(startInstant, endInstant)
|
|
215
|
+
val maxDuration = Duration.ofDays(maxDays)
|
|
216
|
+
return duration <= maxDuration
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fun normalizeAllowlist(sources: List<String>): Set<String> {
|
|
220
|
+
return sources
|
|
221
|
+
.map { it.trim() }
|
|
222
|
+
.filter { it.isNotEmpty() }
|
|
223
|
+
.map { normalizeSourceType(it) }
|
|
224
|
+
.toSet()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
fun normalizePackageAllowlist(packages: List<String>): Set<String> {
|
|
228
|
+
return packages
|
|
229
|
+
.map { it.trim().lowercase() }
|
|
230
|
+
.filter { it.isNotEmpty() }
|
|
231
|
+
.toSet()
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
fun normalizeSourceType(rawValue: String): String {
|
|
235
|
+
return HealthConnectSourceTrust.normalizeSourceType(rawValue)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
fun normalizeSourceType(rawValue: Any?): String {
|
|
239
|
+
return HealthConnectSourceTrust.normalizeSourceType(rawValue)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
fun evaluateRecordTrust(metadata: Any?): RecordTrustResult {
|
|
243
|
+
return HealthConnectSourceTrust.evaluateRecordTrust(metadata)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fun resolveTrustLevelFromSource(sourceType: String): String {
|
|
247
|
+
return HealthConnectSourceTrust.resolveTrustLevelFromSource(sourceType)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
fun resolveDeviceModel(metadata: Any?): String {
|
|
251
|
+
return HealthConnectSourceTrust.resolveDeviceModel(metadata)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
fun isRecordAllowed(sourceType: String, allowlist: Set<String>): Boolean {
|
|
255
|
+
return HealthConnectSourceTrust.isRecordAllowed(sourceType, allowlist)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
fun isPackageAllowed(packageName: String?, packageAllowlist: Set<String>): Boolean {
|
|
259
|
+
if (packageAllowlist.isEmpty()) {
|
|
260
|
+
return true
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
val normalizedPackageName = packageName?.trim()?.lowercase().orEmpty()
|
|
264
|
+
if (normalizedPackageName.isEmpty()) {
|
|
265
|
+
return false
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return packageAllowlist.contains(normalizedPackageName)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fun normalizeOverlaps(
|
|
272
|
+
metricType: MetricType,
|
|
273
|
+
rawIntervals: List<IntervalInput>,
|
|
274
|
+
sinceMs: Long,
|
|
275
|
+
untilMs: Long,
|
|
276
|
+
bucketPeriod: String,
|
|
277
|
+
zoneId: ZoneId
|
|
278
|
+
): NormalizationResult {
|
|
279
|
+
return HealthConnectOverlapNormalizer.normalizeOverlaps(
|
|
280
|
+
metricType = metricType,
|
|
281
|
+
rawIntervals = rawIntervals,
|
|
282
|
+
sinceMs = sinceMs,
|
|
283
|
+
untilMs = untilMs,
|
|
284
|
+
bucketPeriod = bucketPeriod,
|
|
285
|
+
zoneId = zoneId
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
fun mergeCaloriesWithFallback(
|
|
290
|
+
primaryActiveCalories: NormalizationResult,
|
|
291
|
+
totalCalories: NormalizationResult,
|
|
292
|
+
basalCalories: NormalizationResult,
|
|
293
|
+
stepsEvidenceSegments: List<NormalizedSegment> = emptyList(),
|
|
294
|
+
activeTimeEvidenceSegments: List<NormalizedSegment> = emptyList(),
|
|
295
|
+
distanceEvidenceSegments: List<NormalizedSegment> = emptyList(),
|
|
296
|
+
basalSeedApplied: Boolean = false,
|
|
297
|
+
seededFromBeforeSince: Boolean = false,
|
|
298
|
+
basalSeedAgeHours: Double? = null
|
|
299
|
+
): NormalizationResult {
|
|
300
|
+
return HealthConnectCaloriesFallbackMerger.mergeCaloriesWithFallback(
|
|
301
|
+
primaryActiveCalories = primaryActiveCalories,
|
|
302
|
+
totalCalories = totalCalories,
|
|
303
|
+
basalCalories = basalCalories,
|
|
304
|
+
stepsEvidenceSegments = stepsEvidenceSegments,
|
|
305
|
+
activeTimeEvidenceSegments = activeTimeEvidenceSegments,
|
|
306
|
+
distanceEvidenceSegments = distanceEvidenceSegments,
|
|
307
|
+
basalSeedApplied = basalSeedApplied,
|
|
308
|
+
seededFromBeforeSince = seededFromBeforeSince,
|
|
309
|
+
basalSeedAgeHours = basalSeedAgeHours
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
fun nextBucketBoundary(timeMs: Long, zoneId: ZoneId, bucketPeriod: String): Long {
|
|
314
|
+
return HealthConnectOverlapNormalizer.nextBucketBoundary(timeMs, zoneId, bucketPeriod)
|
|
315
|
+
}
|
|
316
|
+
}
|