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