• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.healthconnect.testapps.toolbox.seed
17 
18 import android.content.Context
19 import android.health.connect.HealthConnectManager
20 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord
21 import android.health.connect.datatypes.ActivityIntensityRecord
22 import android.health.connect.datatypes.ActivityIntensityRecord.ACTIVITY_INTENSITY_TYPE_MODERATE
23 import android.health.connect.datatypes.ActivityIntensityRecord.ACTIVITY_INTENSITY_TYPE_VIGOROUS
24 import android.health.connect.datatypes.CyclingPedalingCadenceRecord
25 import android.health.connect.datatypes.CyclingPedalingCadenceRecord.CyclingPedalingCadenceRecordSample
26 import android.health.connect.datatypes.DistanceRecord
27 import android.health.connect.datatypes.ElevationGainedRecord
28 import android.health.connect.datatypes.ExerciseCompletionGoal
29 import android.health.connect.datatypes.ExerciseLap
30 import android.health.connect.datatypes.ExercisePerformanceGoal
31 import android.health.connect.datatypes.ExerciseSegment
32 import android.health.connect.datatypes.ExerciseSegmentType
33 import android.health.connect.datatypes.ExerciseSessionRecord
34 import android.health.connect.datatypes.ExerciseSessionType
35 import android.health.connect.datatypes.FloorsClimbedRecord
36 import android.health.connect.datatypes.PlannedExerciseBlock
37 import android.health.connect.datatypes.PlannedExerciseSessionRecord
38 import android.health.connect.datatypes.PlannedExerciseStep
39 import android.health.connect.datatypes.PlannedExerciseStep.EXERCISE_CATEGORY_ACTIVE
40 import android.health.connect.datatypes.PlannedExerciseStep.EXERCISE_CATEGORY_COOLDOWN
41 import android.health.connect.datatypes.PlannedExerciseStep.EXERCISE_CATEGORY_REST
42 import android.health.connect.datatypes.PlannedExerciseStep.EXERCISE_CATEGORY_WARMUP
43 import android.health.connect.datatypes.PowerRecord
44 import android.health.connect.datatypes.PowerRecord.PowerRecordSample
45 import android.health.connect.datatypes.SpeedRecord
46 import android.health.connect.datatypes.SpeedRecord.SpeedRecordSample
47 import android.health.connect.datatypes.StepsCadenceRecord
48 import android.health.connect.datatypes.StepsCadenceRecord.StepsCadenceRecordSample
49 import android.health.connect.datatypes.StepsRecord
50 import android.health.connect.datatypes.TotalCaloriesBurnedRecord
51 import android.health.connect.datatypes.Vo2MaxRecord
52 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_COOPER_TEST
53 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_HEART_RATE_RATIO
54 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_METABOLIC_CART
55 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_MULTISTAGE_FITNESS_TEST
56 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_OTHER
57 import android.health.connect.datatypes.Vo2MaxRecord.Vo2MaxMeasurementMethod.MEASUREMENT_METHOD_ROCKPORT_FITNESS_TEST
58 import android.health.connect.datatypes.WheelchairPushesRecord
59 import android.health.connect.datatypes.units.Energy
60 import android.health.connect.datatypes.units.Length
61 import android.health.connect.datatypes.units.Power
62 import android.health.connect.datatypes.units.Velocity
63 import com.android.healthconnect.testapps.toolbox.data.ExerciseRoutesTestData
64 import com.android.healthconnect.testapps.toolbox.data.ExerciseRoutesTestData.Companion.generateExerciseRouteFromLocations
65 import com.android.healthconnect.testapps.toolbox.data.ExerciseRoutesTestData.Companion.routeDataMap
66 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.getMetaData
67 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.insertRecords
68 import kotlinx.coroutines.runBlocking
69 import java.time.Duration.ofDays
70 import java.time.Duration.ofMinutes
71 import java.time.Duration.ofSeconds
72 import java.time.Instant
73 import java.time.temporal.ChronoUnit
74 import kotlin.random.Random
75 
76 class SeedActivityData(private val context: Context, private val manager: HealthConnectManager) {
77 
78     companion object {
79         val VALID_VO2_MEASUREMENT_METHOD =
80             setOf(
81                 MEASUREMENT_METHOD_OTHER,
82                 MEASUREMENT_METHOD_METABOLIC_CART,
83                 MEASUREMENT_METHOD_HEART_RATE_RATIO,
84                 MEASUREMENT_METHOD_COOPER_TEST,
85                 MEASUREMENT_METHOD_MULTISTAGE_FITNESS_TEST,
86                 MEASUREMENT_METHOD_ROCKPORT_FITNESS_TEST,
87             )
88     }
89 
90     private val start = Instant.now().truncatedTo(ChronoUnit.DAYS)
91     private val yesterday = start.minus(ofDays(1))
92     private val lastWeek = start.minus(ofDays(7))
93     private val lastMonth = start.minus(ofDays(31))
94 
95     fun seedActivityData() {
96         runBlocking {
97             try {
98                 seedActivityIntensityData()
99                 seedStepsData()
100                 seedDistanceData()
101                 seedElevationGainedRecord()
102                 seedActiveCaloriesBurnedData()
103                 seedExerciseSessionData()
104                 seedPlannedExerciseSessionRecord()
105                 seedSpeedRecord()
106                 seedPowerRecord()
107                 seedCyclingPedalingCadenceRecord()
108                 seedFloorsClimbedRecord()
109                 seedTotalCaloriesBurnedRecord()
110                 seedWheelchairPushesRecord()
111                 seedVo2MaxRecord()
112                 seedStepsCadenceRecord()
113             } catch (ex: Exception) {
114                 throw ex
115             }
116         }
117     }
118 
119     private suspend fun seedActivityIntensityData() {
120         val records =
121             listOf(start, yesterday, lastWeek, lastMonth).flatMap { baseTime ->
122                 List(3) {
123                     val startTime = baseTime.plus(ofMinutes(5 * it.toLong()))
124 
125                     ActivityIntensityRecord.Builder(
126                             getMetaData(context),
127                             startTime,
128                             startTime.plus(ofMinutes(3)),
129                             if (Random.nextBoolean()) ACTIVITY_INTENSITY_TYPE_MODERATE
130                             else ACTIVITY_INTENSITY_TYPE_VIGOROUS,
131                         )
132                         .build()
133                 }
134             }
135 
136         insertRecords(records, manager)
137     }
138 
139     private suspend fun seedStepsData() {
140         val records = (1L..50).map { count -> getStepsRecord(count, start.plus(ofMinutes(count))) }
141         val yesterdayRecords =
142             (1L..3).map { count -> getStepsRecord(count, yesterday.plus(ofMinutes(count))) }
143         val lastWeekRecords =
144             (1L..3).map { count -> getStepsRecord(count, lastWeek.plus(ofMinutes(count))) }
145         val lastMonthRecords =
146             (1L..3).map { count -> getStepsRecord(count, lastMonth.plus(ofMinutes(count))) }
147 
148         insertRecords(records, manager)
149         insertRecords(yesterdayRecords, manager)
150         insertRecords(lastWeekRecords, manager)
151         insertRecords(lastMonthRecords, manager)
152     }
153 
154     private suspend fun seedDistanceData() {
155         val records =
156             (1L..50).map { timeOffSet ->
157                 getDistanceData(getValidLengthData(500, 5000), start.plus(ofMinutes(timeOffSet)))
158             }
159         val yesterdayRecords =
160             (1L..3).map { timeOffSet ->
161                 getDistanceData(
162                     getValidLengthData(500, 5000),
163                     yesterday.plus(ofMinutes(timeOffSet)),
164                 )
165             }
166         val lastWeekRecords =
167             (1L..3).map { timeOffSet ->
168                 getDistanceData(getValidLengthData(500, 5000), lastWeek.plus(ofMinutes(timeOffSet)))
169             }
170         val lastMonthRecords =
171             (1L..3).map { timeOffSet ->
172                 getDistanceData(
173                     getValidLengthData(500, 5000),
174                     lastMonth.plus(ofMinutes(timeOffSet)),
175                 )
176             }
177 
178         insertRecords(records, manager)
179         insertRecords(yesterdayRecords, manager)
180         insertRecords(lastWeekRecords, manager)
181         insertRecords(lastMonthRecords, manager)
182     }
183 
184     private suspend fun seedElevationGainedRecord() {
185         val records =
186             (1L..3).map { timeOffSet ->
187                 getElevationGainedRecord(
188                     getValidLengthData(500, 5000),
189                     start.plus(ofMinutes(timeOffSet)),
190                 )
191             }
192         val yesterdayRecords =
193             (1L..3).map { timeOffSet ->
194                 getElevationGainedRecord(
195                     getValidLengthData(500, 5000),
196                     yesterday.plus(ofMinutes(timeOffSet)),
197                 )
198             }
199         val lastWeekRecords =
200             (1L..3).map { timeOffSet ->
201                 getElevationGainedRecord(
202                     getValidLengthData(500, 5000),
203                     lastWeek.plus(ofMinutes(timeOffSet)),
204                 )
205             }
206         val lastMonthRecords =
207             (1L..3).map { timeOffSet ->
208                 getElevationGainedRecord(
209                     getValidLengthData(500, 5000),
210                     lastMonth.plus(ofMinutes(timeOffSet)),
211                 )
212             }
213 
214         insertRecords(records, manager)
215         insertRecords(yesterdayRecords, manager)
216         insertRecords(lastWeekRecords, manager)
217         insertRecords(lastMonthRecords, manager)
218     }
219 
220     private suspend fun seedActiveCaloriesBurnedData() {
221         val records =
222             (1L..15).map { timeOffSet ->
223                 getActiveCaloriesBurnedRecord(getValidEnergy(), start.plus(ofMinutes(timeOffSet)))
224             }
225         val yesterdayRecords =
226             (1L..3).map { timeOffSet ->
227                 getActiveCaloriesBurnedRecord(
228                     getValidEnergy(),
229                     yesterday.plus(ofMinutes(timeOffSet)),
230                 )
231             }
232         val lastWeekRecords =
233             (1L..3).map { timeOffSet ->
234                 getActiveCaloriesBurnedRecord(
235                     getValidEnergy(),
236                     lastWeek.plus(ofMinutes(timeOffSet)),
237                 )
238             }
239         val lastMonthRecords =
240             (1L..3).map { timeOffSet ->
241                 getActiveCaloriesBurnedRecord(
242                     getValidEnergy(),
243                     lastMonth.plus(ofMinutes(timeOffSet)),
244                 )
245             }
246 
247         insertRecords(records, manager)
248         insertRecords(yesterdayRecords, manager)
249         insertRecords(lastWeekRecords, manager)
250         insertRecords(lastMonthRecords, manager)
251     }
252 
253     private suspend fun seedExerciseSessionData() {
254         val records =
255             (1L..3).map { timeOffSet ->
256                 val exerciseSegments = ArrayList<ExerciseSegment>()
257                 repeat(5) { i ->
258                     exerciseSegments.add(
259                         ExerciseSegment.Builder(
260                                 start.plus(ofMinutes(timeOffSet + i)),
261                                 start.plus(ofMinutes(timeOffSet + i + 1)),
262                                 getValidSegmentType(),
263                             )
264                             .build()
265                     )
266                 }
267                 val exerciseLaps = ArrayList<ExerciseLap>()
268                 repeat(5) { i ->
269                     exerciseLaps.add(
270                         ExerciseLap.Builder(
271                                 start.plus(ofMinutes(timeOffSet + i)),
272                                 start.plus(ofMinutes(timeOffSet + i + 1)),
273                             )
274                             .setLength(getValidLengthData(50, 1050))
275                             .build()
276                     )
277                 }
278 
279                 getExerciseSessionRecord(
280                     exerciseSegments,
281                     exerciseLaps,
282                     start.plus(ofMinutes(timeOffSet)),
283                 )
284             }
285         val yesterdayRecords =
286             (1L..3).map { timeOffSet ->
287                 val exerciseSegments = ArrayList<ExerciseSegment>()
288                 repeat(5) { i ->
289                     exerciseSegments.add(
290                         ExerciseSegment.Builder(
291                                 yesterday.plus(ofMinutes(timeOffSet + i)),
292                                 yesterday.plus(ofMinutes(timeOffSet + i + 1)),
293                                 getValidSegmentType(),
294                             )
295                             .build()
296                     )
297                 }
298                 val exerciseLaps = ArrayList<ExerciseLap>()
299                 repeat(5) { i ->
300                     exerciseLaps.add(
301                         ExerciseLap.Builder(
302                                 yesterday.plus(ofMinutes(timeOffSet + i)),
303                                 yesterday.plus(ofMinutes(timeOffSet + i + 1)),
304                             )
305                             .setLength(getValidLengthData(50, 1050))
306                             .build()
307                     )
308                 }
309                 getExerciseSessionRecord(
310                     exerciseSegments,
311                     exerciseLaps,
312                     yesterday.plus(ofMinutes(timeOffSet)),
313                 )
314             }
315         val lastWeekRecords =
316             (1L..3).map { timeOffSet ->
317                 val exerciseSegments = ArrayList<ExerciseSegment>()
318                 repeat(5) { i ->
319                     exerciseSegments.add(
320                         ExerciseSegment.Builder(
321                                 lastWeek.plus(ofMinutes(timeOffSet + i)),
322                                 lastWeek.plus(ofMinutes(timeOffSet + i + 1)),
323                                 getValidSegmentType(),
324                             )
325                             .build()
326                     )
327                 }
328                 val exerciseLaps = ArrayList<ExerciseLap>()
329                 repeat(5) { i ->
330                     exerciseLaps.add(
331                         ExerciseLap.Builder(
332                                 lastWeek.plus(ofMinutes(timeOffSet + i)),
333                                 lastWeek.plus(ofMinutes(timeOffSet + i + 1)),
334                             )
335                             .setLength(getValidLengthData(50, 1050))
336                             .build()
337                     )
338                 }
339                 getExerciseSessionRecord(
340                     exerciseSegments,
341                     exerciseLaps,
342                     lastWeek.plus(ofMinutes(timeOffSet)),
343                 )
344             }
345         val lastMonthRecords =
346             (1L..3).map { timeOffSet ->
347                 val exerciseSegments = ArrayList<ExerciseSegment>()
348                 repeat(5) { i ->
349                     exerciseSegments.add(
350                         ExerciseSegment.Builder(
351                                 lastMonth.plus(ofMinutes(timeOffSet + i)),
352                                 lastMonth.plus(ofMinutes(timeOffSet + i + 1)),
353                                 getValidSegmentType(),
354                             )
355                             .build()
356                     )
357                 }
358                 val exerciseLaps = ArrayList<ExerciseLap>()
359                 repeat(5) { i ->
360                     exerciseLaps.add(
361                         ExerciseLap.Builder(
362                                 lastMonth.plus(ofMinutes(timeOffSet + i)),
363                                 lastMonth.plus(ofMinutes(timeOffSet + i + 1)),
364                             )
365                             .setLength(getValidLengthData(50, 1050))
366                             .build()
367                     )
368                 }
369                 getExerciseSessionRecord(
370                     exerciseSegments,
371                     exerciseLaps,
372                     lastMonth.plus(ofMinutes(timeOffSet)),
373                 )
374             }
375 
376         insertRecords(records, manager)
377         insertRecords(yesterdayRecords, manager)
378         insertRecords(lastWeekRecords, manager)
379         insertRecords(lastMonthRecords, manager)
380     }
381 
382     private suspend fun seedPlannedExerciseSessionRecord() {
383         val tomorrow = start.plus(ofDays(1))
384         val records =
385             (1L..3).map { timeOffSet ->
386                 val plannedExerciseBlocks = ArrayList<PlannedExerciseBlock>()
387                 plannedExerciseBlocks.add(getValidPlannedExerciseBlockData())
388                 plannedExerciseBlocks.add(getCardioPlannedExerciseBlockData())
389                 getPlannedExerciseSessionRecord(
390                     plannedExerciseBlocks,
391                     start.plus(ofMinutes(timeOffSet)),
392                 )
393             }
394         val tomorrowRecords =
395             (1L..3).map { timeOffSet ->
396                 val plannedExerciseBlocks = ArrayList<PlannedExerciseBlock>()
397                 repeat(10) { plannedExerciseBlocks.add(getValidPlannedExerciseBlockData()) }
398                 getPlannedExerciseSessionRecord(
399                     plannedExerciseBlocks,
400                     tomorrow.plus(ofMinutes(timeOffSet)),
401                 )
402             }
403         val yesterdayRecords =
404             (1L..3).map { timeOffSet ->
405                 val plannedExerciseBlocks = ArrayList<PlannedExerciseBlock>()
406                 repeat(10) { plannedExerciseBlocks.add(getValidPlannedExerciseBlockData()) }
407                 getPlannedExerciseSessionRecord(
408                     plannedExerciseBlocks,
409                     yesterday.plus(ofMinutes(timeOffSet)),
410                 )
411             }
412         val lastWeekRecords =
413             (1L..3).map { timeOffSet ->
414                 val plannedExerciseBlocks = ArrayList<PlannedExerciseBlock>()
415                 repeat(10) { plannedExerciseBlocks.add(getValidPlannedExerciseBlockData()) }
416                 getPlannedExerciseSessionRecord(
417                     plannedExerciseBlocks,
418                     lastWeek.plus(ofMinutes(timeOffSet)),
419                 )
420             }
421         val lastMonthRecords =
422             (1L..3).map { timeOffSet ->
423                 val plannedExerciseBlocks = ArrayList<PlannedExerciseBlock>()
424                 repeat(10) { plannedExerciseBlocks.add(getValidPlannedExerciseBlockData()) }
425                 getPlannedExerciseSessionRecord(
426                     plannedExerciseBlocks,
427                     lastMonth.plus(ofMinutes(timeOffSet)),
428                 )
429             }
430 
431         insertRecords(records, manager)
432         insertRecords(tomorrowRecords, manager)
433         insertRecords(yesterdayRecords, manager)
434         insertRecords(lastWeekRecords, manager)
435         insertRecords(lastMonthRecords, manager)
436     }
437 
438     private suspend fun seedSpeedRecord() {
439         val records =
440             (1L..3).map { timeOffSet ->
441                 val speedRecordSample = ArrayList<SpeedRecordSample>()
442                 repeat(10) { i ->
443                     speedRecordSample.add(
444                         SpeedRecordSample(
445                             getValidSpeedData(),
446                             start.plus(ofMinutes(timeOffSet + i)),
447                         )
448                     )
449                 }
450                 getSpeedRecord(speedRecordSample, start.plus(ofMinutes(timeOffSet)))
451             }
452         val yesterdayRecords =
453             (1L..3).map { timeOffSet ->
454                 val speedRecordSample = ArrayList<SpeedRecordSample>()
455                 repeat(10) { i ->
456                     speedRecordSample.add(
457                         SpeedRecordSample(
458                             getValidSpeedData(),
459                             yesterday.plus(ofMinutes(timeOffSet + i)),
460                         )
461                     )
462                 }
463                 getSpeedRecord(speedRecordSample, yesterday.plus(ofMinutes(timeOffSet)))
464             }
465         val lastWeekRecords =
466             (1L..3).map { timeOffSet ->
467                 val speedRecordSample = ArrayList<SpeedRecordSample>()
468                 repeat(10) { i ->
469                     speedRecordSample.add(
470                         SpeedRecordSample(
471                             getValidSpeedData(),
472                             lastWeek.plus(ofMinutes(timeOffSet + i)),
473                         )
474                     )
475                 }
476                 getSpeedRecord(speedRecordSample, lastWeek.plus(ofMinutes(timeOffSet)))
477             }
478         val lastMonthRecords =
479             (1L..3).map { timeOffSet ->
480                 val speedRecordSample = ArrayList<SpeedRecordSample>()
481                 repeat(10) { i ->
482                     speedRecordSample.add(
483                         SpeedRecordSample(
484                             getValidSpeedData(),
485                             lastMonth.plus(ofMinutes(timeOffSet + i)),
486                         )
487                     )
488                 }
489                 getSpeedRecord(speedRecordSample, lastMonth.plus(ofMinutes(timeOffSet)))
490             }
491 
492         insertRecords(records, manager)
493         insertRecords(yesterdayRecords, manager)
494         insertRecords(lastWeekRecords, manager)
495         insertRecords(lastMonthRecords, manager)
496     }
497 
498     private suspend fun seedPowerRecord() {
499         val records =
500             (1L..3).map { timeOffSet ->
501                 val powerRecordSample = ArrayList<PowerRecordSample>()
502                 repeat(10) { i ->
503                     powerRecordSample.add(
504                         PowerRecordSample(
505                             getValidPowerData(),
506                             start.plus(ofMinutes(timeOffSet + i)),
507                         )
508                     )
509                 }
510 
511                 getPowerRecord(powerRecordSample, start.plus(ofMinutes(timeOffSet)))
512             }
513         val yesterdayRecords =
514             (1L..3).map { timeOffSet ->
515                 val powerRecordSample = ArrayList<PowerRecordSample>()
516                 repeat(10) { i ->
517                     powerRecordSample.add(
518                         PowerRecordSample(
519                             getValidPowerData(),
520                             yesterday.plus(ofMinutes(timeOffSet + i)),
521                         )
522                     )
523                 }
524 
525                 getPowerRecord(powerRecordSample, yesterday.plus(ofMinutes(timeOffSet)))
526             }
527         val lastWeekRecords =
528             (1L..3).map { timeOffSet ->
529                 val powerRecordSample = ArrayList<PowerRecordSample>()
530                 repeat(10) { i ->
531                     powerRecordSample.add(
532                         PowerRecordSample(
533                             getValidPowerData(),
534                             lastWeek.plus(ofMinutes(timeOffSet + i)),
535                         )
536                     )
537                 }
538 
539                 getPowerRecord(powerRecordSample, lastWeek.plus(ofMinutes(timeOffSet)))
540             }
541         val lastMonthRecords =
542             (1L..3).map { timeOffSet ->
543                 val powerRecordSample = ArrayList<PowerRecordSample>()
544                 repeat(10) { i ->
545                     powerRecordSample.add(
546                         PowerRecordSample(
547                             getValidPowerData(),
548                             lastMonth.plus(ofMinutes(timeOffSet + i)),
549                         )
550                     )
551                 }
552 
553                 getPowerRecord(powerRecordSample, lastMonth.plus(ofMinutes(timeOffSet)))
554             }
555 
556         insertRecords(records, manager)
557         insertRecords(yesterdayRecords, manager)
558         insertRecords(lastWeekRecords, manager)
559         insertRecords(lastMonthRecords, manager)
560     }
561 
562     private suspend fun seedCyclingPedalingCadenceRecord() {
563         val records =
564             (1L..3).map { timeOffSet ->
565                 val cyclingCadenceSample = ArrayList<CyclingPedalingCadenceRecordSample>()
566                 repeat(10) { i ->
567                     cyclingCadenceSample.add(
568                         CyclingPedalingCadenceRecordSample(
569                             getValidDoubleData(60, 100),
570                             start.plus(ofMinutes(timeOffSet + i)),
571                         )
572                     )
573                 }
574 
575                 getCyclingPedalingCadenceRecord(
576                     cyclingCadenceSample,
577                     start.plus(ofMinutes(timeOffSet)),
578                 )
579             }
580         val yesterdayRecords =
581             (1L..3).map { timeOffSet ->
582                 val cyclingCadenceSample = ArrayList<CyclingPedalingCadenceRecordSample>()
583                 repeat(10) { i ->
584                     cyclingCadenceSample.add(
585                         CyclingPedalingCadenceRecordSample(
586                             getValidDoubleData(60, 100),
587                             yesterday.plus(ofMinutes(timeOffSet + i)),
588                         )
589                     )
590                 }
591 
592                 getCyclingPedalingCadenceRecord(
593                     cyclingCadenceSample,
594                     yesterday.plus(ofMinutes(timeOffSet)),
595                 )
596             }
597         val lastWeekRecords =
598             (1L..3).map { timeOffSet ->
599                 val cyclingCadenceSample = ArrayList<CyclingPedalingCadenceRecordSample>()
600                 repeat(10) { i ->
601                     cyclingCadenceSample.add(
602                         CyclingPedalingCadenceRecordSample(
603                             getValidDoubleData(60, 100),
604                             lastWeek.plus(ofMinutes(timeOffSet + i)),
605                         )
606                     )
607                 }
608 
609                 getCyclingPedalingCadenceRecord(
610                     cyclingCadenceSample,
611                     lastWeek.plus(ofMinutes(timeOffSet)),
612                 )
613             }
614         val lastMonthRecords =
615             (1L..3).map { timeOffSet ->
616                 val cyclingCadenceSample = ArrayList<CyclingPedalingCadenceRecordSample>()
617                 repeat(10) { i ->
618                     cyclingCadenceSample.add(
619                         CyclingPedalingCadenceRecordSample(
620                             getValidDoubleData(60, 100),
621                             lastMonth.plus(ofMinutes(timeOffSet + i)),
622                         )
623                     )
624                 }
625 
626                 getCyclingPedalingCadenceRecord(
627                     cyclingCadenceSample,
628                     lastMonth.plus(ofMinutes(timeOffSet)),
629                 )
630             }
631 
632         insertRecords(records, manager)
633         insertRecords(yesterdayRecords, manager)
634         insertRecords(lastWeekRecords, manager)
635         insertRecords(lastMonthRecords, manager)
636     }
637 
638     private suspend fun seedFloorsClimbedRecord() {
639         val records =
640             (1L..3).map { timeOffSet ->
641                 getFloorsClimbedRecord(getValidDoubleData(1, 10), start.plus(ofMinutes(timeOffSet)))
642             }
643         val yesterdayRecords =
644             (1L..3).map { timeOffSet ->
645                 getFloorsClimbedRecord(
646                     getValidDoubleData(1, 10),
647                     yesterday.plus(ofMinutes(timeOffSet)),
648                 )
649             }
650         val lastWeekRecords =
651             (1L..3).map { timeOffSet ->
652                 getFloorsClimbedRecord(
653                     getValidDoubleData(1, 10),
654                     lastWeek.plus(ofMinutes(timeOffSet)),
655                 )
656             }
657         val lastMonthRecords =
658             (1L..3).map { timeOffSet ->
659                 getFloorsClimbedRecord(
660                     getValidDoubleData(1, 10),
661                     lastMonth.plus(ofMinutes(timeOffSet)),
662                 )
663             }
664 
665         insertRecords(records, manager)
666         insertRecords(yesterdayRecords, manager)
667         insertRecords(lastWeekRecords, manager)
668         insertRecords(lastMonthRecords, manager)
669     }
670 
671     private suspend fun seedTotalCaloriesBurnedRecord() {
672         val records =
673             (1L..3).map { timeOffSet ->
674                 getTotalCaloriesBurnedRecord(getValidEnergy(), start.plus(ofMinutes(timeOffSet)))
675             }
676         val yesterdayRecords =
677             (1L..3).map { timeOffSet ->
678                 getTotalCaloriesBurnedRecord(
679                     getValidEnergy(),
680                     yesterday.plus(ofMinutes(timeOffSet)),
681                 )
682             }
683         val lastWeekRecords =
684             (1L..3).map { timeOffSet ->
685                 getTotalCaloriesBurnedRecord(getValidEnergy(), lastWeek.plus(ofMinutes(timeOffSet)))
686             }
687         val lastMonthRecords =
688             (1L..3).map { timeOffSet ->
689                 getTotalCaloriesBurnedRecord(
690                     getValidEnergy(),
691                     lastMonth.plus(ofMinutes(timeOffSet)),
692                 )
693             }
694 
695         insertRecords(records, manager)
696         insertRecords(yesterdayRecords, manager)
697         insertRecords(lastWeekRecords, manager)
698         insertRecords(lastMonthRecords, manager)
699     }
700 
701     private suspend fun seedWheelchairPushesRecord() {
702         val records =
703             (1L..3).map { timeOffSet ->
704                 getWheelchairPushesRecord(timeOffSet, start.plus(ofMinutes(timeOffSet)))
705             }
706         val yesterdayRecords =
707             (1L..3).map { timeOffSet ->
708                 getWheelchairPushesRecord(timeOffSet, yesterday.plus(ofMinutes(timeOffSet)))
709             }
710         val lastWeekRecords =
711             (1L..3).map { timeOffSet ->
712                 getWheelchairPushesRecord(timeOffSet, lastWeek.plus(ofMinutes(timeOffSet)))
713             }
714         val lastMonthRecords =
715             (1L..3).map { timeOffSet ->
716                 getWheelchairPushesRecord(timeOffSet, lastMonth.plus(ofMinutes(timeOffSet)))
717             }
718 
719         insertRecords(records, manager)
720         insertRecords(yesterdayRecords, manager)
721         insertRecords(lastWeekRecords, manager)
722         insertRecords(lastMonthRecords, manager)
723     }
724 
725     private suspend fun seedVo2MaxRecord() {
726         val records =
727             (1L..3).map { timeOffSet ->
728                 getVo2MaxRecord(
729                     getValidVo2MeasurementMethod(),
730                     getValidDoubleData(25, 40),
731                     start.plus(ofMinutes(timeOffSet)),
732                 )
733             }
734         val yesterdayRecords =
735             (1L..3).map { timeOffSet ->
736                 getVo2MaxRecord(
737                     getValidVo2MeasurementMethod(),
738                     getValidDoubleData(25, 40),
739                     yesterday.plus(ofMinutes(timeOffSet)),
740                 )
741             }
742         val lastWeekRecords =
743             (1L..3).map { timeOffSet ->
744                 getVo2MaxRecord(
745                     getValidVo2MeasurementMethod(),
746                     getValidDoubleData(25, 40),
747                     lastWeek.plus(ofMinutes(timeOffSet)),
748                 )
749             }
750         val lastMonthRecords =
751             (1L..3).map { timeOffSet ->
752                 getVo2MaxRecord(
753                     getValidVo2MeasurementMethod(),
754                     getValidDoubleData(25, 40),
755                     lastMonth.plus(ofMinutes(timeOffSet)),
756                 )
757             }
758 
759         insertRecords(records, manager)
760         insertRecords(yesterdayRecords, manager)
761         insertRecords(lastWeekRecords, manager)
762         insertRecords(lastMonthRecords, manager)
763     }
764 
765     private suspend fun seedStepsCadenceRecord() {
766         val records =
767             (1L..3).map { timeOffSet ->
768                 val stepsCadenceRecordSample = ArrayList<StepsCadenceRecordSample>()
769                 repeat(10) { i ->
770                     stepsCadenceRecordSample.add(
771                         StepsCadenceRecordSample(
772                             getValidDoubleData(160, 180),
773                             start.plus(ofMinutes(timeOffSet + i)),
774                         )
775                     )
776                 }
777                 getStepsCadenceRecord(stepsCadenceRecordSample, start.plus(ofMinutes(timeOffSet)))
778             }
779         val yesterdayRecords =
780             (1L..3).map { timeOffSet ->
781                 val stepsCadenceRecordSample = ArrayList<StepsCadenceRecordSample>()
782                 repeat(10) { i ->
783                     stepsCadenceRecordSample.add(
784                         StepsCadenceRecordSample(
785                             getValidDoubleData(160, 180),
786                             yesterday.plus(ofMinutes(timeOffSet + i)),
787                         )
788                     )
789                 }
790                 getStepsCadenceRecord(
791                     stepsCadenceRecordSample,
792                     yesterday.plus(ofMinutes(timeOffSet)),
793                 )
794             }
795         val lastWeekRecords =
796             (1L..3).map { timeOffSet ->
797                 val stepsCadenceRecordSample = ArrayList<StepsCadenceRecordSample>()
798                 repeat(10) { i ->
799                     stepsCadenceRecordSample.add(
800                         StepsCadenceRecordSample(
801                             getValidDoubleData(160, 180),
802                             lastWeek.plus(ofMinutes(timeOffSet + i)),
803                         )
804                     )
805                 }
806                 getStepsCadenceRecord(
807                     stepsCadenceRecordSample,
808                     lastWeek.plus(ofMinutes(timeOffSet)),
809                 )
810             }
811         val lastMonthRecords =
812             (1L..3).map { timeOffSet ->
813                 val stepsCadenceRecordSample = ArrayList<StepsCadenceRecordSample>()
814                 repeat(10) { i ->
815                     stepsCadenceRecordSample.add(
816                         StepsCadenceRecordSample(
817                             getValidDoubleData(160, 180),
818                             lastMonth.plus(ofMinutes(timeOffSet + i)),
819                         )
820                     )
821                 }
822                 getStepsCadenceRecord(
823                     stepsCadenceRecordSample,
824                     lastMonth.plus(ofMinutes(timeOffSet)),
825                 )
826             }
827 
828         insertRecords(records, manager)
829         insertRecords(yesterdayRecords, manager)
830         insertRecords(lastWeekRecords, manager)
831         insertRecords(lastMonthRecords, manager)
832     }
833 
834     private fun getStepsRecord(count: Long, time: Instant): StepsRecord {
835         return StepsRecord.Builder(getMetaData(context), time, time.plusSeconds(30), count).build()
836     }
837 
838     private fun getDistanceData(length: Length, time: Instant): DistanceRecord {
839         return DistanceRecord.Builder(getMetaData(context), time, time.plusSeconds(30), length)
840             .build()
841     }
842 
843     private fun getValidLengthData(min: Int, max: Int): Length {
844         return Length.fromMeters((Random.nextInt(min, max)).toDouble())
845     }
846 
847     private fun getElevationGainedRecord(distance: Length, time: Instant): ElevationGainedRecord {
848         return ElevationGainedRecord.Builder(
849                 getMetaData(context),
850                 time,
851                 time.plusSeconds(30),
852                 distance,
853             )
854             .build()
855     }
856 
857     private fun getActiveCaloriesBurnedRecord(
858         energy: Energy,
859         time: Instant,
860     ): ActiveCaloriesBurnedRecord {
861         return ActiveCaloriesBurnedRecord.Builder(
862                 getMetaData(context),
863                 time,
864                 time.plusSeconds(30),
865                 energy,
866             )
867             .build()
868     }
869 
870     private fun getValidEnergy(): Energy {
871         return Energy.fromCalories((Random.nextInt(500, 5000)).toDouble())
872     }
873 
874     private fun getExerciseSessionRecord(
875         exerciseSegments: List<ExerciseSegment>,
876         laps: List<ExerciseLap>,
877         time: Instant,
878     ): ExerciseSessionRecord {
879         return ExerciseSessionRecord.Builder(
880                 getMetaData(context),
881                 time,
882                 time.plusSeconds(1000),
883                 ExerciseSessionType.EXERCISE_SESSION_TYPE_EXERCISE_CLASS,
884             )
885             .setSegments(exerciseSegments)
886             .setLaps(laps)
887             .setRoute(
888                 generateExerciseRouteFromLocations(
889                     getValidExerciseRouteLocation(),
890                     time.toEpochMilli(),
891                 )
892             )
893             .build()
894     }
895 
896     private fun getValidExerciseRouteLocation():
897         List<ExerciseRoutesTestData.ExerciseRouteLocationData> {
898         return routeDataMap.values.random()
899     }
900 
901     private fun getValidSegmentType(): Int {
902         return ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_STRETCHING
903     }
904 
905     private fun getPlannedExerciseSessionRecord(
906         plannedExerciseBlocks: List<PlannedExerciseBlock>,
907         time: Instant,
908     ): PlannedExerciseSessionRecord {
909         return PlannedExerciseSessionRecord.Builder(
910                 getMetaData(context),
911                 ExerciseSessionType.EXERCISE_SESSION_TYPE_EXERCISE_CLASS,
912                 time,
913                 time.plusSeconds(30),
914             )
915             .setBlocks(plannedExerciseBlocks)
916             .setExerciseType(ExerciseSessionType.EXERCISE_SESSION_TYPE_WEIGHTLIFTING)
917             .setNotes("Gym training notes")
918             .build()
919     }
920 
921     private fun getValidPlannedExerciseBlockData(): PlannedExerciseBlock {
922         val warmupSet =
923             PlannedExerciseStep.Builder(
924                     ExerciseSessionType.EXERCISE_SESSION_TYPE_WEIGHTLIFTING,
925                     EXERCISE_CATEGORY_WARMUP,
926                     ExerciseCompletionGoal.RepetitionsGoal(Random.nextInt(10, 20)),
927                 )
928                 .build()
929         val activeSet =
930             PlannedExerciseStep.Builder(
931                     ExerciseSessionType.EXERCISE_SESSION_TYPE_WEIGHTLIFTING,
932                     EXERCISE_CATEGORY_ACTIVE,
933                     ExerciseCompletionGoal.RepetitionsGoal(Random.nextInt(20, 30)),
934                 )
935                 .build()
936         val cooldownSet =
937             PlannedExerciseStep.Builder(
938                     ExerciseSessionType.EXERCISE_SESSION_TYPE_WEIGHTLIFTING,
939                     EXERCISE_CATEGORY_COOLDOWN,
940                     ExerciseCompletionGoal.RepetitionsGoal(Random.nextInt(20, 30)),
941                 )
942                 .build()
943         val rest =
944             PlannedExerciseStep.Builder(
945                     ExerciseSessionType.EXERCISE_SESSION_TYPE_STRETCHING,
946                     EXERCISE_CATEGORY_REST,
947                     ExerciseCompletionGoal.DurationGoal(ofSeconds(30)),
948                 )
949                 .build()
950         return PlannedExerciseBlock.Builder(Random.nextInt(1, 5))
951             .addStep(warmupSet)
952             .addStep(activeSet)
953             .addStep(cooldownSet)
954             .addStep(rest)
955             .build()
956     }
957 
958     private fun getCardioPlannedExerciseBlockData(): PlannedExerciseBlock {
959         val warmupSet =
960             PlannedExerciseStep.Builder(
961                     ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING_TREADMILL,
962                     EXERCISE_CATEGORY_WARMUP,
963                     ExerciseCompletionGoal.DurationGoal(ofMinutes(5)),
964                 )
965                 .addPerformanceGoal(
966                     ExercisePerformanceGoal.SpeedGoal(
967                         Velocity.fromMetersPerSecond(100.0),
968                         Velocity.fromMetersPerSecond(200.0),
969                     )
970                 )
971                 .build()
972         val activeSet =
973             PlannedExerciseStep.Builder(
974                     ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING_TREADMILL,
975                     EXERCISE_CATEGORY_WARMUP,
976                     ExerciseCompletionGoal.DurationGoal(ofMinutes(45)),
977                 )
978                 .addPerformanceGoal(ExercisePerformanceGoal.HeartRateGoal(90, 110))
979                 .build()
980         val cooldownSet =
981             PlannedExerciseStep.Builder(
982                     ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING_TREADMILL,
983                     EXERCISE_CATEGORY_WARMUP,
984                     ExerciseCompletionGoal.DurationGoal(ofMinutes(10)),
985                 )
986                 .build()
987         val rest =
988             PlannedExerciseStep.Builder(
989                     ExerciseSessionType.EXERCISE_SESSION_TYPE_STRETCHING,
990                     EXERCISE_CATEGORY_REST,
991                     ExerciseCompletionGoal.DurationGoal(ofSeconds(180)),
992                 )
993                 .build()
994         return PlannedExerciseBlock.Builder(Random.nextInt(1, 5))
995             .addStep(warmupSet)
996             .addStep(activeSet)
997             .addStep(cooldownSet)
998             .addStep(rest)
999             .build()
1000     }
1001 
1002     private fun getValidPlannedExerciseStepData(): PlannedExerciseStep {
1003         return PlannedExerciseStep.Builder(
1004                 ExerciseSessionType.EXERCISE_SESSION_TYPE_EXERCISE_CLASS,
1005                 EXERCISE_CATEGORY_ACTIVE,
1006                 getValidCompletionGoal(),
1007             )
1008             .build()
1009     }
1010 
1011     private fun getValidCompletionGoal(): ExerciseCompletionGoal {
1012         return ExerciseCompletionGoal.StepsGoal(Random.nextInt(100, 500))
1013     }
1014 
1015     private fun getSpeedRecord(speed: List<SpeedRecordSample>, time: Instant): SpeedRecord {
1016         return SpeedRecord.Builder(getMetaData(context), time, time.plusSeconds(1000), speed)
1017             .build()
1018     }
1019 
1020     private fun getValidSpeedData(): Velocity {
1021         return Velocity.fromMetersPerSecond(Random.nextInt(1, 10).toDouble())
1022     }
1023 
1024     private fun getPowerRecord(power: List<PowerRecordSample>, time: Instant): PowerRecord {
1025         return PowerRecord.Builder(getMetaData(context), time, time.plusSeconds(1000), power)
1026             .build()
1027     }
1028 
1029     private fun getValidPowerData(): Power {
1030         return Power.fromWatts(Random.nextInt(150, 400).toDouble())
1031     }
1032 
1033     private fun getCyclingPedalingCadenceRecord(
1034         cyclingCadenceSample: List<CyclingPedalingCadenceRecordSample>,
1035         time: Instant,
1036     ): CyclingPedalingCadenceRecord {
1037         return CyclingPedalingCadenceRecord.Builder(
1038                 getMetaData(context),
1039                 time,
1040                 time.plusSeconds(1000),
1041                 cyclingCadenceSample,
1042             )
1043             .build()
1044     }
1045 
1046     private fun getFloorsClimbedRecord(floors: Double, time: Instant): FloorsClimbedRecord {
1047         return FloorsClimbedRecord.Builder(getMetaData(context), time, time.plusSeconds(30), floors)
1048             .build()
1049     }
1050 
1051     private fun getTotalCaloriesBurnedRecord(
1052         energy: Energy,
1053         time: Instant,
1054     ): TotalCaloriesBurnedRecord {
1055         return TotalCaloriesBurnedRecord.Builder(
1056                 getMetaData(context),
1057                 time,
1058                 time.plusSeconds(30),
1059                 energy,
1060             )
1061             .build()
1062     }
1063 
1064     private fun getWheelchairPushesRecord(count: Long, time: Instant): WheelchairPushesRecord {
1065         return WheelchairPushesRecord.Builder(
1066                 getMetaData(context),
1067                 time,
1068                 time.plusSeconds(30),
1069                 count,
1070             )
1071             .build()
1072     }
1073 
1074     private fun getVo2MaxRecord(
1075         measurementMethod: Int,
1076         vo2Max: Double,
1077         time: Instant,
1078     ): Vo2MaxRecord {
1079         return Vo2MaxRecord.Builder(getMetaData(context), time, measurementMethod, vo2Max).build()
1080     }
1081 
1082     private fun getValidVo2MeasurementMethod(): Int {
1083         return VALID_VO2_MEASUREMENT_METHOD.random()
1084     }
1085 
1086     private fun getStepsCadenceRecord(
1087         stepsCadenceRecordSample: List<StepsCadenceRecordSample>,
1088         time: Instant,
1089     ): StepsCadenceRecord {
1090         return StepsCadenceRecord.Builder(
1091                 getMetaData(context),
1092                 time,
1093                 time.plusSeconds(1000),
1094                 stepsCadenceRecordSample,
1095             )
1096             .build()
1097     }
1098 
1099     private fun getValidDoubleData(min: Int, max: Int): Double {
1100         return Random.nextInt(min, max).toDouble()
1101     }
1102 }
1103