1 /* 2 * Copyright (C) 2024 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 17 package com.android.server.healthconnect.backuprestore; 18 19 import static android.health.connect.datatypes.units.Temperature.fromCelsius; 20 21 import static java.util.stream.Collectors.toSet; 22 23 import android.annotation.SuppressLint; 24 import android.health.connect.datatypes.RecordTypeIdentifier; 25 import android.health.connect.datatypes.units.Energy; 26 import android.health.connect.datatypes.units.Length; 27 import android.health.connect.datatypes.units.Mass; 28 import android.health.connect.datatypes.units.Power; 29 import android.health.connect.datatypes.units.Velocity; 30 import android.health.connect.internal.datatypes.ActiveCaloriesBurnedRecordInternal; 31 import android.health.connect.internal.datatypes.ActivityIntensityRecordInternal; 32 import android.health.connect.internal.datatypes.BasalBodyTemperatureRecordInternal; 33 import android.health.connect.internal.datatypes.BasalMetabolicRateRecordInternal; 34 import android.health.connect.internal.datatypes.BloodGlucoseRecordInternal; 35 import android.health.connect.internal.datatypes.BloodPressureRecordInternal; 36 import android.health.connect.internal.datatypes.BodyFatRecordInternal; 37 import android.health.connect.internal.datatypes.BodyTemperatureRecordInternal; 38 import android.health.connect.internal.datatypes.BodyWaterMassRecordInternal; 39 import android.health.connect.internal.datatypes.BoneMassRecordInternal; 40 import android.health.connect.internal.datatypes.CervicalMucusRecordInternal; 41 import android.health.connect.internal.datatypes.CyclingPedalingCadenceRecordInternal; 42 import android.health.connect.internal.datatypes.DistanceRecordInternal; 43 import android.health.connect.internal.datatypes.ElevationGainedRecordInternal; 44 import android.health.connect.internal.datatypes.ExerciseCompletionGoalInternal; 45 import android.health.connect.internal.datatypes.ExerciseLapInternal; 46 import android.health.connect.internal.datatypes.ExercisePerformanceGoalInternal; 47 import android.health.connect.internal.datatypes.ExerciseRouteInternal; 48 import android.health.connect.internal.datatypes.ExerciseRouteInternal.LocationInternal; 49 import android.health.connect.internal.datatypes.ExerciseSegmentInternal; 50 import android.health.connect.internal.datatypes.ExerciseSessionRecordInternal; 51 import android.health.connect.internal.datatypes.FloorsClimbedRecordInternal; 52 import android.health.connect.internal.datatypes.HeartRateRecordInternal; 53 import android.health.connect.internal.datatypes.HeartRateVariabilityRmssdRecordInternal; 54 import android.health.connect.internal.datatypes.HeightRecordInternal; 55 import android.health.connect.internal.datatypes.HydrationRecordInternal; 56 import android.health.connect.internal.datatypes.InstantRecordInternal; 57 import android.health.connect.internal.datatypes.IntermenstrualBleedingRecordInternal; 58 import android.health.connect.internal.datatypes.IntervalRecordInternal; 59 import android.health.connect.internal.datatypes.LeanBodyMassRecordInternal; 60 import android.health.connect.internal.datatypes.MenstruationFlowRecordInternal; 61 import android.health.connect.internal.datatypes.MenstruationPeriodRecordInternal; 62 import android.health.connect.internal.datatypes.MindfulnessSessionRecordInternal; 63 import android.health.connect.internal.datatypes.NutritionRecordInternal; 64 import android.health.connect.internal.datatypes.OvulationTestRecordInternal; 65 import android.health.connect.internal.datatypes.OxygenSaturationRecordInternal; 66 import android.health.connect.internal.datatypes.PlannedExerciseBlockInternal; 67 import android.health.connect.internal.datatypes.PlannedExerciseSessionRecordInternal; 68 import android.health.connect.internal.datatypes.PlannedExerciseStepInternal; 69 import android.health.connect.internal.datatypes.PowerRecordInternal; 70 import android.health.connect.internal.datatypes.RecordInternal; 71 import android.health.connect.internal.datatypes.RespiratoryRateRecordInternal; 72 import android.health.connect.internal.datatypes.RestingHeartRateRecordInternal; 73 import android.health.connect.internal.datatypes.SexualActivityRecordInternal; 74 import android.health.connect.internal.datatypes.SkinTemperatureRecordInternal; 75 import android.health.connect.internal.datatypes.SleepSessionRecordInternal; 76 import android.health.connect.internal.datatypes.SleepStageInternal; 77 import android.health.connect.internal.datatypes.SpeedRecordInternal; 78 import android.health.connect.internal.datatypes.StepsCadenceRecordInternal; 79 import android.health.connect.internal.datatypes.StepsRecordInternal; 80 import android.health.connect.internal.datatypes.TotalCaloriesBurnedRecordInternal; 81 import android.health.connect.internal.datatypes.Vo2MaxRecordInternal; 82 import android.health.connect.internal.datatypes.WeightRecordInternal; 83 import android.health.connect.internal.datatypes.WheelchairPushesRecordInternal; 84 import android.health.connect.internal.datatypes.utils.HealthConnectMappings; 85 86 import com.android.server.healthconnect.proto.backuprestore.ActiveCaloriesBurned; 87 import com.android.server.healthconnect.proto.backuprestore.ActivityIntensity; 88 import com.android.server.healthconnect.proto.backuprestore.BasalBodyTemperature; 89 import com.android.server.healthconnect.proto.backuprestore.BasalMetabolicRate; 90 import com.android.server.healthconnect.proto.backuprestore.BloodGlucose; 91 import com.android.server.healthconnect.proto.backuprestore.BloodPressure; 92 import com.android.server.healthconnect.proto.backuprestore.BodyFat; 93 import com.android.server.healthconnect.proto.backuprestore.BodyTemperature; 94 import com.android.server.healthconnect.proto.backuprestore.BodyWaterMass; 95 import com.android.server.healthconnect.proto.backuprestore.BoneMass; 96 import com.android.server.healthconnect.proto.backuprestore.CervicalMucus; 97 import com.android.server.healthconnect.proto.backuprestore.CyclingPedalingCadence; 98 import com.android.server.healthconnect.proto.backuprestore.CyclingPedalingCadence.CyclingPedalingCadenceSample; 99 import com.android.server.healthconnect.proto.backuprestore.Distance; 100 import com.android.server.healthconnect.proto.backuprestore.ElevationGained; 101 import com.android.server.healthconnect.proto.backuprestore.ExerciseSession; 102 import com.android.server.healthconnect.proto.backuprestore.ExerciseSession.ExerciseLap; 103 import com.android.server.healthconnect.proto.backuprestore.ExerciseSession.ExerciseRoute; 104 import com.android.server.healthconnect.proto.backuprestore.ExerciseSession.ExerciseRoute.Location; 105 import com.android.server.healthconnect.proto.backuprestore.ExerciseSession.ExerciseSegment; 106 import com.android.server.healthconnect.proto.backuprestore.FloorsClimbed; 107 import com.android.server.healthconnect.proto.backuprestore.HeartRate; 108 import com.android.server.healthconnect.proto.backuprestore.HeartRateVariabilityRmssd; 109 import com.android.server.healthconnect.proto.backuprestore.Height; 110 import com.android.server.healthconnect.proto.backuprestore.Hydration; 111 import com.android.server.healthconnect.proto.backuprestore.InstantRecord; 112 import com.android.server.healthconnect.proto.backuprestore.IntermenstrualBleeding; 113 import com.android.server.healthconnect.proto.backuprestore.IntervalRecord; 114 import com.android.server.healthconnect.proto.backuprestore.LeanBodyMass; 115 import com.android.server.healthconnect.proto.backuprestore.MenstruationFlow; 116 import com.android.server.healthconnect.proto.backuprestore.MenstruationPeriod; 117 import com.android.server.healthconnect.proto.backuprestore.MindfulnessSession; 118 import com.android.server.healthconnect.proto.backuprestore.Nutrition; 119 import com.android.server.healthconnect.proto.backuprestore.OvulationTest; 120 import com.android.server.healthconnect.proto.backuprestore.OxygenSaturation; 121 import com.android.server.healthconnect.proto.backuprestore.PlannedExerciseSession; 122 import com.android.server.healthconnect.proto.backuprestore.PlannedExerciseSession.PlannedExerciseBlock; 123 import com.android.server.healthconnect.proto.backuprestore.PlannedExerciseSession.PlannedExerciseBlock.PlannedExerciseStep; 124 import com.android.server.healthconnect.proto.backuprestore.PlannedExerciseSession.PlannedExerciseBlock.PlannedExerciseStep.ExerciseCompletionGoal; 125 import com.android.server.healthconnect.proto.backuprestore.PlannedExerciseSession.PlannedExerciseBlock.PlannedExerciseStep.ExercisePerformanceGoal; 126 import com.android.server.healthconnect.proto.backuprestore.Record; 127 import com.android.server.healthconnect.proto.backuprestore.RespiratoryRate; 128 import com.android.server.healthconnect.proto.backuprestore.RestingHeartRate; 129 import com.android.server.healthconnect.proto.backuprestore.SexualActivity; 130 import com.android.server.healthconnect.proto.backuprestore.SkinTemperature; 131 import com.android.server.healthconnect.proto.backuprestore.SleepSession; 132 import com.android.server.healthconnect.proto.backuprestore.SleepSession.SleepStage; 133 import com.android.server.healthconnect.proto.backuprestore.Speed; 134 import com.android.server.healthconnect.proto.backuprestore.Speed.SpeedSample; 135 import com.android.server.healthconnect.proto.backuprestore.Steps; 136 import com.android.server.healthconnect.proto.backuprestore.StepsCadence; 137 import com.android.server.healthconnect.proto.backuprestore.TotalCaloriesBurned; 138 import com.android.server.healthconnect.proto.backuprestore.Vo2Max; 139 import com.android.server.healthconnect.proto.backuprestore.Weight; 140 import com.android.server.healthconnect.proto.backuprestore.WheelchairPushes; 141 142 import java.lang.reflect.InvocationTargetException; 143 import java.time.Duration; 144 import java.util.List; 145 import java.util.Map; 146 import java.util.Objects; 147 import java.util.UUID; 148 149 /** 150 * A helper class used to create {@link RecordInternal} objects using its proto. 151 * 152 * @hide 153 */ 154 public final class RecordProtoConverter { 155 156 public static final int PROTO_VERSION = 1; 157 158 private final Map<Integer, Class<? extends RecordInternal<?>>> mDataTypeClassMap = 159 HealthConnectMappings.getInstance().getRecordIdToInternalRecordClassMap(); 160 161 /** Creates a {@link RecordInternal} from the {@link Record} */ toRecordInternal(Record recordProto)162 public RecordInternal<?> toRecordInternal(Record recordProto) 163 throws NoSuchMethodException, 164 InvocationTargetException, 165 InstantiationException, 166 IllegalAccessException { 167 int recordTypeId = getRecordTypeId(recordProto); 168 Class<? extends RecordInternal<?>> recordClass = mDataTypeClassMap.get(recordTypeId); 169 Objects.requireNonNull(recordClass); 170 RecordInternal<?> recordInternal = recordClass.getConstructor().newInstance(); 171 populateRecordInternal(recordProto, recordInternal); 172 return recordInternal; 173 } 174 175 /** Creates a {@link Record} from the {@link RecordInternal} */ toRecordProto(RecordInternal<?> recordInternal)176 public Record toRecordProto(RecordInternal<?> recordInternal) { 177 Record.Builder builder = 178 Record.newBuilder() 179 .setUuid( 180 recordInternal.getUuid() == null 181 ? "" 182 : recordInternal.getUuid().toString()) 183 .setLastModifiedTime(recordInternal.getLastModifiedTime()) 184 .setClientRecordVersion(recordInternal.getClientRecordVersion()) 185 .setDeviceType(recordInternal.getDeviceType()) 186 .setRecordingMethod(recordInternal.getRecordingMethod()); 187 if (recordInternal.getPackageName() != null) { 188 builder.setPackageName(recordInternal.getPackageName()); 189 } 190 if (recordInternal.getClientRecordId() != null) { 191 builder.setClientRecordId(recordInternal.getClientRecordId()); 192 } 193 if (recordInternal.getManufacturer() != null) { 194 builder.setManufacturer(recordInternal.getManufacturer()); 195 } 196 if (recordInternal.getModel() != null) { 197 builder.setModel(recordInternal.getModel()); 198 } 199 200 if (recordInternal instanceof IntervalRecordInternal<?> intervalRecordInternal) { 201 builder.setIntervalRecord(toIntervalRecordProto(intervalRecordInternal)); 202 } else if (recordInternal instanceof InstantRecordInternal<?> instantRecordInternal) { 203 builder.setInstantRecord(toInstantRecordProto(instantRecordInternal)); 204 } else { 205 throw new IllegalArgumentException( 206 "Unknown record type " + recordInternal.getClass().getSimpleName()); 207 } 208 209 return builder.build(); 210 } 211 toIntervalRecordProto(IntervalRecordInternal<?> intervalRecordInternal)212 private IntervalRecord toIntervalRecordProto(IntervalRecordInternal<?> intervalRecordInternal) { 213 IntervalRecord.Builder builder = 214 IntervalRecord.newBuilder() 215 .setStartTime(intervalRecordInternal.getStartTimeInMillis()) 216 .setStartZoneOffset(intervalRecordInternal.getStartZoneOffsetInSeconds()) 217 .setEndTime(intervalRecordInternal.getEndTimeInMillis()) 218 .setEndZoneOffset(intervalRecordInternal.getEndZoneOffsetInSeconds()); 219 220 if (intervalRecordInternal 221 instanceof ActiveCaloriesBurnedRecordInternal activeCaloriesBurnedRecordInternal) { 222 builder.setActiveCaloriesBurned( 223 toActiveCaloriesBurnedProto(activeCaloriesBurnedRecordInternal)); 224 } else if (intervalRecordInternal 225 instanceof ActivityIntensityRecordInternal activityIntensityRecordInternal) { 226 builder.setActivityIntensity(toActivityIntensityProto(activityIntensityRecordInternal)); 227 } else if (intervalRecordInternal 228 instanceof 229 CyclingPedalingCadenceRecordInternal cyclingPedalingCadenceRecordInternal) { 230 builder.setCyclingPedalingCadence( 231 toCyclingPedalingCadenceProto(cyclingPedalingCadenceRecordInternal)); 232 } else if (intervalRecordInternal 233 instanceof DistanceRecordInternal distanceRecordInternal) { 234 builder.setDistance(toDistanceProto(distanceRecordInternal)); 235 } else if (intervalRecordInternal 236 instanceof ElevationGainedRecordInternal elevationGainedRecordInternal) { 237 builder.setElevationGained(toElevationGainedProto(elevationGainedRecordInternal)); 238 } else if (intervalRecordInternal 239 instanceof ExerciseSessionRecordInternal exerciseSessionRecordInternal) { 240 builder.setExerciseSession(toExerciseSessionProto(exerciseSessionRecordInternal)); 241 } else if (intervalRecordInternal 242 instanceof FloorsClimbedRecordInternal floorsClimbedRecordInternal) { 243 builder.setFloorsClimbed(toFloorsClimbedProto(floorsClimbedRecordInternal)); 244 } else if (intervalRecordInternal 245 instanceof HeartRateRecordInternal heartRateRecordInternal) { 246 builder.setHeartRate(toHeartRateProto(heartRateRecordInternal)); 247 } else if (intervalRecordInternal 248 instanceof HydrationRecordInternal hydrationRecordInternal) { 249 builder.setHydration(toHydrationProto(hydrationRecordInternal)); 250 } else if (intervalRecordInternal instanceof MenstruationPeriodRecordInternal) { 251 builder.setMenstruationPeriod(MenstruationPeriod.getDefaultInstance()); 252 } else if (intervalRecordInternal 253 instanceof MindfulnessSessionRecordInternal mindfulnessSessionRecordInternal) { 254 builder.setMindfulnessSession( 255 toMindfulnessSessionProto(mindfulnessSessionRecordInternal)); 256 } else if (intervalRecordInternal 257 instanceof NutritionRecordInternal nutritionRecordInternal) { 258 builder.setNutrition(toNutritionProto(nutritionRecordInternal)); 259 } else if (intervalRecordInternal 260 instanceof 261 PlannedExerciseSessionRecordInternal plannedExerciseSessionRecordInternal) { 262 builder.setPlannedExerciseSession( 263 toPlannedExerciseSessionProto(plannedExerciseSessionRecordInternal)); 264 } else if (intervalRecordInternal instanceof PowerRecordInternal powerRecordInternal) { 265 builder.setPower(toPowerProto(powerRecordInternal)); 266 } else if (intervalRecordInternal 267 instanceof SkinTemperatureRecordInternal skinTemperatureRecordInternal) { 268 builder.setSkinTemperature(toSkinTemperatureProto(skinTemperatureRecordInternal)); 269 } else if (intervalRecordInternal 270 instanceof SleepSessionRecordInternal sleepSessionRecordInternal) { 271 builder.setSleepSession(toSleepSessionProto(sleepSessionRecordInternal)); 272 } else if (intervalRecordInternal instanceof SpeedRecordInternal speedRecordInternal) { 273 builder.setSpeed(toSpeedProto(speedRecordInternal)); 274 } else if (intervalRecordInternal instanceof StepsRecordInternal stepsRecordInternal) { 275 builder.setSteps(toStepsProto(stepsRecordInternal)); 276 } else if (intervalRecordInternal 277 instanceof StepsCadenceRecordInternal stepsCadenceRecordInternal) { 278 builder.setStepsCadence(toStepsCadenceProto(stepsCadenceRecordInternal)); 279 } else if (intervalRecordInternal 280 instanceof TotalCaloriesBurnedRecordInternal totalCaloriesBurnedRecordInternal) { 281 builder.setTotalCaloriesBurned( 282 toTotalCaloriesBurnedProto(totalCaloriesBurnedRecordInternal)); 283 } else if (intervalRecordInternal 284 instanceof WheelchairPushesRecordInternal wheelchairPushesRecordInternal) { 285 builder.setWheelchairPushes(toWheelchairPushesProto(wheelchairPushesRecordInternal)); 286 } else { 287 throw new IllegalArgumentException( 288 "Unknown interval record type " 289 + intervalRecordInternal.getClass().getSimpleName()); 290 } 291 292 return builder.build(); 293 } 294 toActiveCaloriesBurnedProto( ActiveCaloriesBurnedRecordInternal activeCaloriesBurnedRecordInternal)295 private static ActiveCaloriesBurned toActiveCaloriesBurnedProto( 296 ActiveCaloriesBurnedRecordInternal activeCaloriesBurnedRecordInternal) { 297 return ActiveCaloriesBurned.newBuilder() 298 .setEnergy(activeCaloriesBurnedRecordInternal.getEnergy()) 299 .build(); 300 } 301 toActivityIntensityProto( ActivityIntensityRecordInternal activityIntensityRecordInternal)302 private static ActivityIntensity toActivityIntensityProto( 303 ActivityIntensityRecordInternal activityIntensityRecordInternal) { 304 return ActivityIntensity.newBuilder() 305 .setActivityIntensityType( 306 activityIntensityRecordInternal.getActivityIntensityType()) 307 .build(); 308 } 309 toCyclingPedalingCadenceProto( CyclingPedalingCadenceRecordInternal cyclingPedalingCadenceRecordInternal)310 private static CyclingPedalingCadence toCyclingPedalingCadenceProto( 311 CyclingPedalingCadenceRecordInternal cyclingPedalingCadenceRecordInternal) { 312 List<CyclingPedalingCadenceSample> samples = 313 cyclingPedalingCadenceRecordInternal.getSamples().stream() 314 .map( 315 sample -> 316 CyclingPedalingCadenceSample.newBuilder() 317 .setRevolutionsPerMinute( 318 sample.getRevolutionsPerMinute()) 319 .setEpochMillis(sample.getEpochMillis()) 320 .build()) 321 .toList(); 322 323 return CyclingPedalingCadence.newBuilder().addAllSample(samples).build(); 324 } 325 toDistanceProto(DistanceRecordInternal distanceRecordInternal)326 private static Distance toDistanceProto(DistanceRecordInternal distanceRecordInternal) { 327 return Distance.newBuilder().setDistance(distanceRecordInternal.getDistance()).build(); 328 } 329 toElevationGainedProto( ElevationGainedRecordInternal elevationGainedRecordInternal)330 private static ElevationGained toElevationGainedProto( 331 ElevationGainedRecordInternal elevationGainedRecordInternal) { 332 return ElevationGained.newBuilder() 333 .setElevation(elevationGainedRecordInternal.getElevation()) 334 .build(); 335 } 336 toExerciseSessionProto( ExerciseSessionRecordInternal exerciseSessionRecordInternal)337 private static ExerciseSession toExerciseSessionProto( 338 ExerciseSessionRecordInternal exerciseSessionRecordInternal) { 339 ExerciseSession.Builder builder = 340 ExerciseSession.newBuilder() 341 .setExerciseType(exerciseSessionRecordInternal.getExerciseType()) 342 .setHasRoute(exerciseSessionRecordInternal.hasRoute()); 343 344 if (exerciseSessionRecordInternal.getNotes() != null) { 345 builder.setNotes(exerciseSessionRecordInternal.getNotes()); 346 } 347 if (exerciseSessionRecordInternal.getTitle() != null) { 348 builder.setTitle(exerciseSessionRecordInternal.getTitle()); 349 } 350 if (exerciseSessionRecordInternal.getRoute() != null) { 351 List<Location> routeLocations = 352 exerciseSessionRecordInternal.getRoute().getRouteLocations().stream() 353 .map(RecordProtoConverter::toLocationProto) 354 .toList(); 355 builder.setRoute(ExerciseRoute.newBuilder().addAllRouteLocation(routeLocations)); 356 } 357 if (exerciseSessionRecordInternal.getLaps() != null) { 358 builder.addAllLap( 359 exerciseSessionRecordInternal.getLaps().stream() 360 .map(RecordProtoConverter::toLapProto) 361 .toList()); 362 } 363 if (exerciseSessionRecordInternal.getSegments() != null) { 364 builder.addAllSegment( 365 exerciseSessionRecordInternal.getSegments().stream() 366 .map(RecordProtoConverter::toSegmentProto) 367 .toList()); 368 } 369 if (exerciseSessionRecordInternal.getPlannedExerciseSessionId() != null) { 370 builder.setPlannedExerciseSessionId( 371 exerciseSessionRecordInternal.getPlannedExerciseSessionId().toString()); 372 } 373 374 return builder.build(); 375 } 376 toLocationProto(LocationInternal locationInternal)377 private static Location toLocationProto(LocationInternal locationInternal) { 378 return Location.newBuilder() 379 .setTime(locationInternal.getTime()) 380 .setLatitude(locationInternal.getLatitude()) 381 .setLongitude(locationInternal.getLongitude()) 382 .setHorizontalAccuracy(locationInternal.getHorizontalAccuracy()) 383 .setVerticalAccuracy(locationInternal.getVerticalAccuracy()) 384 .setAltitude(locationInternal.getAltitude()) 385 .build(); 386 } 387 toLapProto(ExerciseLapInternal lapInternal)388 private static ExerciseLap toLapProto(ExerciseLapInternal lapInternal) { 389 return ExerciseLap.newBuilder() 390 .setStartTime(lapInternal.getStartTime()) 391 .setEndTime(lapInternal.getEndTime()) 392 .setLength(lapInternal.getLength()) 393 .build(); 394 } 395 toSegmentProto(ExerciseSegmentInternal segmentInternal)396 private static ExerciseSegment toSegmentProto(ExerciseSegmentInternal segmentInternal) { 397 return ExerciseSegment.newBuilder() 398 .setStartTime(segmentInternal.getStartTime()) 399 .setEndTime(segmentInternal.getEndTime()) 400 .setSegmentType(segmentInternal.getSegmentType()) 401 .setRepetitionsCount(segmentInternal.getRepetitionsCount()) 402 .build(); 403 } 404 toFloorsClimbedProto( FloorsClimbedRecordInternal floorsClimbedRecordInternal)405 private static FloorsClimbed toFloorsClimbedProto( 406 FloorsClimbedRecordInternal floorsClimbedRecordInternal) { 407 return FloorsClimbed.newBuilder() 408 .setFloors(floorsClimbedRecordInternal.getFloors()) 409 .build(); 410 } 411 toHeartRateProto(HeartRateRecordInternal heartRateRecordInternal)412 private static HeartRate toHeartRateProto(HeartRateRecordInternal heartRateRecordInternal) { 413 List<HeartRate.HeartRateSample> samples = 414 heartRateRecordInternal.getSamples().stream() 415 .map( 416 sample -> 417 HeartRate.HeartRateSample.newBuilder() 418 .setBeatsPerMinute(sample.getBeatsPerMinute()) 419 .setEpochMillis(sample.getEpochMillis()) 420 .build()) 421 .toList(); 422 423 return HeartRate.newBuilder().addAllSample(samples).build(); 424 } 425 toHydrationProto(HydrationRecordInternal hydrationRecordInternal)426 private static Hydration toHydrationProto(HydrationRecordInternal hydrationRecordInternal) { 427 return Hydration.newBuilder().setVolume(hydrationRecordInternal.getVolume()).build(); 428 } 429 toMindfulnessSessionProto( MindfulnessSessionRecordInternal mindfulnessSessionRecordInternal)430 private static MindfulnessSession toMindfulnessSessionProto( 431 MindfulnessSessionRecordInternal mindfulnessSessionRecordInternal) { 432 MindfulnessSession.Builder builder = 433 MindfulnessSession.newBuilder() 434 .setMindfulnessSessionType( 435 mindfulnessSessionRecordInternal.getMindfulnessSessionType()); 436 if (mindfulnessSessionRecordInternal.getTitle() != null) { 437 builder.setTitle(mindfulnessSessionRecordInternal.getTitle()); 438 } 439 if (mindfulnessSessionRecordInternal.getNotes() != null) { 440 builder.setNotes(mindfulnessSessionRecordInternal.getNotes()); 441 } 442 443 return builder.build(); 444 } 445 toNutritionProto(NutritionRecordInternal nutritionRecordInternal)446 private static Nutrition toNutritionProto(NutritionRecordInternal nutritionRecordInternal) { 447 Nutrition.Builder builder = 448 Nutrition.newBuilder() 449 .setUnsaturatedFat(nutritionRecordInternal.getUnsaturatedFat()) 450 .setPotassium(nutritionRecordInternal.getPotassium()) 451 .setThiamin(nutritionRecordInternal.getThiamin()) 452 .setMealType(nutritionRecordInternal.getMealType()) 453 .setTransFat(nutritionRecordInternal.getTransFat()) 454 .setManganese(nutritionRecordInternal.getManganese()) 455 .setEnergyFromFat(nutritionRecordInternal.getEnergyFromFat()) 456 .setCaffeine(nutritionRecordInternal.getCaffeine()) 457 .setDietaryFiber(nutritionRecordInternal.getDietaryFiber()) 458 .setSelenium(nutritionRecordInternal.getSelenium()) 459 .setVitaminB6(nutritionRecordInternal.getVitaminB6()) 460 .setProtein(nutritionRecordInternal.getProtein()) 461 .setChloride(nutritionRecordInternal.getChloride()) 462 .setCholesterol(nutritionRecordInternal.getCholesterol()) 463 .setCopper(nutritionRecordInternal.getCopper()) 464 .setIodine(nutritionRecordInternal.getIodine()) 465 .setVitaminB12(nutritionRecordInternal.getVitaminB12()) 466 .setZinc(nutritionRecordInternal.getZinc()) 467 .setRiboflavin(nutritionRecordInternal.getRiboflavin()) 468 .setEnergy(nutritionRecordInternal.getEnergy()) 469 .setMolybdenum(nutritionRecordInternal.getMolybdenum()) 470 .setPhosphorus(nutritionRecordInternal.getPhosphorus()) 471 .setChromium(nutritionRecordInternal.getChromium()) 472 .setTotalFat(nutritionRecordInternal.getTotalFat()) 473 .setCalcium(nutritionRecordInternal.getCalcium()) 474 .setVitaminC(nutritionRecordInternal.getVitaminC()) 475 .setVitaminE(nutritionRecordInternal.getVitaminE()) 476 .setBiotin(nutritionRecordInternal.getBiotin()) 477 .setVitaminD(nutritionRecordInternal.getVitaminD()) 478 .setNiacin(nutritionRecordInternal.getNiacin()) 479 .setMagnesium(nutritionRecordInternal.getMagnesium()) 480 .setTotalCarbohydrate(nutritionRecordInternal.getTotalCarbohydrate()) 481 .setVitaminK(nutritionRecordInternal.getVitaminK()) 482 .setPolyunsaturatedFat(nutritionRecordInternal.getPolyunsaturatedFat()) 483 .setSaturatedFat(nutritionRecordInternal.getSaturatedFat()) 484 .setSodium(nutritionRecordInternal.getSodium()) 485 .setFolate(nutritionRecordInternal.getFolate()) 486 .setMonounsaturatedFat(nutritionRecordInternal.getMonounsaturatedFat()) 487 .setPantothenicAcid(nutritionRecordInternal.getPantothenicAcid()) 488 .setIron(nutritionRecordInternal.getIron()) 489 .setVitaminA(nutritionRecordInternal.getVitaminA()) 490 .setFolicAcid(nutritionRecordInternal.getFolicAcid()) 491 .setSugar(nutritionRecordInternal.getSugar()); 492 493 if (nutritionRecordInternal.getMealName() != null) { 494 builder.setMealName(nutritionRecordInternal.getMealName()); 495 } 496 497 return builder.build(); 498 } 499 toPlannedExerciseSessionProto( PlannedExerciseSessionRecordInternal plannedExerciseSessionRecordInternal)500 private static PlannedExerciseSession toPlannedExerciseSessionProto( 501 PlannedExerciseSessionRecordInternal plannedExerciseSessionRecordInternal) { 502 PlannedExerciseSession.Builder builder = 503 PlannedExerciseSession.newBuilder() 504 .setExerciseType(plannedExerciseSessionRecordInternal.getExerciseType()) 505 .setHasExplicitTime( 506 plannedExerciseSessionRecordInternal.getHasExplicitTime()) 507 .addAllExerciseBlock( 508 plannedExerciseSessionRecordInternal.getExerciseBlocks().stream() 509 .map(RecordProtoConverter::toPlannedExerciseBlockProto) 510 .toList()); 511 if (plannedExerciseSessionRecordInternal.getNotes() != null) { 512 builder.setNotes(plannedExerciseSessionRecordInternal.getNotes()); 513 } 514 if (plannedExerciseSessionRecordInternal.getTitle() != null) { 515 builder.setTitle(plannedExerciseSessionRecordInternal.getTitle()); 516 } 517 518 return builder.build(); 519 } 520 toPlannedExerciseBlockProto( PlannedExerciseBlockInternal plannedExerciseBlockInternal)521 private static PlannedExerciseBlock toPlannedExerciseBlockProto( 522 PlannedExerciseBlockInternal plannedExerciseBlockInternal) { 523 PlannedExerciseBlock.Builder builder = 524 PlannedExerciseBlock.newBuilder() 525 .setRepetitions(plannedExerciseBlockInternal.getRepetitions()) 526 .addAllStep( 527 plannedExerciseBlockInternal.getExerciseSteps().stream() 528 .map(RecordProtoConverter::toPlannedExerciseStepProto) 529 .toList()); 530 if (plannedExerciseBlockInternal.getDescription() != null) { 531 builder.setDescription(plannedExerciseBlockInternal.getDescription()); 532 } 533 534 return builder.build(); 535 } 536 toPlannedExerciseStepProto( PlannedExerciseStepInternal plannedExerciseStepInternal)537 private static PlannedExerciseStep toPlannedExerciseStepProto( 538 PlannedExerciseStepInternal plannedExerciseStepInternal) { 539 PlannedExerciseStep.Builder builder = 540 PlannedExerciseStep.newBuilder() 541 .setExerciseType(plannedExerciseStepInternal.getExerciseType()) 542 .setExerciseCategory(plannedExerciseStepInternal.getExerciseCategory()); 543 if (plannedExerciseStepInternal.getDescription() != null) { 544 builder.setDescription(plannedExerciseStepInternal.getDescription()); 545 } 546 if (plannedExerciseStepInternal.getCompletionGoal() != null) { 547 builder.setCompletionGoal( 548 toCompletionGoalProto(plannedExerciseStepInternal.getCompletionGoal())); 549 } 550 if (plannedExerciseStepInternal.getPerformanceGoals() != null) { 551 builder.addAllPerformanceGoal( 552 plannedExerciseStepInternal.getPerformanceGoals().stream() 553 .map(RecordProtoConverter::toPerformanceGoalProto) 554 .toList()); 555 } 556 557 return builder.build(); 558 } 559 toPerformanceGoalProto( ExercisePerformanceGoalInternal performanceGoalInternal)560 private static ExercisePerformanceGoal toPerformanceGoalProto( 561 ExercisePerformanceGoalInternal performanceGoalInternal) { 562 if (performanceGoalInternal 563 instanceof ExercisePerformanceGoalInternal.PowerGoalInternal powerGoalInternal) { 564 return ExercisePerformanceGoal.newBuilder() 565 .setPowerGoal( 566 ExercisePerformanceGoal.PowerGoal.newBuilder() 567 .setMinPower(powerGoalInternal.getMinPower().getInWatts()) 568 .setMaxPower(powerGoalInternal.getMaxPower().getInWatts())) 569 .build(); 570 } else if (performanceGoalInternal 571 instanceof ExercisePerformanceGoalInternal.SpeedGoalInternal speedGoalInternal) { 572 return ExercisePerformanceGoal.newBuilder() 573 .setSpeedGoal( 574 ExercisePerformanceGoal.SpeedGoal.newBuilder() 575 .setMinSpeed( 576 speedGoalInternal.getMinSpeed().getInMetersPerSecond()) 577 .setMaxSpeed( 578 speedGoalInternal.getMaxSpeed().getInMetersPerSecond())) 579 .build(); 580 } else if (performanceGoalInternal 581 instanceof 582 ExercisePerformanceGoalInternal.CadenceGoalInternal cadenceGoalInternal) { 583 return ExercisePerformanceGoal.newBuilder() 584 .setCadenceGoal( 585 ExercisePerformanceGoal.CadenceGoal.newBuilder() 586 .setMinRpm(cadenceGoalInternal.getMinRpm()) 587 .setMaxRpm(cadenceGoalInternal.getMaxRpm())) 588 .build(); 589 } else if (performanceGoalInternal 590 instanceof 591 ExercisePerformanceGoalInternal.HeartRateGoalInternal heartRateGoalInternal) { 592 return ExercisePerformanceGoal.newBuilder() 593 .setHeartRateGoal( 594 ExercisePerformanceGoal.HeartRateGoal.newBuilder() 595 .setMinBpm(heartRateGoalInternal.getMinBpm()) 596 .setMaxBpm(heartRateGoalInternal.getMaxBpm())) 597 .build(); 598 } else if (performanceGoalInternal 599 instanceof ExercisePerformanceGoalInternal.WeightGoalInternal weightGoalInternal) { 600 return ExercisePerformanceGoal.newBuilder() 601 .setWeightGoal( 602 ExercisePerformanceGoal.WeightGoal.newBuilder() 603 .setMass(weightGoalInternal.getMass().getInGrams())) 604 .build(); 605 } else if (performanceGoalInternal 606 instanceof 607 ExercisePerformanceGoalInternal.RateOfPerceivedExertionGoalInternal 608 rateOfPerceivedExertionGoalInternal) { 609 return ExercisePerformanceGoal.newBuilder() 610 .setRateOfPerceivedExertionGoal( 611 ExercisePerformanceGoal.RateOfPerceivedExertionGoal.newBuilder() 612 .setRpe(rateOfPerceivedExertionGoalInternal.getRpe())) 613 .build(); 614 } else if (performanceGoalInternal 615 instanceof ExercisePerformanceGoalInternal.AmrapGoalInternal) { 616 return ExercisePerformanceGoal.newBuilder() 617 .setAmrapGoal(ExercisePerformanceGoal.AmrapGoal.getDefaultInstance()) 618 .build(); 619 } else if (performanceGoalInternal 620 instanceof ExercisePerformanceGoalInternal.UnknownGoalInternal) { 621 return ExercisePerformanceGoal.newBuilder() 622 .setUnknownGoal(ExercisePerformanceGoal.UnknownGoal.getDefaultInstance()) 623 .build(); 624 } else { 625 throw new IllegalArgumentException( 626 "Unknown performance goal type " 627 + performanceGoalInternal.getClass().getSimpleName()); 628 } 629 } 630 toCompletionGoalProto( ExerciseCompletionGoalInternal completionGoalInternal)631 private static ExerciseCompletionGoal toCompletionGoalProto( 632 ExerciseCompletionGoalInternal completionGoalInternal) { 633 if (completionGoalInternal 634 instanceof 635 ExerciseCompletionGoalInternal.DistanceGoalInternal distanceGoalInternal) { 636 return ExerciseCompletionGoal.newBuilder() 637 .setDistanceGoal( 638 ExerciseCompletionGoal.DistanceGoal.newBuilder() 639 .setDistance(distanceGoalInternal.getDistance().getInMeters())) 640 .build(); 641 } else if (completionGoalInternal 642 instanceof ExerciseCompletionGoalInternal.StepsGoalInternal stepsGoalInternal) { 643 return ExerciseCompletionGoal.newBuilder() 644 .setStepsGoal( 645 ExerciseCompletionGoal.StepsGoal.newBuilder() 646 .setSteps(stepsGoalInternal.getSteps())) 647 .build(); 648 } else if (completionGoalInternal 649 instanceof 650 ExerciseCompletionGoalInternal.DurationGoalInternal durationGoalInternal) { 651 return ExerciseCompletionGoal.newBuilder() 652 .setDurationGoal( 653 ExerciseCompletionGoal.DurationGoal.newBuilder() 654 .setDuration(durationGoalInternal.getDuration().toMillis())) 655 .build(); 656 } else if (completionGoalInternal 657 instanceof 658 ExerciseCompletionGoalInternal.RepetitionsGoalInternal repetitionsGoalInternal) { 659 return ExerciseCompletionGoal.newBuilder() 660 .setRepetitionsGoal( 661 ExerciseCompletionGoal.RepetitionsGoal.newBuilder() 662 .setRepetitions(repetitionsGoalInternal.getReps())) 663 .build(); 664 } else if (completionGoalInternal 665 instanceof 666 ExerciseCompletionGoalInternal.TotalCaloriesBurnedGoalInternal 667 totalCaloriesBurnedGoalInternal) { 668 return ExerciseCompletionGoal.newBuilder() 669 .setTotalCaloriesBurnedGoal( 670 ExerciseCompletionGoal.TotalCaloriesBurnedGoal.newBuilder() 671 .setTotalCalories( 672 totalCaloriesBurnedGoalInternal 673 .getTotalCalories() 674 .getInCalories())) 675 .build(); 676 } else if (completionGoalInternal 677 instanceof 678 ExerciseCompletionGoalInternal.ActiveCaloriesBurnedGoalInternal 679 activeCaloriesBurnedGoalInternal) { 680 return ExerciseCompletionGoal.newBuilder() 681 .setActiveCaloriesBurnedGoal( 682 ExerciseCompletionGoal.ActiveCaloriesBurnedGoal.newBuilder() 683 .setActiveCalories( 684 activeCaloriesBurnedGoalInternal 685 .getActiveCalories() 686 .getInCalories())) 687 .build(); 688 } else if (completionGoalInternal 689 instanceof 690 ExerciseCompletionGoalInternal.DistanceWithVariableRestGoalInternal 691 distanceWithVariableRestGoalInternal) { 692 return ExerciseCompletionGoal.newBuilder() 693 .setDistanceWithVariableRestGoal( 694 ExerciseCompletionGoal.DistanceWithVariableRestGoal.newBuilder() 695 .setDistance( 696 distanceWithVariableRestGoalInternal 697 .getDistance() 698 .getInMeters()) 699 .setDuration( 700 distanceWithVariableRestGoalInternal 701 .getDuration() 702 .toMillis())) 703 .build(); 704 } else if (completionGoalInternal 705 instanceof ExerciseCompletionGoalInternal.UnspecifiedGoalInternal) { 706 return ExerciseCompletionGoal.newBuilder() 707 .setUnspecifiedGoal(ExerciseCompletionGoal.UnspecifiedGoal.getDefaultInstance()) 708 .build(); 709 } else if (completionGoalInternal 710 instanceof ExerciseCompletionGoalInternal.UnknownGoalInternal) { 711 return ExerciseCompletionGoal.newBuilder() 712 .setUnknownGoal(ExerciseCompletionGoal.UnknownGoal.getDefaultInstance()) 713 .build(); 714 } else { 715 throw new IllegalArgumentException( 716 "Unknown completion goal type " 717 + completionGoalInternal.getClass().getSimpleName()); 718 } 719 } 720 toPowerProto( PowerRecordInternal powerRecordInternal)721 private static com.android.server.healthconnect.proto.backuprestore.Power toPowerProto( 722 PowerRecordInternal powerRecordInternal) { 723 List<com.android.server.healthconnect.proto.backuprestore.Power.PowerSample> samples = 724 powerRecordInternal.getSamples().stream() 725 .map( 726 sample -> 727 com.android.server.healthconnect.proto.backuprestore.Power 728 .PowerSample.newBuilder() 729 .setPower(sample.getPower()) 730 .setEpochMillis(sample.getEpochMillis()) 731 .build()) 732 .toList(); 733 734 return com.android.server.healthconnect.proto.backuprestore.Power.newBuilder() 735 .addAllSample(samples) 736 .build(); 737 } 738 toSkinTemperatureProto( SkinTemperatureRecordInternal skinTemperatureRecordInternal)739 private static SkinTemperature toSkinTemperatureProto( 740 SkinTemperatureRecordInternal skinTemperatureRecordInternal) { 741 List<SkinTemperature.SkinTemperatureDeltaSample> samples = 742 skinTemperatureRecordInternal.getSamples().stream() 743 .map( 744 sample -> 745 SkinTemperature.SkinTemperatureDeltaSample.newBuilder() 746 .setTemperatureDeltaInCelsius( 747 sample.mTemperatureDeltaInCelsius()) 748 .setEpochMillis(sample.mEpochMillis()) 749 .build()) 750 .toList(); 751 752 return SkinTemperature.newBuilder() 753 .setMeasurementLocation(skinTemperatureRecordInternal.getMeasurementLocation()) 754 .setBaseline(skinTemperatureRecordInternal.getBaseline().getInCelsius()) 755 .addAllSample(samples) 756 .build(); 757 } 758 toSleepSessionProto( SleepSessionRecordInternal sleepSessionRecordInternal)759 private static SleepSession toSleepSessionProto( 760 SleepSessionRecordInternal sleepSessionRecordInternal) { 761 SleepSession.Builder builder = SleepSession.newBuilder(); 762 763 if (sleepSessionRecordInternal.getNotes() != null) { 764 builder.setNotes(sleepSessionRecordInternal.getNotes()); 765 } 766 if (sleepSessionRecordInternal.getTitle() != null) { 767 builder.setTitle(sleepSessionRecordInternal.getTitle()); 768 } 769 if (sleepSessionRecordInternal.getSleepStages() != null) { 770 List<SleepStage> stages = 771 sleepSessionRecordInternal.getSleepStages().stream() 772 .map(RecordProtoConverter::toSleepStageProto) 773 .toList(); 774 builder.addAllStage(stages); 775 } 776 777 return builder.build(); 778 } 779 toSleepStageProto(SleepStageInternal sleepStageInternal)780 private static SleepStage toSleepStageProto(SleepStageInternal sleepStageInternal) { 781 return SleepStage.newBuilder() 782 .setStartTime(sleepStageInternal.getStartTime()) 783 .setEndTime(sleepStageInternal.getEndTime()) 784 .setStageType(sleepStageInternal.getStageType()) 785 .build(); 786 } 787 toSpeedProto(SpeedRecordInternal speedRecordInternal)788 private static Speed toSpeedProto(SpeedRecordInternal speedRecordInternal) { 789 List<SpeedSample> samples = 790 speedRecordInternal.getSamples().stream() 791 .map( 792 sample -> 793 SpeedSample.newBuilder() 794 .setSpeed(sample.getSpeed()) 795 .setEpochMillis(sample.getEpochMillis()) 796 .build()) 797 .toList(); 798 799 return Speed.newBuilder().addAllSample(samples).build(); 800 } 801 toStepsProto(StepsRecordInternal stepsRecordInternal)802 private static Steps toStepsProto(StepsRecordInternal stepsRecordInternal) { 803 return Steps.newBuilder().setCount(stepsRecordInternal.getCount()).build(); 804 } 805 toStepsCadenceProto( StepsCadenceRecordInternal stepsCadenceRecordInternal)806 private static StepsCadence toStepsCadenceProto( 807 StepsCadenceRecordInternal stepsCadenceRecordInternal) { 808 List<StepsCadence.StepsCadenceSample> samples = 809 stepsCadenceRecordInternal.getSamples().stream() 810 .map( 811 sample -> 812 StepsCadence.StepsCadenceSample.newBuilder() 813 .setRate(sample.getRate()) 814 .setEpochMillis(sample.getEpochMillis()) 815 .build()) 816 .toList(); 817 818 return StepsCadence.newBuilder().addAllSample(samples).build(); 819 } 820 toTotalCaloriesBurnedProto( TotalCaloriesBurnedRecordInternal totalCaloriesBurnedRecordInternal)821 private static TotalCaloriesBurned toTotalCaloriesBurnedProto( 822 TotalCaloriesBurnedRecordInternal totalCaloriesBurnedRecordInternal) { 823 return TotalCaloriesBurned.newBuilder() 824 .setEnergy(totalCaloriesBurnedRecordInternal.getEnergy()) 825 .build(); 826 } 827 toWheelchairPushesProto( WheelchairPushesRecordInternal wheelchairPushesRecordInternal)828 private static WheelchairPushes toWheelchairPushesProto( 829 WheelchairPushesRecordInternal wheelchairPushesRecordInternal) { 830 return WheelchairPushes.newBuilder() 831 .setCount((int) wheelchairPushesRecordInternal.getCount()) 832 .build(); 833 } 834 toInstantRecordProto(InstantRecordInternal<?> instantRecordInternal)835 private InstantRecord toInstantRecordProto(InstantRecordInternal<?> instantRecordInternal) { 836 InstantRecord.Builder builder = 837 InstantRecord.newBuilder() 838 .setTime(instantRecordInternal.getTimeInMillis()) 839 .setZoneOffset(instantRecordInternal.getZoneOffsetInSeconds()); 840 841 if (instantRecordInternal 842 instanceof BasalBodyTemperatureRecordInternal basalBodyTemperatureRecordInternal) { 843 builder.setBasalBodyTemperature( 844 toBasalBodyTemperatureProto(basalBodyTemperatureRecordInternal)); 845 } else if (instantRecordInternal 846 instanceof BasalMetabolicRateRecordInternal basalMetabolicRateRecordInternal) { 847 builder.setBasalMetabolicRate( 848 toBasalMetabolicRateProto(basalMetabolicRateRecordInternal)); 849 } else if (instantRecordInternal 850 instanceof BloodGlucoseRecordInternal bloodGlucoseRecordInternal) { 851 builder.setBloodGlucose(toBloodGlucoseProto(bloodGlucoseRecordInternal)); 852 } else if (instantRecordInternal 853 instanceof BloodPressureRecordInternal bloodPressureRecordInternal) { 854 builder.setBloodPressure(toBloodPressureProto(bloodPressureRecordInternal)); 855 } else if (instantRecordInternal instanceof BodyFatRecordInternal bodyFatRecordInternal) { 856 builder.setBodyFat(toBodyFatProto(bodyFatRecordInternal)); 857 } else if (instantRecordInternal 858 instanceof BodyTemperatureRecordInternal bodyTemperatureRecordInternal) { 859 builder.setBodyTemperature(toBodyTemperatureProto(bodyTemperatureRecordInternal)); 860 } else if (instantRecordInternal 861 instanceof BodyWaterMassRecordInternal bodyWaterMassRecordInternal) { 862 builder.setBodyWaterMass(toBodyWaterMassProto(bodyWaterMassRecordInternal)); 863 } else if (instantRecordInternal instanceof BoneMassRecordInternal boneMassRecordInternal) { 864 builder.setBoneMass(toBoneMassProto(boneMassRecordInternal)); 865 } else if (instantRecordInternal 866 instanceof CervicalMucusRecordInternal cervicalMucusRecordInternal) { 867 builder.setCervicalMucus(toCervicalMucusProto(cervicalMucusRecordInternal)); 868 } else if (instantRecordInternal 869 instanceof 870 HeartRateVariabilityRmssdRecordInternal heartRateVariabilityRmssdRecordInternal) { 871 builder.setHeartRateVariabilityRmssd( 872 toHeartRateVariabilityRmssdProto(heartRateVariabilityRmssdRecordInternal)); 873 } else if (instantRecordInternal instanceof HeightRecordInternal heightRecordInternal) { 874 builder.setHeight(toHeightProto(heightRecordInternal)); 875 } else if (instantRecordInternal instanceof IntermenstrualBleedingRecordInternal) { 876 builder.setIntermenstrualBleeding(IntermenstrualBleeding.getDefaultInstance()); 877 } else if (instantRecordInternal 878 instanceof LeanBodyMassRecordInternal leanBodyMassRecordInternal) { 879 builder.setLeanBodyMass(toLeanBodyMassProto(leanBodyMassRecordInternal)); 880 } else if (instantRecordInternal 881 instanceof MenstruationFlowRecordInternal menstruationFlowRecordInternal) { 882 builder.setMenstruationFlow(toMenstruationFlowProto(menstruationFlowRecordInternal)); 883 } else if (instantRecordInternal 884 instanceof OvulationTestRecordInternal ovulationTestRecordInternal) { 885 builder.setOvulationTest(toOvulationTestProto(ovulationTestRecordInternal)); 886 } else if (instantRecordInternal 887 instanceof OxygenSaturationRecordInternal oxygenSaturationRecordInternal) { 888 builder.setOxygenSaturation(toOxygenSaturationProto(oxygenSaturationRecordInternal)); 889 } else if (instantRecordInternal 890 instanceof RespiratoryRateRecordInternal respiratoryRateRecordInternal) { 891 builder.setRespiratoryRate(toRespiratoryRateProto(respiratoryRateRecordInternal)); 892 } else if (instantRecordInternal 893 instanceof RestingHeartRateRecordInternal restingHeartRateRecordInternal) { 894 builder.setRestingHeartRate(toRestingHeartRateProto(restingHeartRateRecordInternal)); 895 } else if (instantRecordInternal 896 instanceof SexualActivityRecordInternal sexualActivityRecordInternal) { 897 builder.setSexualActivity(toSexualActivityProto(sexualActivityRecordInternal)); 898 } else if (instantRecordInternal instanceof Vo2MaxRecordInternal vo2MaxRecordInternal) { 899 builder.setVo2Max(toVo2MaxProto(vo2MaxRecordInternal)); 900 } else if (instantRecordInternal instanceof WeightRecordInternal weightRecordInternal) { 901 builder.setWeight(toWeightProto(weightRecordInternal)); 902 } else { 903 throw new IllegalArgumentException( 904 "Unknown instant record type " 905 + instantRecordInternal.getClass().getSimpleName()); 906 } 907 908 return builder.build(); 909 } 910 toBasalBodyTemperatureProto( BasalBodyTemperatureRecordInternal basalBodyTemperatureRecordInternal)911 private static BasalBodyTemperature toBasalBodyTemperatureProto( 912 BasalBodyTemperatureRecordInternal basalBodyTemperatureRecordInternal) { 913 return BasalBodyTemperature.newBuilder() 914 .setMeasurementLocation(basalBodyTemperatureRecordInternal.getMeasurementLocation()) 915 .setTemperature(basalBodyTemperatureRecordInternal.getTemperature()) 916 .build(); 917 } 918 toBasalMetabolicRateProto( BasalMetabolicRateRecordInternal basalMetabolicRateRecordInternal)919 private static BasalMetabolicRate toBasalMetabolicRateProto( 920 BasalMetabolicRateRecordInternal basalMetabolicRateRecordInternal) { 921 return BasalMetabolicRate.newBuilder() 922 .setBasalMetabolicRate(basalMetabolicRateRecordInternal.getBasalMetabolicRate()) 923 .build(); 924 } 925 toBloodGlucoseProto( BloodGlucoseRecordInternal bloodGlucoseRecordInternal)926 private static BloodGlucose toBloodGlucoseProto( 927 BloodGlucoseRecordInternal bloodGlucoseRecordInternal) { 928 return BloodGlucose.newBuilder() 929 .setSpecimenSource(bloodGlucoseRecordInternal.getSpecimenSource()) 930 .setLevel(bloodGlucoseRecordInternal.getLevel()) 931 .setRelationToMeal(bloodGlucoseRecordInternal.getRelationToMeal()) 932 .setMealType(bloodGlucoseRecordInternal.getMealType()) 933 .build(); 934 } 935 toBloodPressureProto( BloodPressureRecordInternal bloodPressureRecordInternal)936 private static BloodPressure toBloodPressureProto( 937 BloodPressureRecordInternal bloodPressureRecordInternal) { 938 return BloodPressure.newBuilder() 939 .setMeasurementLocation(bloodPressureRecordInternal.getMeasurementLocation()) 940 .setSystolic(bloodPressureRecordInternal.getSystolic()) 941 .setDiastolic(bloodPressureRecordInternal.getDiastolic()) 942 .setBodyPosition(bloodPressureRecordInternal.getBodyPosition()) 943 .build(); 944 } 945 toBodyFatProto(BodyFatRecordInternal bodyFatRecordInternal)946 private static BodyFat toBodyFatProto(BodyFatRecordInternal bodyFatRecordInternal) { 947 return BodyFat.newBuilder().setPercentage(bodyFatRecordInternal.getPercentage()).build(); 948 } 949 toBodyTemperatureProto( BodyTemperatureRecordInternal bodyTemperatureRecordInternal)950 private static BodyTemperature toBodyTemperatureProto( 951 BodyTemperatureRecordInternal bodyTemperatureRecordInternal) { 952 return BodyTemperature.newBuilder() 953 .setMeasurementLocation(bodyTemperatureRecordInternal.getMeasurementLocation()) 954 .setTemperature(bodyTemperatureRecordInternal.getTemperature()) 955 .build(); 956 } 957 toBodyWaterMassProto( BodyWaterMassRecordInternal bodyWaterMassRecordInternal)958 private static BodyWaterMass toBodyWaterMassProto( 959 BodyWaterMassRecordInternal bodyWaterMassRecordInternal) { 960 return BodyWaterMass.newBuilder() 961 .setBodyWaterMass(bodyWaterMassRecordInternal.getBodyWaterMass()) 962 .build(); 963 } 964 toBoneMassProto(BoneMassRecordInternal boneMassRecordInternal)965 private static BoneMass toBoneMassProto(BoneMassRecordInternal boneMassRecordInternal) { 966 return BoneMass.newBuilder().setMass(boneMassRecordInternal.getMass()).build(); 967 } 968 toCervicalMucusProto( CervicalMucusRecordInternal cervicalMucusRecordInternal)969 private static CervicalMucus toCervicalMucusProto( 970 CervicalMucusRecordInternal cervicalMucusRecordInternal) { 971 return CervicalMucus.newBuilder() 972 .setSensation(cervicalMucusRecordInternal.getSensation()) 973 .setAppearance(cervicalMucusRecordInternal.getAppearance()) 974 .build(); 975 } 976 toHeartRateVariabilityRmssdProto( HeartRateVariabilityRmssdRecordInternal heartRateVariabilityRmssdRecordInternal)977 private static HeartRateVariabilityRmssd toHeartRateVariabilityRmssdProto( 978 HeartRateVariabilityRmssdRecordInternal heartRateVariabilityRmssdRecordInternal) { 979 return HeartRateVariabilityRmssd.newBuilder() 980 .setHeartRateVariabilityMillis( 981 heartRateVariabilityRmssdRecordInternal.getHeartRateVariabilityMillis()) 982 .build(); 983 } 984 toHeightProto(HeightRecordInternal heightRecordInternal)985 private static Height toHeightProto(HeightRecordInternal heightRecordInternal) { 986 return Height.newBuilder().setHeight(heightRecordInternal.getHeight()).build(); 987 } 988 toLeanBodyMassProto( LeanBodyMassRecordInternal leanBodyMassRecordInternal)989 private static LeanBodyMass toLeanBodyMassProto( 990 LeanBodyMassRecordInternal leanBodyMassRecordInternal) { 991 return LeanBodyMass.newBuilder().setMass(leanBodyMassRecordInternal.getMass()).build(); 992 } 993 toMenstruationFlowProto( MenstruationFlowRecordInternal menstruationFlowRecordInternal)994 private static MenstruationFlow toMenstruationFlowProto( 995 MenstruationFlowRecordInternal menstruationFlowRecordInternal) { 996 return MenstruationFlow.newBuilder() 997 .setFlow(menstruationFlowRecordInternal.getFlow()) 998 .build(); 999 } 1000 toOvulationTestProto( OvulationTestRecordInternal ovulationTestRecordInternal)1001 private static OvulationTest toOvulationTestProto( 1002 OvulationTestRecordInternal ovulationTestRecordInternal) { 1003 return OvulationTest.newBuilder() 1004 .setResult(ovulationTestRecordInternal.getResult()) 1005 .build(); 1006 } 1007 toOxygenSaturationProto( OxygenSaturationRecordInternal oxygenSaturationRecordInternal)1008 private static OxygenSaturation toOxygenSaturationProto( 1009 OxygenSaturationRecordInternal oxygenSaturationRecordInternal) { 1010 return OxygenSaturation.newBuilder() 1011 .setPercentage(oxygenSaturationRecordInternal.getPercentage()) 1012 .build(); 1013 } 1014 toRespiratoryRateProto( RespiratoryRateRecordInternal respiratoryRateRecordInternal)1015 private static RespiratoryRate toRespiratoryRateProto( 1016 RespiratoryRateRecordInternal respiratoryRateRecordInternal) { 1017 return RespiratoryRate.newBuilder() 1018 .setRate(respiratoryRateRecordInternal.getRate()) 1019 .build(); 1020 } 1021 toRestingHeartRateProto( RestingHeartRateRecordInternal restingHeartRateRecordInternal)1022 private static RestingHeartRate toRestingHeartRateProto( 1023 RestingHeartRateRecordInternal restingHeartRateRecordInternal) { 1024 return RestingHeartRate.newBuilder() 1025 .setBeatsPerMinute(restingHeartRateRecordInternal.getBeatsPerMinute()) 1026 .build(); 1027 } 1028 toSexualActivityProto( SexualActivityRecordInternal sexualActivityRecordInternal)1029 private static SexualActivity toSexualActivityProto( 1030 SexualActivityRecordInternal sexualActivityRecordInternal) { 1031 return SexualActivity.newBuilder() 1032 .setProtectionUsed(sexualActivityRecordInternal.getProtectionUsed()) 1033 .build(); 1034 } 1035 toVo2MaxProto(Vo2MaxRecordInternal vo2MaxRecordInternal)1036 private static Vo2Max toVo2MaxProto(Vo2MaxRecordInternal vo2MaxRecordInternal) { 1037 return Vo2Max.newBuilder() 1038 .setMeasurementMethod(vo2MaxRecordInternal.getMeasurementMethod()) 1039 .setVo2MillilitersPerMinuteKilogram( 1040 vo2MaxRecordInternal.getVo2MillilitersPerMinuteKilogram()) 1041 .build(); 1042 } 1043 toWeightProto(WeightRecordInternal weightRecordInternal)1044 private static Weight toWeightProto(WeightRecordInternal weightRecordInternal) { 1045 return Weight.newBuilder().setWeight(weightRecordInternal.getWeight()).build(); 1046 } 1047 1048 @SuppressLint("WrongConstant") // Proto doesn't know about the device type & rec method IntDefs populateRecordInternal( Record recordProto, RecordInternal<?> recordInternal)1049 private static void populateRecordInternal( 1050 Record recordProto, RecordInternal<?> recordInternal) { 1051 String uuidString = recordProto.getUuid(); 1052 if (!uuidString.isEmpty()) { 1053 recordInternal.setUuid(UUID.fromString(uuidString)); 1054 } 1055 if (recordProto.hasPackageName()) { 1056 recordInternal.setPackageName(recordProto.getPackageName()); 1057 } 1058 recordInternal.setLastModifiedTime(recordProto.getLastModifiedTime()); 1059 if (recordProto.hasClientRecordId()) { 1060 recordInternal.setClientRecordId(recordProto.getClientRecordId()); 1061 } 1062 recordInternal.setClientRecordVersion(recordProto.getClientRecordVersion()); 1063 if (recordProto.hasManufacturer()) { 1064 recordInternal.setManufacturer(recordProto.getManufacturer()); 1065 } 1066 if (recordProto.hasModel()) { 1067 recordInternal.setModel(recordProto.getModel()); 1068 } 1069 recordInternal.setDeviceType(recordProto.getDeviceType()); 1070 recordInternal.setRecordingMethod(recordProto.getRecordingMethod()); 1071 1072 switch (recordProto.getSubRecordCase()) { 1073 case INTERVAL_RECORD -> 1074 populateIntervalRecordInternal( 1075 recordProto.getIntervalRecord(), 1076 (IntervalRecordInternal<?>) recordInternal); 1077 case INSTANT_RECORD -> 1078 populateInstantRecordInternal( 1079 recordProto.getInstantRecord(), 1080 (InstantRecordInternal<?>) recordInternal); 1081 default -> 1082 throw new IllegalArgumentException( 1083 "Unknown record type " + recordProto.getSubRecordCase()); 1084 } 1085 } 1086 populateIntervalRecordInternal( IntervalRecord intervalRecordProto, IntervalRecordInternal<?> intervalRecordInternal)1087 private static void populateIntervalRecordInternal( 1088 IntervalRecord intervalRecordProto, IntervalRecordInternal<?> intervalRecordInternal) { 1089 intervalRecordInternal 1090 .setStartTime(intervalRecordProto.getStartTime()) 1091 .setStartZoneOffset(intervalRecordProto.getStartZoneOffset()) 1092 .setEndTime(intervalRecordProto.getEndTime()) 1093 .setEndZoneOffset(intervalRecordProto.getEndZoneOffset()); 1094 1095 switch (intervalRecordProto.getDataCase()) { 1096 case ACTIVE_CALORIES_BURNED -> 1097 populateActiveCaloriesBurnedRecordInternal( 1098 intervalRecordProto.getActiveCaloriesBurned(), 1099 (ActiveCaloriesBurnedRecordInternal) intervalRecordInternal); 1100 case ACTIVITY_INTENSITY -> 1101 populateActivityIntensityRecordInternal( 1102 intervalRecordProto.getActivityIntensity(), 1103 (ActivityIntensityRecordInternal) intervalRecordInternal); 1104 case CYCLING_PEDALING_CADENCE -> 1105 populateCyclingPedalingCadenceRecordInternal( 1106 intervalRecordProto.getCyclingPedalingCadence(), 1107 (CyclingPedalingCadenceRecordInternal) intervalRecordInternal); 1108 case DISTANCE -> 1109 populateDistanceRecordInternal( 1110 intervalRecordProto.getDistance(), 1111 (DistanceRecordInternal) intervalRecordInternal); 1112 case ELEVATION_GAINED -> 1113 populateElevationGainedRecordInternal( 1114 intervalRecordProto.getElevationGained(), 1115 (ElevationGainedRecordInternal) intervalRecordInternal); 1116 case EXERCISE_SESSION -> 1117 populateExerciseSessionRecordInternal( 1118 intervalRecordProto.getExerciseSession(), 1119 (ExerciseSessionRecordInternal) intervalRecordInternal); 1120 case FLOORS_CLIMBED -> 1121 populateFloorsClimbedRecordInternal( 1122 intervalRecordProto.getFloorsClimbed(), 1123 (FloorsClimbedRecordInternal) intervalRecordInternal); 1124 case HEART_RATE -> 1125 populateHeartRateRecordInternal( 1126 intervalRecordProto.getHeartRate(), 1127 (HeartRateRecordInternal) intervalRecordInternal); 1128 case HYDRATION -> 1129 populateHydrationRecordInternal( 1130 intervalRecordProto.getHydration(), 1131 (HydrationRecordInternal) intervalRecordInternal); 1132 case MENSTRUATION_PERIOD -> { 1133 // No data to populate. 1134 } 1135 case MINDFULNESS_SESSION -> 1136 populateMindfulnessSessionRecordInternal( 1137 intervalRecordProto.getMindfulnessSession(), 1138 (MindfulnessSessionRecordInternal) intervalRecordInternal); 1139 case NUTRITION -> 1140 populateNutritionRecordInternal( 1141 intervalRecordProto.getNutrition(), 1142 (NutritionRecordInternal) intervalRecordInternal); 1143 case PLANNED_EXERCISE_SESSION -> 1144 populatePlannedExerciseSessionRecordInternal( 1145 intervalRecordProto.getPlannedExerciseSession(), 1146 (PlannedExerciseSessionRecordInternal) intervalRecordInternal); 1147 case POWER -> 1148 populatePowerRecordInternal( 1149 intervalRecordProto.getPower(), 1150 (PowerRecordInternal) intervalRecordInternal); 1151 case SKIN_TEMPERATURE -> 1152 populateSkinTemperatureRecordInternal( 1153 intervalRecordProto.getSkinTemperature(), 1154 (SkinTemperatureRecordInternal) intervalRecordInternal); 1155 case SLEEP_SESSION -> 1156 populateSleepSessionRecordInternal( 1157 intervalRecordProto.getSleepSession(), 1158 (SleepSessionRecordInternal) intervalRecordInternal); 1159 case SPEED -> 1160 populateSpeedRecordInternal( 1161 intervalRecordProto.getSpeed(), 1162 (SpeedRecordInternal) intervalRecordInternal); 1163 case STEPS -> 1164 populateStepsRecordInternal( 1165 intervalRecordProto.getSteps(), 1166 (StepsRecordInternal) intervalRecordInternal); 1167 case STEPS_CADENCE -> 1168 populateStepsCadenceRecordInternal( 1169 intervalRecordProto.getStepsCadence(), 1170 (StepsCadenceRecordInternal) intervalRecordInternal); 1171 case TOTAL_CALORIES_BURNED -> 1172 populateTotalCaloriesBurnedRecordInternal( 1173 intervalRecordProto.getTotalCaloriesBurned(), 1174 (TotalCaloriesBurnedRecordInternal) intervalRecordInternal); 1175 case WHEELCHAIR_PUSHES -> 1176 populateWheelchairPushesRecordInternal( 1177 intervalRecordProto.getWheelchairPushes(), 1178 (WheelchairPushesRecordInternal) intervalRecordInternal); 1179 default -> 1180 throw new IllegalArgumentException( 1181 "Unknown record type " + intervalRecordProto.getDataCase()); 1182 } 1183 } 1184 populateActiveCaloriesBurnedRecordInternal( ActiveCaloriesBurned activeCaloriesBurnedProto, ActiveCaloriesBurnedRecordInternal activeCaloriesBurnedRecordInternal)1185 private static void populateActiveCaloriesBurnedRecordInternal( 1186 ActiveCaloriesBurned activeCaloriesBurnedProto, 1187 ActiveCaloriesBurnedRecordInternal activeCaloriesBurnedRecordInternal) { 1188 activeCaloriesBurnedRecordInternal.setEnergy(activeCaloriesBurnedProto.getEnergy()); 1189 } 1190 populateActivityIntensityRecordInternal( ActivityIntensity activityIntensityProto, ActivityIntensityRecordInternal activityIntensityRecordInternal)1191 private static void populateActivityIntensityRecordInternal( 1192 ActivityIntensity activityIntensityProto, 1193 ActivityIntensityRecordInternal activityIntensityRecordInternal) { 1194 activityIntensityRecordInternal.setActivityIntensityType( 1195 activityIntensityProto.getActivityIntensityType()); 1196 } 1197 populateCyclingPedalingCadenceRecordInternal( CyclingPedalingCadence cyclingPedalingCadenceProto, CyclingPedalingCadenceRecordInternal cyclingPedalingCadenceRecordInternal)1198 private static void populateCyclingPedalingCadenceRecordInternal( 1199 CyclingPedalingCadence cyclingPedalingCadenceProto, 1200 CyclingPedalingCadenceRecordInternal cyclingPedalingCadenceRecordInternal) { 1201 cyclingPedalingCadenceRecordInternal.setSamples( 1202 cyclingPedalingCadenceProto.getSampleList().stream() 1203 .map( 1204 sample -> 1205 new CyclingPedalingCadenceRecordInternal 1206 .CyclingPedalingCadenceRecordSample( 1207 sample.getRevolutionsPerMinute(), 1208 sample.getEpochMillis())) 1209 .collect(toSet())); 1210 } 1211 populateDistanceRecordInternal( Distance distanceProto, DistanceRecordInternal distanceRecordInternal)1212 private static void populateDistanceRecordInternal( 1213 Distance distanceProto, DistanceRecordInternal distanceRecordInternal) { 1214 distanceRecordInternal.setDistance(distanceProto.getDistance()); 1215 } 1216 populateElevationGainedRecordInternal( ElevationGained elevationGainedProto, ElevationGainedRecordInternal elevationGainedRecordInternal)1217 private static void populateElevationGainedRecordInternal( 1218 ElevationGained elevationGainedProto, 1219 ElevationGainedRecordInternal elevationGainedRecordInternal) { 1220 elevationGainedRecordInternal.setElevation(elevationGainedProto.getElevation()); 1221 } 1222 populateExerciseSessionRecordInternal( ExerciseSession exerciseSessionProto, ExerciseSessionRecordInternal exerciseSessionRecordInternal)1223 private static void populateExerciseSessionRecordInternal( 1224 ExerciseSession exerciseSessionProto, 1225 ExerciseSessionRecordInternal exerciseSessionRecordInternal) { 1226 if (exerciseSessionProto.hasNotes()) { 1227 exerciseSessionRecordInternal.setNotes(exerciseSessionProto.getNotes()); 1228 } 1229 exerciseSessionRecordInternal.setExerciseType(exerciseSessionProto.getExerciseType()); 1230 if (exerciseSessionProto.hasTitle()) { 1231 exerciseSessionRecordInternal.setTitle(exerciseSessionProto.getTitle()); 1232 } 1233 exerciseSessionRecordInternal.setHasRoute(exerciseSessionProto.getHasRoute()); 1234 if (exerciseSessionProto.hasRoute()) { 1235 List<LocationInternal> locations = 1236 exerciseSessionProto.getRoute().getRouteLocationList().stream() 1237 .map( 1238 location -> 1239 new LocationInternal() 1240 .setTime(location.getTime()) 1241 .setLatitude(location.getLatitude()) 1242 .setLongitude(location.getLongitude()) 1243 .setHorizontalAccuracy( 1244 location.getHorizontalAccuracy()) 1245 .setVerticalAccuracy( 1246 location.getVerticalAccuracy()) 1247 .setAltitude(location.getAltitude())) 1248 .toList(); 1249 exerciseSessionRecordInternal.setRoute(new ExerciseRouteInternal(locations)); 1250 } 1251 exerciseSessionRecordInternal.setExerciseLaps( 1252 exerciseSessionProto.getLapList().stream() 1253 .map( 1254 lap -> 1255 new ExerciseLapInternal() 1256 .setStartTime(lap.getStartTime()) 1257 .setEndTime(lap.getEndTime()) 1258 .setLength(lap.getLength())) 1259 .toList()); 1260 exerciseSessionRecordInternal.setExerciseSegments( 1261 exerciseSessionProto.getSegmentList().stream() 1262 .map( 1263 segment -> 1264 new ExerciseSegmentInternal() 1265 .setStartTime(segment.getStartTime()) 1266 .setEndTime(segment.getEndTime()) 1267 .setSegmentType(segment.getSegmentType()) 1268 .setRepetitionsCount(segment.getRepetitionsCount())) 1269 .toList()); 1270 if (exerciseSessionProto.hasPlannedExerciseSessionId()) { 1271 exerciseSessionRecordInternal.setPlannedExerciseSessionId( 1272 UUID.fromString(exerciseSessionProto.getPlannedExerciseSessionId())); 1273 } 1274 } 1275 populateFloorsClimbedRecordInternal( FloorsClimbed floorsClimbedProto, FloorsClimbedRecordInternal floorsClimbedRecordInternal)1276 private static void populateFloorsClimbedRecordInternal( 1277 FloorsClimbed floorsClimbedProto, 1278 FloorsClimbedRecordInternal floorsClimbedRecordInternal) { 1279 floorsClimbedRecordInternal.setFloors(floorsClimbedProto.getFloors()); 1280 } 1281 populateHeartRateRecordInternal( HeartRate heartRateProto, HeartRateRecordInternal heartRateRecordInternal)1282 private static void populateHeartRateRecordInternal( 1283 HeartRate heartRateProto, HeartRateRecordInternal heartRateRecordInternal) { 1284 heartRateRecordInternal.setSamples( 1285 heartRateProto.getSampleList().stream() 1286 .map( 1287 sample -> 1288 new HeartRateRecordInternal.HeartRateSample( 1289 sample.getBeatsPerMinute(), 1290 sample.getEpochMillis())) 1291 .collect(toSet())); 1292 } 1293 populateHydrationRecordInternal( Hydration hydrationProto, HydrationRecordInternal hydrationRecordInternal)1294 private static void populateHydrationRecordInternal( 1295 Hydration hydrationProto, HydrationRecordInternal hydrationRecordInternal) { 1296 hydrationRecordInternal.setVolume(hydrationProto.getVolume()); 1297 } 1298 populateMindfulnessSessionRecordInternal( MindfulnessSession mindfulnessSessionProto, MindfulnessSessionRecordInternal mindfulnessSessionRecordInternal)1299 private static void populateMindfulnessSessionRecordInternal( 1300 MindfulnessSession mindfulnessSessionProto, 1301 MindfulnessSessionRecordInternal mindfulnessSessionRecordInternal) { 1302 mindfulnessSessionRecordInternal.setMindfulnessSessionType( 1303 mindfulnessSessionProto.getMindfulnessSessionType()); 1304 if (mindfulnessSessionProto.hasTitle()) { 1305 mindfulnessSessionRecordInternal.setTitle(mindfulnessSessionProto.getTitle()); 1306 } 1307 if (mindfulnessSessionProto.hasNotes()) { 1308 mindfulnessSessionRecordInternal.setNotes(mindfulnessSessionProto.getNotes()); 1309 } 1310 } 1311 populateNutritionRecordInternal( Nutrition nutritionProto, NutritionRecordInternal nutritionRecordInternal)1312 private static void populateNutritionRecordInternal( 1313 Nutrition nutritionProto, NutritionRecordInternal nutritionRecordInternal) { 1314 nutritionRecordInternal 1315 .setUnsaturatedFat(nutritionProto.getUnsaturatedFat()) 1316 .setPotassium(nutritionProto.getPotassium()) 1317 .setThiamin(nutritionProto.getThiamin()) 1318 .setMealType(nutritionProto.getMealType()) 1319 .setTransFat(nutritionProto.getTransFat()) 1320 .setManganese(nutritionProto.getManganese()) 1321 .setEnergyFromFat(nutritionProto.getEnergyFromFat()) 1322 .setCaffeine(nutritionProto.getCaffeine()) 1323 .setDietaryFiber(nutritionProto.getDietaryFiber()) 1324 .setSelenium(nutritionProto.getSelenium()) 1325 .setVitaminB6(nutritionProto.getVitaminB6()) 1326 .setProtein(nutritionProto.getProtein()) 1327 .setChloride(nutritionProto.getChloride()) 1328 .setCholesterol(nutritionProto.getCholesterol()) 1329 .setCopper(nutritionProto.getCopper()) 1330 .setIodine(nutritionProto.getIodine()) 1331 .setVitaminB12(nutritionProto.getVitaminB12()) 1332 .setZinc(nutritionProto.getZinc()) 1333 .setRiboflavin(nutritionProto.getRiboflavin()) 1334 .setEnergy(nutritionProto.getEnergy()) 1335 .setMolybdenum(nutritionProto.getMolybdenum()) 1336 .setPhosphorus(nutritionProto.getPhosphorus()) 1337 .setChromium(nutritionProto.getChromium()) 1338 .setTotalFat(nutritionProto.getTotalFat()) 1339 .setCalcium(nutritionProto.getCalcium()) 1340 .setVitaminC(nutritionProto.getVitaminC()) 1341 .setVitaminE(nutritionProto.getVitaminE()) 1342 .setBiotin(nutritionProto.getBiotin()) 1343 .setVitaminD(nutritionProto.getVitaminD()) 1344 .setNiacin(nutritionProto.getNiacin()) 1345 .setMagnesium(nutritionProto.getMagnesium()) 1346 .setTotalCarbohydrate(nutritionProto.getTotalCarbohydrate()) 1347 .setVitaminK(nutritionProto.getVitaminK()) 1348 .setPolyunsaturatedFat(nutritionProto.getPolyunsaturatedFat()) 1349 .setSaturatedFat(nutritionProto.getSaturatedFat()) 1350 .setSodium(nutritionProto.getSodium()) 1351 .setFolate(nutritionProto.getFolate()) 1352 .setMonounsaturatedFat(nutritionProto.getMonounsaturatedFat()) 1353 .setPantothenicAcid(nutritionProto.getPantothenicAcid()) 1354 .setIron(nutritionProto.getIron()) 1355 .setVitaminA(nutritionProto.getVitaminA()) 1356 .setFolicAcid(nutritionProto.getFolicAcid()) 1357 .setSugar(nutritionProto.getSugar()); 1358 1359 if (nutritionProto.hasMealName()) { 1360 nutritionRecordInternal.setMealName(nutritionProto.getMealName()); 1361 } 1362 } 1363 populatePlannedExerciseSessionRecordInternal( PlannedExerciseSession plannedExerciseSessionProto, PlannedExerciseSessionRecordInternal plannedExerciseSessionRecordInternal)1364 private static void populatePlannedExerciseSessionRecordInternal( 1365 PlannedExerciseSession plannedExerciseSessionProto, 1366 PlannedExerciseSessionRecordInternal plannedExerciseSessionRecordInternal) { 1367 if (plannedExerciseSessionProto.hasNotes()) { 1368 plannedExerciseSessionRecordInternal.setNotes(plannedExerciseSessionProto.getNotes()); 1369 } 1370 plannedExerciseSessionRecordInternal.setExerciseType( 1371 plannedExerciseSessionProto.getExerciseType()); 1372 if (plannedExerciseSessionProto.hasTitle()) { 1373 plannedExerciseSessionRecordInternal.setTitle(plannedExerciseSessionProto.getTitle()); 1374 } 1375 plannedExerciseSessionRecordInternal.setHasExplicitTime( 1376 plannedExerciseSessionProto.getHasExplicitTime()); 1377 plannedExerciseSessionRecordInternal.setExerciseBlocks( 1378 plannedExerciseSessionProto.getExerciseBlockList().stream() 1379 .map(RecordProtoConverter::convertToPlannedExerciseBlockInternal) 1380 .toList()); 1381 } 1382 convertToPlannedExerciseBlockInternal( PlannedExerciseBlock plannedExerciseBlockProto)1383 private static PlannedExerciseBlockInternal convertToPlannedExerciseBlockInternal( 1384 PlannedExerciseBlock plannedExerciseBlockProto) { 1385 var plannedExerciseBlockInternal = 1386 new PlannedExerciseBlockInternal(plannedExerciseBlockProto.getRepetitions()); 1387 1388 if (plannedExerciseBlockProto.hasDescription()) { 1389 plannedExerciseBlockInternal.setDescription(plannedExerciseBlockProto.getDescription()); 1390 } 1391 plannedExerciseBlockInternal.setExerciseSteps( 1392 plannedExerciseBlockProto.getStepList().stream() 1393 .map(RecordProtoConverter::convertToPlannedExerciseStepInternal) 1394 .toList()); 1395 1396 return plannedExerciseBlockInternal; 1397 } 1398 convertToPlannedExerciseStepInternal( PlannedExerciseStep plannedExerciseStepProto)1399 private static PlannedExerciseStepInternal convertToPlannedExerciseStepInternal( 1400 PlannedExerciseStep plannedExerciseStepProto) { 1401 var plannedExerciseStepInternal = 1402 new PlannedExerciseStepInternal( 1403 plannedExerciseStepProto.getExerciseType(), 1404 plannedExerciseStepProto.getExerciseCategory(), 1405 convertToExerciseCompletionGoalInternal( 1406 plannedExerciseStepProto.getCompletionGoal())); 1407 1408 if (plannedExerciseStepProto.hasDescription()) { 1409 plannedExerciseStepInternal.setDescription(plannedExerciseStepProto.getDescription()); 1410 } 1411 plannedExerciseStepInternal.setPerformanceGoals( 1412 plannedExerciseStepProto.getPerformanceGoalList().stream() 1413 .map(RecordProtoConverter::convertToExercisePerformanceGoalInternal) 1414 .toList()); 1415 1416 return plannedExerciseStepInternal; 1417 } 1418 convertToExerciseCompletionGoalInternal( ExerciseCompletionGoal exerciseCompletionGoalProto)1419 private static ExerciseCompletionGoalInternal convertToExerciseCompletionGoalInternal( 1420 ExerciseCompletionGoal exerciseCompletionGoalProto) { 1421 return switch (exerciseCompletionGoalProto.getGoalCase()) { 1422 case DISTANCE_GOAL -> 1423 new ExerciseCompletionGoalInternal.DistanceGoalInternal( 1424 Length.fromMeters( 1425 exerciseCompletionGoalProto.getDistanceGoal().getDistance())); 1426 case STEPS_GOAL -> 1427 new ExerciseCompletionGoalInternal.StepsGoalInternal( 1428 exerciseCompletionGoalProto.getStepsGoal().getSteps()); 1429 case DURATION_GOAL -> 1430 new ExerciseCompletionGoalInternal.DurationGoalInternal( 1431 Duration.ofMillis( 1432 exerciseCompletionGoalProto.getDurationGoal().getDuration())); 1433 case REPETITIONS_GOAL -> 1434 new ExerciseCompletionGoalInternal.RepetitionsGoalInternal( 1435 exerciseCompletionGoalProto.getRepetitionsGoal().getRepetitions()); 1436 case TOTAL_CALORIES_BURNED_GOAL -> 1437 new ExerciseCompletionGoalInternal.TotalCaloriesBurnedGoalInternal( 1438 Energy.fromCalories( 1439 exerciseCompletionGoalProto 1440 .getTotalCaloriesBurnedGoal() 1441 .getTotalCalories())); 1442 case ACTIVE_CALORIES_BURNED_GOAL -> 1443 new ExerciseCompletionGoalInternal.ActiveCaloriesBurnedGoalInternal( 1444 Energy.fromCalories( 1445 exerciseCompletionGoalProto 1446 .getActiveCaloriesBurnedGoal() 1447 .getActiveCalories())); 1448 case DISTANCE_WITH_VARIABLE_REST_GOAL -> 1449 new ExerciseCompletionGoalInternal.DistanceWithVariableRestGoalInternal( 1450 Length.fromMeters( 1451 exerciseCompletionGoalProto 1452 .getDistanceWithVariableRestGoal() 1453 .getDistance()), 1454 Duration.ofMillis( 1455 exerciseCompletionGoalProto 1456 .getDistanceWithVariableRestGoal() 1457 .getDuration())); 1458 case UNSPECIFIED_GOAL -> 1459 ExerciseCompletionGoalInternal.UnspecifiedGoalInternal.INSTANCE; 1460 case UNKNOWN_GOAL, GOAL_NOT_SET -> 1461 ExerciseCompletionGoalInternal.UnknownGoalInternal.INSTANCE; 1462 }; 1463 } 1464 convertToExercisePerformanceGoalInternal( ExercisePerformanceGoal exercisePerformanceGoalProto)1465 private static ExercisePerformanceGoalInternal convertToExercisePerformanceGoalInternal( 1466 ExercisePerformanceGoal exercisePerformanceGoalProto) { 1467 return switch (exercisePerformanceGoalProto.getGoalCase()) { 1468 case POWER_GOAL -> 1469 new ExercisePerformanceGoalInternal.PowerGoalInternal( 1470 Power.fromWatts( 1471 exercisePerformanceGoalProto.getPowerGoal().getMinPower()), 1472 Power.fromWatts( 1473 exercisePerformanceGoalProto.getPowerGoal().getMaxPower())); 1474 case SPEED_GOAL -> 1475 new ExercisePerformanceGoalInternal.SpeedGoalInternal( 1476 Velocity.fromMetersPerSecond( 1477 exercisePerformanceGoalProto.getSpeedGoal().getMinSpeed()), 1478 Velocity.fromMetersPerSecond( 1479 exercisePerformanceGoalProto.getSpeedGoal().getMaxSpeed())); 1480 case CADENCE_GOAL -> 1481 new ExercisePerformanceGoalInternal.CadenceGoalInternal( 1482 exercisePerformanceGoalProto.getCadenceGoal().getMinRpm(), 1483 exercisePerformanceGoalProto.getCadenceGoal().getMaxRpm()); 1484 case HEART_RATE_GOAL -> 1485 new ExercisePerformanceGoalInternal.HeartRateGoalInternal( 1486 exercisePerformanceGoalProto.getHeartRateGoal().getMinBpm(), 1487 exercisePerformanceGoalProto.getHeartRateGoal().getMaxBpm()); 1488 case WEIGHT_GOAL -> 1489 new ExercisePerformanceGoalInternal.WeightGoalInternal( 1490 Mass.fromGrams(exercisePerformanceGoalProto.getWeightGoal().getMass())); 1491 case RATE_OF_PERCEIVED_EXERTION_GOAL -> 1492 new ExercisePerformanceGoalInternal.RateOfPerceivedExertionGoalInternal( 1493 exercisePerformanceGoalProto.getRateOfPerceivedExertionGoal().getRpe()); 1494 case AMRAP_GOAL -> ExercisePerformanceGoalInternal.AmrapGoalInternal.INSTANCE; 1495 case UNKNOWN_GOAL, GOAL_NOT_SET -> 1496 ExercisePerformanceGoalInternal.UnknownGoalInternal.INSTANCE; 1497 }; 1498 } 1499 1500 private static void populatePowerRecordInternal( 1501 com.android.server.healthconnect.proto.backuprestore.Power powerProto, 1502 PowerRecordInternal powerRecordInternal) { 1503 powerRecordInternal.setSamples( 1504 powerProto.getSampleList().stream() 1505 .map( 1506 sample -> 1507 new PowerRecordInternal.PowerRecordSample( 1508 sample.getPower(), sample.getEpochMillis())) 1509 .collect(toSet())); 1510 } 1511 1512 private static void populateSkinTemperatureRecordInternal( 1513 SkinTemperature skinTemperatureProto, 1514 SkinTemperatureRecordInternal skinTemperatureRecordInternal) { 1515 skinTemperatureRecordInternal 1516 .setMeasurementLocation(skinTemperatureProto.getMeasurementLocation()) 1517 .setBaseline(fromCelsius(skinTemperatureProto.getBaseline())) 1518 .setSamples( 1519 skinTemperatureProto.getSampleList().stream() 1520 .map( 1521 sample -> 1522 new SkinTemperatureRecordInternal 1523 .SkinTemperatureDeltaSample( 1524 sample.getTemperatureDeltaInCelsius(), 1525 sample.getEpochMillis())) 1526 .collect(toSet())); 1527 } 1528 1529 @SuppressLint("WrongConstant") 1530 private static void populateSleepSessionRecordInternal( 1531 SleepSession sleepSessionProto, SleepSessionRecordInternal sleepSessionRecordInternal) { 1532 if (sleepSessionProto.hasNotes()) { 1533 sleepSessionRecordInternal.setNotes(sleepSessionProto.getNotes()); 1534 } 1535 if (sleepSessionProto.hasTitle()) { 1536 sleepSessionRecordInternal.setTitle(sleepSessionProto.getTitle()); 1537 } 1538 if (sleepSessionProto.getStageCount() > 0) { 1539 sleepSessionRecordInternal.setSleepStages( 1540 sleepSessionProto.getStageList().stream() 1541 .map( 1542 sleepStage -> 1543 new SleepStageInternal() 1544 .setStartTime(sleepStage.getStartTime()) 1545 .setEndTime(sleepStage.getEndTime()) 1546 .setStageType(sleepStage.getStageType())) 1547 .toList()); 1548 } 1549 } 1550 1551 private static void populateSpeedRecordInternal( 1552 Speed speedProto, SpeedRecordInternal speedRecordInternal) { 1553 speedRecordInternal.setSamples( 1554 speedProto.getSampleList().stream() 1555 .map( 1556 sample -> 1557 new SpeedRecordInternal.SpeedRecordSample( 1558 sample.getSpeed(), sample.getEpochMillis())) 1559 .collect(toSet())); 1560 } 1561 1562 private static void populateStepsRecordInternal( 1563 Steps stepsProto, StepsRecordInternal stepsRecordInternal) { 1564 stepsRecordInternal.setCount(stepsProto.getCount()); 1565 } 1566 1567 private static void populateTotalCaloriesBurnedRecordInternal( 1568 TotalCaloriesBurned totalCaloriesBurnedProto, 1569 TotalCaloriesBurnedRecordInternal totalCaloriesBurnedRecordInternal) { 1570 totalCaloriesBurnedRecordInternal.setEnergy(totalCaloriesBurnedProto.getEnergy()); 1571 } 1572 1573 private static void populateStepsCadenceRecordInternal( 1574 StepsCadence stepsCadenceProto, StepsCadenceRecordInternal stepsCadenceRecordInternal) { 1575 stepsCadenceRecordInternal.setSamples( 1576 stepsCadenceProto.getSampleList().stream() 1577 .map( 1578 sample -> 1579 new StepsCadenceRecordInternal.StepsCadenceRecordSample( 1580 sample.getRate(), sample.getEpochMillis())) 1581 .collect(toSet())); 1582 } 1583 1584 private static void populateWheelchairPushesRecordInternal( 1585 WheelchairPushes wheelchairPushesProto, 1586 WheelchairPushesRecordInternal wheelchairPushesRecordInternal) { 1587 wheelchairPushesRecordInternal.setCount(wheelchairPushesProto.getCount()); 1588 } 1589 1590 private static void populateInstantRecordInternal( 1591 InstantRecord instantRecordProto, InstantRecordInternal<?> instantRecordInternal) { 1592 instantRecordInternal 1593 .setTime(instantRecordProto.getTime()) 1594 .setZoneOffset(instantRecordProto.getZoneOffset()); 1595 1596 switch (instantRecordProto.getDataCase()) { 1597 case BASAL_BODY_TEMPERATURE -> 1598 populateBasalBodyTemperatureRecordInternal( 1599 instantRecordProto.getBasalBodyTemperature(), 1600 (BasalBodyTemperatureRecordInternal) instantRecordInternal); 1601 case BASAL_METABOLIC_RATE -> 1602 populateBasalMetabolicRateRecordInternal( 1603 instantRecordProto.getBasalMetabolicRate(), 1604 (BasalMetabolicRateRecordInternal) instantRecordInternal); 1605 case BLOOD_GLUCOSE -> 1606 populateBloodGlucoseRecordInternal( 1607 instantRecordProto.getBloodGlucose(), 1608 (BloodGlucoseRecordInternal) instantRecordInternal); 1609 case BLOOD_PRESSURE -> 1610 populateBloodPressureRecordInternal( 1611 instantRecordProto.getBloodPressure(), 1612 (BloodPressureRecordInternal) instantRecordInternal); 1613 case BODY_FAT -> 1614 populateBodyFatRecordInternal( 1615 instantRecordProto.getBodyFat(), 1616 (BodyFatRecordInternal) instantRecordInternal); 1617 case BODY_TEMPERATURE -> 1618 populateBodyTemperatureRecordInternal( 1619 instantRecordProto.getBodyTemperature(), 1620 (BodyTemperatureRecordInternal) instantRecordInternal); 1621 case BODY_WATER_MASS -> 1622 populateBodyWaterMassRecordInternal( 1623 instantRecordProto.getBodyWaterMass(), 1624 (BodyWaterMassRecordInternal) instantRecordInternal); 1625 case BONE_MASS -> 1626 populateBoneMassRecordInternal( 1627 instantRecordProto.getBoneMass(), 1628 (BoneMassRecordInternal) instantRecordInternal); 1629 case CERVICAL_MUCUS -> 1630 populateCervicalMucusRecordInternal( 1631 instantRecordProto.getCervicalMucus(), 1632 (CervicalMucusRecordInternal) instantRecordInternal); 1633 case HEART_RATE_VARIABILITY_RMSSD -> 1634 populateHeartRateVariabilityRmssdRecordInternal( 1635 instantRecordProto.getHeartRateVariabilityRmssd(), 1636 (HeartRateVariabilityRmssdRecordInternal) instantRecordInternal); 1637 case HEIGHT -> 1638 populateHeightRecordInternal( 1639 instantRecordProto.getHeight(), 1640 (HeightRecordInternal) instantRecordInternal); 1641 case INTERMENSTRUAL_BLEEDING -> { 1642 // No data to populate. 1643 } 1644 case LEAN_BODY_MASS -> 1645 populateLeanBodyMassRecordInternal( 1646 instantRecordProto.getLeanBodyMass(), 1647 (LeanBodyMassRecordInternal) instantRecordInternal); 1648 case MENSTRUATION_FLOW -> 1649 populateMenstruationFlowRecordInternal( 1650 instantRecordProto.getMenstruationFlow(), 1651 (MenstruationFlowRecordInternal) instantRecordInternal); 1652 case OVULATION_TEST -> 1653 populateOvulationTestRecordInternal( 1654 instantRecordProto.getOvulationTest(), 1655 (OvulationTestRecordInternal) instantRecordInternal); 1656 case OXYGEN_SATURATION -> 1657 populateOxygenSaturationRecordInternal( 1658 instantRecordProto.getOxygenSaturation(), 1659 (OxygenSaturationRecordInternal) instantRecordInternal); 1660 case RESPIRATORY_RATE -> 1661 populateRespiratoryRateRecordInternal( 1662 instantRecordProto.getRespiratoryRate(), 1663 (RespiratoryRateRecordInternal) instantRecordInternal); 1664 case RESTING_HEART_RATE -> 1665 populateRestingHeartRateRecordInternal( 1666 instantRecordProto.getRestingHeartRate(), 1667 (RestingHeartRateRecordInternal) instantRecordInternal); 1668 case SEXUAL_ACTIVITY -> 1669 populateSexualActivityRecordInternal( 1670 instantRecordProto.getSexualActivity(), 1671 (SexualActivityRecordInternal) instantRecordInternal); 1672 case VO2_MAX -> 1673 populateVo2MaxRecordInternal( 1674 instantRecordProto.getVo2Max(), 1675 (Vo2MaxRecordInternal) instantRecordInternal); 1676 case WEIGHT -> 1677 populateWeightRecordInternal( 1678 instantRecordProto.getWeight(), 1679 (WeightRecordInternal) instantRecordInternal); 1680 default -> 1681 throw new IllegalArgumentException( 1682 "Unknown record type " + instantRecordProto.getDataCase()); 1683 } 1684 } 1685 1686 private static void populateBasalBodyTemperatureRecordInternal( 1687 BasalBodyTemperature basalBodyTemperatureProto, 1688 BasalBodyTemperatureRecordInternal basalBodyTemperatureRecordInternal) { 1689 basalBodyTemperatureRecordInternal 1690 .setTemperature(basalBodyTemperatureProto.getTemperature()) 1691 .setMeasurementLocation(basalBodyTemperatureProto.getMeasurementLocation()); 1692 } 1693 1694 private static void populateBasalMetabolicRateRecordInternal( 1695 BasalMetabolicRate basalMetabolicRateProto, 1696 BasalMetabolicRateRecordInternal basalMetabolicRateRecordInternal) { 1697 basalMetabolicRateRecordInternal.setBasalMetabolicRate( 1698 basalMetabolicRateProto.getBasalMetabolicRate()); 1699 } 1700 1701 private static void populateBloodGlucoseRecordInternal( 1702 BloodGlucose bloodGlucoseProto, BloodGlucoseRecordInternal bloodGlucoseRecordInternal) { 1703 bloodGlucoseRecordInternal 1704 .setSpecimenSource(bloodGlucoseProto.getSpecimenSource()) 1705 .setLevel(bloodGlucoseProto.getLevel()) 1706 .setRelationToMeal(bloodGlucoseProto.getRelationToMeal()) 1707 .setMealType(bloodGlucoseProto.getMealType()); 1708 } 1709 1710 private static void populateBloodPressureRecordInternal( 1711 BloodPressure bloodPressureProto, 1712 BloodPressureRecordInternal bloodPressureRecordInternal) { 1713 bloodPressureRecordInternal 1714 .setMeasurementLocation(bloodPressureProto.getMeasurementLocation()) 1715 .setSystolic(bloodPressureProto.getSystolic()) 1716 .setDiastolic(bloodPressureProto.getDiastolic()) 1717 .setBodyPosition(bloodPressureProto.getBodyPosition()); 1718 } 1719 1720 private static void populateBodyFatRecordInternal( 1721 BodyFat bodyFatProto, BodyFatRecordInternal bodyFatRecordInternal) { 1722 bodyFatRecordInternal.setPercentage(bodyFatProto.getPercentage()); 1723 } 1724 1725 private static void populateBodyTemperatureRecordInternal( 1726 BodyTemperature bodyTemperatureProto, 1727 BodyTemperatureRecordInternal bodyTemperatureRecordInternal) { 1728 bodyTemperatureRecordInternal 1729 .setTemperature(bodyTemperatureProto.getTemperature()) 1730 .setMeasurementLocation(bodyTemperatureProto.getMeasurementLocation()); 1731 } 1732 1733 private static void populateBodyWaterMassRecordInternal( 1734 BodyWaterMass bodyWaterMassProto, 1735 BodyWaterMassRecordInternal bodyWaterMassRecordInternal) { 1736 bodyWaterMassRecordInternal.setBodyWaterMass(bodyWaterMassProto.getBodyWaterMass()); 1737 } 1738 1739 private static void populateBoneMassRecordInternal( 1740 BoneMass boneMassProto, BoneMassRecordInternal boneMassRecordInternal) { 1741 boneMassRecordInternal.setMass(boneMassProto.getMass()); 1742 } 1743 1744 private static void populateCervicalMucusRecordInternal( 1745 CervicalMucus cervicalMucusProto, 1746 CervicalMucusRecordInternal cervicalMucusRecordInternal) { 1747 cervicalMucusRecordInternal 1748 .setSensation(cervicalMucusProto.getSensation()) 1749 .setAppearance(cervicalMucusProto.getAppearance()); 1750 } 1751 1752 private static void populateMenstruationFlowRecordInternal( 1753 MenstruationFlow menstruationFlowProto, 1754 MenstruationFlowRecordInternal menstruationFlowRecordInternal) { 1755 menstruationFlowRecordInternal.setFlow(menstruationFlowProto.getFlow()); 1756 } 1757 1758 private static void populateOvulationTestRecordInternal( 1759 OvulationTest ovulationTestProto, 1760 OvulationTestRecordInternal ovulationTestRecordInternal) { 1761 ovulationTestRecordInternal.setResult(ovulationTestProto.getResult()); 1762 } 1763 1764 private static void populateOxygenSaturationRecordInternal( 1765 OxygenSaturation oxygenSaturationProto, 1766 OxygenSaturationRecordInternal oxygenSaturationRecordInternal) { 1767 oxygenSaturationRecordInternal.setPercentage(oxygenSaturationProto.getPercentage()); 1768 } 1769 1770 private static void populateHeartRateVariabilityRmssdRecordInternal( 1771 HeartRateVariabilityRmssd heartRateVariabilityRmssdProto, 1772 HeartRateVariabilityRmssdRecordInternal heartRateVariabilityRmssdRecordInternal) { 1773 heartRateVariabilityRmssdRecordInternal.setHeartRateVariabilityMillis( 1774 heartRateVariabilityRmssdProto.getHeartRateVariabilityMillis()); 1775 } 1776 1777 private static void populateHeightRecordInternal( 1778 Height heightProto, HeightRecordInternal heightRecordInternal) { 1779 heightRecordInternal.setHeight(heightProto.getHeight()); 1780 } 1781 1782 private static void populateLeanBodyMassRecordInternal( 1783 LeanBodyMass leanBodyMassProto, LeanBodyMassRecordInternal leanBodyMassRecordInternal) { 1784 leanBodyMassRecordInternal.setMass(leanBodyMassProto.getMass()); 1785 } 1786 1787 private static void populateRespiratoryRateRecordInternal( 1788 RespiratoryRate respiratoryRateProto, 1789 RespiratoryRateRecordInternal respiratoryRateRecordInternal) { 1790 respiratoryRateRecordInternal.setRate(respiratoryRateProto.getRate()); 1791 } 1792 1793 private static void populateRestingHeartRateRecordInternal( 1794 RestingHeartRate restingHeartRateProto, 1795 RestingHeartRateRecordInternal restingHeartRateRecordInternal) { 1796 restingHeartRateRecordInternal.setBeatsPerMinute(restingHeartRateProto.getBeatsPerMinute()); 1797 } 1798 1799 private static void populateSexualActivityRecordInternal( 1800 SexualActivity sexualActivityProto, 1801 SexualActivityRecordInternal sexualActivityRecordInternal) { 1802 sexualActivityRecordInternal.setProtectionUsed(sexualActivityProto.getProtectionUsed()); 1803 } 1804 1805 private static void populateVo2MaxRecordInternal( 1806 Vo2Max vo2MaxProto, Vo2MaxRecordInternal vo2MaxRecordInternal) { 1807 vo2MaxRecordInternal 1808 .setMeasurementMethod(vo2MaxProto.getMeasurementMethod()) 1809 .setVo2MillilitersPerMinuteKilogram( 1810 vo2MaxProto.getVo2MillilitersPerMinuteKilogram()); 1811 } 1812 1813 private static void populateWeightRecordInternal( 1814 Weight weightProto, WeightRecordInternal weightRecordInternal) { 1815 weightRecordInternal.setWeight(weightProto.getWeight()); 1816 } 1817 1818 @RecordTypeIdentifier.RecordType 1819 int getRecordTypeId(Record protoRecord) { 1820 if (protoRecord.hasIntervalRecord()) { 1821 return getIntervalRecordId(protoRecord.getIntervalRecord()); 1822 } 1823 if (protoRecord.hasInstantRecord()) { 1824 return getInstantRecordId(protoRecord.getInstantRecord()); 1825 } 1826 throw new IllegalArgumentException("Record proto doesn't have a sub record defined."); 1827 } 1828 1829 @RecordTypeIdentifier.RecordType 1830 private int getIntervalRecordId(IntervalRecord protoRecord) { 1831 return switch (protoRecord.getDataCase()) { 1832 case ACTIVE_CALORIES_BURNED -> RecordTypeIdentifier.RECORD_TYPE_ACTIVE_CALORIES_BURNED; 1833 case ACTIVITY_INTENSITY -> RecordTypeIdentifier.RECORD_TYPE_ACTIVITY_INTENSITY; 1834 case CYCLING_PEDALING_CADENCE -> 1835 RecordTypeIdentifier.RECORD_TYPE_CYCLING_PEDALING_CADENCE; 1836 case DISTANCE -> RecordTypeIdentifier.RECORD_TYPE_DISTANCE; 1837 case ELEVATION_GAINED -> RecordTypeIdentifier.RECORD_TYPE_ELEVATION_GAINED; 1838 case EXERCISE_SESSION -> RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION; 1839 case FLOORS_CLIMBED -> RecordTypeIdentifier.RECORD_TYPE_FLOORS_CLIMBED; 1840 case HEART_RATE -> RecordTypeIdentifier.RECORD_TYPE_HEART_RATE; 1841 case HYDRATION -> RecordTypeIdentifier.RECORD_TYPE_HYDRATION; 1842 case MENSTRUATION_PERIOD -> RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_PERIOD; 1843 case MINDFULNESS_SESSION -> RecordTypeIdentifier.RECORD_TYPE_MINDFULNESS_SESSION; 1844 case NUTRITION -> RecordTypeIdentifier.RECORD_TYPE_NUTRITION; 1845 case PLANNED_EXERCISE_SESSION -> 1846 RecordTypeIdentifier.RECORD_TYPE_PLANNED_EXERCISE_SESSION; 1847 case POWER -> RecordTypeIdentifier.RECORD_TYPE_POWER; 1848 case SKIN_TEMPERATURE -> RecordTypeIdentifier.RECORD_TYPE_SKIN_TEMPERATURE; 1849 case SLEEP_SESSION -> RecordTypeIdentifier.RECORD_TYPE_SLEEP_SESSION; 1850 case SPEED -> RecordTypeIdentifier.RECORD_TYPE_SPEED; 1851 case STEPS -> RecordTypeIdentifier.RECORD_TYPE_STEPS; 1852 case STEPS_CADENCE -> RecordTypeIdentifier.RECORD_TYPE_STEPS_CADENCE; 1853 case TOTAL_CALORIES_BURNED -> RecordTypeIdentifier.RECORD_TYPE_TOTAL_CALORIES_BURNED; 1854 case WHEELCHAIR_PUSHES -> RecordTypeIdentifier.RECORD_TYPE_WHEELCHAIR_PUSHES; 1855 case DATA_NOT_SET -> throw new IllegalArgumentException("Interval record not set"); 1856 }; 1857 } 1858 1859 @RecordTypeIdentifier.RecordType 1860 private int getInstantRecordId(InstantRecord protoRecord) { 1861 return switch (protoRecord.getDataCase()) { 1862 case BASAL_BODY_TEMPERATURE -> RecordTypeIdentifier.RECORD_TYPE_BASAL_BODY_TEMPERATURE; 1863 case BASAL_METABOLIC_RATE -> RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE; 1864 case BLOOD_GLUCOSE -> RecordTypeIdentifier.RECORD_TYPE_BLOOD_GLUCOSE; 1865 case BLOOD_PRESSURE -> RecordTypeIdentifier.RECORD_TYPE_BLOOD_PRESSURE; 1866 case BODY_FAT -> RecordTypeIdentifier.RECORD_TYPE_BODY_FAT; 1867 case BODY_TEMPERATURE -> RecordTypeIdentifier.RECORD_TYPE_BODY_TEMPERATURE; 1868 case BODY_WATER_MASS -> RecordTypeIdentifier.RECORD_TYPE_BODY_WATER_MASS; 1869 case BONE_MASS -> RecordTypeIdentifier.RECORD_TYPE_BONE_MASS; 1870 case CERVICAL_MUCUS -> RecordTypeIdentifier.RECORD_TYPE_CERVICAL_MUCUS; 1871 case HEART_RATE_VARIABILITY_RMSSD -> 1872 RecordTypeIdentifier.RECORD_TYPE_HEART_RATE_VARIABILITY_RMSSD; 1873 case HEIGHT -> RecordTypeIdentifier.RECORD_TYPE_HEIGHT; 1874 case INTERMENSTRUAL_BLEEDING -> 1875 RecordTypeIdentifier.RECORD_TYPE_INTERMENSTRUAL_BLEEDING; 1876 case LEAN_BODY_MASS -> RecordTypeIdentifier.RECORD_TYPE_LEAN_BODY_MASS; 1877 case MENSTRUATION_FLOW -> RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_FLOW; 1878 case OVULATION_TEST -> RecordTypeIdentifier.RECORD_TYPE_OVULATION_TEST; 1879 case OXYGEN_SATURATION -> RecordTypeIdentifier.RECORD_TYPE_OXYGEN_SATURATION; 1880 case RESPIRATORY_RATE -> RecordTypeIdentifier.RECORD_TYPE_RESPIRATORY_RATE; 1881 case RESTING_HEART_RATE -> RecordTypeIdentifier.RECORD_TYPE_RESTING_HEART_RATE; 1882 case SEXUAL_ACTIVITY -> RecordTypeIdentifier.RECORD_TYPE_SEXUAL_ACTIVITY; 1883 case VO2_MAX -> RecordTypeIdentifier.RECORD_TYPE_VO2_MAX; 1884 case WEIGHT -> RecordTypeIdentifier.RECORD_TYPE_WEIGHT; 1885 case DATA_NOT_SET -> throw new IllegalArgumentException("Instant record not set"); 1886 }; 1887 } 1888 } 1889