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