1 /** <lambda>null2 * Copyright (C) 2022 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.DataOrigin 21 import android.health.connect.datatypes.Device 22 import android.health.connect.datatypes.HeartRateRecord 23 import android.health.connect.datatypes.HeightRecord 24 import android.health.connect.datatypes.MenstruationFlowRecord 25 import android.health.connect.datatypes.MenstruationFlowRecord.MenstruationFlowType 26 import android.health.connect.datatypes.MenstruationPeriodRecord 27 import android.health.connect.datatypes.Metadata 28 import android.health.connect.datatypes.Record 29 import android.health.connect.datatypes.StepsRecord 30 import android.health.connect.datatypes.WeightRecord 31 import android.health.connect.datatypes.units.Length 32 import android.health.connect.datatypes.units.Mass 33 import android.os.Build.MANUFACTURER 34 import android.os.Build.MODEL 35 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.insertRecords 36 import java.time.Duration.ofDays 37 import java.time.Duration.ofMinutes 38 import java.time.Instant 39 import java.time.temporal.ChronoUnit 40 import java.util.Random 41 import kotlinx.coroutines.runBlocking 42 43 class SeedData(private val context: Context, private val manager: HealthConnectManager) { 44 45 companion object { 46 const val NUMBER_OF_SERIES_RECORDS_TO_INSERT = 200L 47 } 48 49 fun seedData() { 50 runBlocking { 51 try { 52 seedMenstruationData() 53 seedStepsData() 54 seedHeartRateData(10) 55 } catch (ex: Exception) { 56 throw ex 57 } 58 } 59 } 60 61 private suspend fun seedStepsData() { 62 val start = Instant.now().truncatedTo(ChronoUnit.DAYS) 63 val records = 64 (1L..50).map { count -> 65 getStepsRecord(count, start.plus(ofMinutes(count))) 66 } 67 68 insertRecords(records, manager) 69 } 70 71 private suspend fun seedMenstruationData() { 72 val today = Instant.now() 73 val periodRecord = 74 MenstruationPeriodRecord.Builder(getMetaData(), today.minus(ofDays(5L)), today).build() 75 val flowRecords = 76 (-5..0).map { days -> 77 MenstruationFlowRecord.Builder( 78 getMetaData(), 79 today.plus(ofDays(days.toLong())), 80 MenstruationFlowType.FLOW_MEDIUM) 81 .build() 82 } 83 insertRecords( 84 buildList { 85 add(periodRecord) 86 addAll(flowRecords) 87 }, 88 manager) 89 } 90 91 suspend fun seedHeartRateData(numberOfRecordsPerBatch: Long) { 92 val start = Instant.now().truncatedTo(ChronoUnit.DAYS) 93 val random = Random() 94 val records = 95 (1L..numberOfRecordsPerBatch).map { timeOffset -> 96 val hrSamples = ArrayList<Pair<Long, Instant>>() 97 repeat(10) { i -> 98 hrSamples.add( 99 Pair(getValidHeartRate(random), start.plus(ofMinutes(timeOffset + i)))) 100 } 101 getHeartRateRecord( 102 hrSamples, 103 start.plus(ofMinutes(timeOffset)), 104 start.plus(ofMinutes(timeOffset + 100))) 105 } 106 insertRecords(records, manager) 107 } 108 109 private fun getHeartRateRecord( 110 heartRateValues: List<Pair<Long, Instant>>, 111 start: Instant, 112 end: Instant, 113 ): HeartRateRecord { 114 return HeartRateRecord.Builder( 115 getMetaData(), 116 start, 117 end, 118 heartRateValues.map { HeartRateRecord.HeartRateSample(it.first, it.second) }) 119 .build() 120 } 121 122 private fun getValidHeartRate(random: Random): Long { 123 return (random.nextInt(20) + 80).toLong() 124 } 125 126 private fun getStepsRecord(count: Long, time: Instant): StepsRecord { 127 return StepsRecord.Builder(getMetaData(), time, time.plusSeconds(30), count).build() 128 } 129 130 private fun getMetaData(): Metadata { 131 val device: Device = 132 Device.Builder().setManufacturer(MANUFACTURER).setModel(MODEL).setType(1).build() 133 val dataOrigin = DataOrigin.Builder().setPackageName(context.packageName).build() 134 return Metadata.Builder().setDevice(device).setDataOrigin(dataOrigin).build() 135 } 136 } 137