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.BasalMetabolicRateRecord 21 import android.health.connect.datatypes.BodyFatRecord 22 import android.health.connect.datatypes.BodyWaterMassRecord 23 import android.health.connect.datatypes.BoneMassRecord 24 import android.health.connect.datatypes.DataOrigin 25 import android.health.connect.datatypes.Device 26 import android.health.connect.datatypes.HeightRecord 27 import android.health.connect.datatypes.LeanBodyMassRecord 28 import android.health.connect.datatypes.Metadata 29 import android.health.connect.datatypes.WeightRecord 30 import android.health.connect.datatypes.units.Length 31 import android.health.connect.datatypes.units.Mass 32 import android.health.connect.datatypes.units.Percentage 33 import android.health.connect.datatypes.units.Power 34 import android.os.Build.MANUFACTURER 35 import android.os.Build.MODEL 36 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.getMetaData 37 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.insertRecords 38 import kotlinx.coroutines.runBlocking 39 import java.time.Duration.ofDays 40 import java.time.Duration.ofMinutes 41 import java.time.Instant 42 import java.time.temporal.ChronoUnit 43 import kotlin.random.Random 44 45 class SeedBodyMeasurementsData(private val context: Context, private val manager: HealthConnectManager) { 46 47 private val start = Instant.now().truncatedTo(ChronoUnit.DAYS) 48 private val yesterday = start.minus(ofDays(1)) 49 private val lastWeek = start.minus(ofDays(7)) 50 private val lastMonth = start.minus(ofDays(31)) 51 52 fun seedBodyMeasurementsData(){ 53 runBlocking { 54 try { 55 seedBodyFatRecord() 56 seedBodyWaterMassRecord() 57 seedHeightRecord() 58 seedBoneMassRecord() 59 seedLeanBodyMassRecord() 60 seedBasalMetabolicRate() 61 seedWeightRecord() 62 63 } catch (ex: Exception) { 64 throw ex 65 } 66 } 67 } 68 69 private suspend fun seedBodyFatRecord(){ 70 val records = (1L..3).map { timeOffSet -> 71 getBodyFatRecord(getValidBodyFatPercentage(), start.plus(ofMinutes(timeOffSet))) 72 } 73 val yesterdayRecords = (1L..3).map { timeOffSet -> 74 getBodyFatRecord(getValidBodyFatPercentage(), yesterday.plus(ofMinutes(timeOffSet))) 75 } 76 val lastWeekRecords = (1L..3).map { timeOffSet -> 77 getBodyFatRecord(getValidBodyFatPercentage(), lastWeek.plus(ofMinutes(timeOffSet))) 78 } 79 val lastMonthRecords = (1L..3).map { timeOffSet -> 80 getBodyFatRecord(getValidBodyFatPercentage(), lastMonth.plus(ofMinutes(timeOffSet))) 81 } 82 83 insertRecords(records, manager) 84 insertRecords(yesterdayRecords, manager) 85 insertRecords(lastWeekRecords, manager) 86 insertRecords(lastMonthRecords, manager) 87 } 88 89 private suspend fun seedBodyWaterMassRecord(){ 90 val records = (1L..3).map { timeOffSet -> 91 getBodyWaterMassRecord(getValidMassData(20000, 45000), start.plus(ofMinutes(timeOffSet))) 92 } 93 val yesterdayRecords = (1L..3).map { timeOffSet -> 94 getBodyWaterMassRecord(getValidMassData(20000, 45000), yesterday.plus(ofMinutes(timeOffSet))) 95 } 96 val lastWeekRecords = (1L..3).map { timeOffSet -> 97 getBodyWaterMassRecord(getValidMassData(20000, 45000), lastWeek.plus(ofMinutes(timeOffSet))) 98 } 99 val lastMonthRecords = (1L..3).map { timeOffSet -> 100 getBodyWaterMassRecord(getValidMassData(20000, 45000), lastMonth.plus(ofMinutes(timeOffSet))) 101 } 102 103 insertRecords(records, manager) 104 insertRecords(yesterdayRecords, manager) 105 insertRecords(lastWeekRecords, manager) 106 insertRecords(lastMonthRecords, manager) 107 } 108 109 private suspend fun seedBoneMassRecord(){ 110 val records = (1L..3).map { timeOffSet -> 111 getBoneMassRecord(getValidMassData(5000, 11000), start.plus(ofMinutes(timeOffSet))) 112 } 113 val yesterdayRecords = (1L..3).map { timeOffSet -> 114 getBoneMassRecord(getValidMassData(5000, 11000), yesterday.plus(ofMinutes(timeOffSet))) 115 } 116 val lastWeekRecords = (1L..3).map { timeOffSet -> 117 getBoneMassRecord(getValidMassData(5000, 11000), lastWeek.plus(ofMinutes(timeOffSet))) 118 } 119 val lastMonthRecords = (1L..3).map { timeOffSet -> 120 getBoneMassRecord(getValidMassData(5000, 11000), lastMonth.plus(ofMinutes(timeOffSet))) 121 } 122 123 insertRecords(records, manager) 124 insertRecords(yesterdayRecords, manager) 125 insertRecords(lastWeekRecords, manager) 126 insertRecords(lastMonthRecords, manager) 127 } 128 129 private suspend fun seedHeightRecord(){ 130 val records = (1L..3).map { timeOffSet -> 131 getHeightRecord(getValidHeightData(), start.plus(ofMinutes(timeOffSet))) 132 } 133 val yesterdayRecords = (1L..3).map { timeOffSet -> 134 getHeightRecord(getValidHeightData(), yesterday.plus(ofMinutes(timeOffSet))) 135 } 136 val lastWeekRecords = (1L..3).map { timeOffSet -> 137 getHeightRecord(getValidHeightData(), lastWeek.plus(ofMinutes(timeOffSet))) 138 } 139 val lastMonthRecords = (1L..3).map { timeOffSet -> 140 getHeightRecord(getValidHeightData(), lastMonth.plus(ofMinutes(timeOffSet))) 141 } 142 143 insertRecords(records, manager) 144 insertRecords(yesterdayRecords, manager) 145 insertRecords(lastWeekRecords, manager) 146 insertRecords(lastMonthRecords, manager) 147 } 148 149 private suspend fun seedBasalMetabolicRate(){ 150 val records = (1L..3).map { timeOffSet -> 151 getBasalMetabolicRateRecord(getValidBasalMetabolicRateData(), start.plus(ofMinutes(timeOffSet))) 152 } 153 val yesterdayRecords = (1L..3).map { timeOffSet -> 154 getBasalMetabolicRateRecord(getValidBasalMetabolicRateData(), yesterday.plus(ofMinutes(timeOffSet))) 155 } 156 val lastWeekRecords = (1L..3).map { timeOffSet -> 157 getBasalMetabolicRateRecord(getValidBasalMetabolicRateData(), lastWeek.plus(ofMinutes(timeOffSet))) 158 } 159 val lastMonthRecords = (1L..3).map { timeOffSet -> 160 getBasalMetabolicRateRecord(getValidBasalMetabolicRateData(), lastMonth.plus(ofMinutes(timeOffSet))) 161 } 162 163 insertRecords(records, manager) 164 insertRecords(yesterdayRecords, manager) 165 insertRecords(lastWeekRecords, manager) 166 insertRecords(lastMonthRecords, manager) 167 } 168 169 private suspend fun seedLeanBodyMassRecord(){ 170 val records = (1L..3).map { timeOffSet -> 171 getLeanBodyMassRecord(getValidMassData(45000, 90000), start.plus(ofMinutes(timeOffSet))) 172 } 173 val yesterdayRecords = (1L..3).map { timeOffSet -> 174 getLeanBodyMassRecord(getValidMassData(45000, 90000), yesterday.plus(ofMinutes(timeOffSet))) 175 } 176 val lastWeekRecords = (1L..3).map { timeOffSet -> 177 getLeanBodyMassRecord(getValidMassData(45000, 90000), lastWeek.plus(ofMinutes(timeOffSet))) 178 } 179 val lastMonthRecords = (1L..3).map { timeOffSet -> 180 getLeanBodyMassRecord(getValidMassData(45000, 90000), lastMonth.plus(ofMinutes(timeOffSet))) 181 } 182 183 insertRecords(records, manager) 184 insertRecords(yesterdayRecords, manager) 185 insertRecords(lastWeekRecords, manager) 186 insertRecords(lastMonthRecords, manager) 187 } 188 189 private suspend fun seedWeightRecord(){ 190 val records = (1L..3).map { timeOffSet -> 191 getWeightRecord(getValidMassData(45000, 90000), start.plus(ofMinutes(timeOffSet))) 192 } 193 val yesterdayRecords = (1L..3).map { timeOffSet -> 194 getWeightRecord(getValidMassData(45000, 90000), yesterday.plus(ofMinutes(timeOffSet))) 195 } 196 val lastWeekRecords = (1L..3).map { timeOffSet -> 197 getWeightRecord(getValidMassData(45000, 90000), lastWeek.plus(ofMinutes(timeOffSet))) 198 } 199 val lastMonthRecords = (1L..3).map { timeOffSet -> 200 getWeightRecord(getValidMassData(45000, 90000), lastMonth.plus(ofMinutes(timeOffSet))) 201 } 202 203 insertRecords(records, manager) 204 insertRecords(yesterdayRecords, manager) 205 insertRecords(lastWeekRecords, manager) 206 insertRecords(lastMonthRecords, manager) 207 } 208 209 private fun getBodyFatRecord(percentage: Percentage, time: Instant): BodyFatRecord { 210 return BodyFatRecord.Builder(getMetaData(context), time, percentage).build() 211 } 212 213 private fun getValidBodyFatPercentage(): Percentage { 214 return Percentage.fromValue(Random.nextInt(10, 25).toDouble()) 215 } 216 217 private fun getBodyWaterMassRecord(bodyWaterMass: Mass, time: Instant): BodyWaterMassRecord { 218 return BodyWaterMassRecord.Builder(getMetaData(context), time, bodyWaterMass).build() 219 } 220 221 private fun getValidMassData(min: Int, max: Int): Mass { 222 return Mass.fromGrams(Random.nextInt(min, max).toDouble()) 223 } 224 225 private fun getBoneMassRecord(mass: Mass, time: Instant): BoneMassRecord { 226 return BoneMassRecord.Builder(getMetaData(context), time, mass).build() 227 } 228 229 private fun getHeightRecord(height: Length, time: Instant): HeightRecord { 230 return HeightRecord.Builder(getMetaData(context), time, height).build() 231 } 232 233 private fun getValidHeightData(): Length { 234 return Length.fromMeters(Random.nextDouble(1.6, 1.8)) 235 } 236 237 private fun getLeanBodyMassRecord(mass: Mass, time: Instant): LeanBodyMassRecord { 238 return LeanBodyMassRecord.Builder(getMetaData(context), time, mass).build() 239 } 240 241 private fun getWeightRecord(weight: Mass, time: Instant): WeightRecord { 242 return WeightRecord.Builder(getMetaData(context), time, weight).build() 243 } 244 245 private fun getBasalMetabolicRateRecord(basalMetabolicRate: Power, time: Instant): BasalMetabolicRateRecord { 246 return BasalMetabolicRateRecord.Builder(getMetaData(context), time, basalMetabolicRate).build() 247 } 248 249 private fun getValidBasalMetabolicRateData() : Power { 250 return Power.fromWatts(Random.nextInt(65, 80).toDouble()) 251 } 252 }