1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * ```
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * ```
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.healthconnect.testapps.toolbox.utils
17 
18 import android.content.Context
19 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord
20 import android.health.connect.datatypes.ActivityIntensityRecord
21 import android.health.connect.datatypes.BasalBodyTemperatureRecord
22 import android.health.connect.datatypes.BasalMetabolicRateRecord
23 import android.health.connect.datatypes.BloodGlucoseRecord
24 import android.health.connect.datatypes.BloodPressureRecord
25 import android.health.connect.datatypes.BodyFatRecord
26 import android.health.connect.datatypes.BodyTemperatureRecord
27 import android.health.connect.datatypes.BodyWaterMassRecord
28 import android.health.connect.datatypes.BoneMassRecord
29 import android.health.connect.datatypes.CervicalMucusRecord
30 import android.health.connect.datatypes.CyclingPedalingCadenceRecord
31 import android.health.connect.datatypes.CyclingPedalingCadenceRecord.CyclingPedalingCadenceRecordSample
32 import android.health.connect.datatypes.DistanceRecord
33 import android.health.connect.datatypes.ElevationGainedRecord
34 import android.health.connect.datatypes.ExerciseLap
35 import android.health.connect.datatypes.ExerciseSegment
36 import android.health.connect.datatypes.ExerciseSessionRecord
37 import android.health.connect.datatypes.FloorsClimbedRecord
38 import android.health.connect.datatypes.HeartRateRecord
39 import android.health.connect.datatypes.HeartRateRecord.HeartRateSample
40 import android.health.connect.datatypes.HeartRateVariabilityRmssdRecord
41 import android.health.connect.datatypes.HeightRecord
42 import android.health.connect.datatypes.HydrationRecord
43 import android.health.connect.datatypes.IntermenstrualBleedingRecord
44 import android.health.connect.datatypes.LeanBodyMassRecord
45 import android.health.connect.datatypes.MenstruationFlowRecord
46 import android.health.connect.datatypes.MenstruationPeriodRecord
47 import android.health.connect.datatypes.Metadata
48 import android.health.connect.datatypes.MindfulnessSessionRecord
49 import android.health.connect.datatypes.NutritionRecord
50 import android.health.connect.datatypes.OvulationTestRecord
51 import android.health.connect.datatypes.OxygenSaturationRecord
52 import android.health.connect.datatypes.PlannedExerciseBlock
53 import android.health.connect.datatypes.PlannedExerciseSessionRecord
54 import android.health.connect.datatypes.PowerRecord
55 import android.health.connect.datatypes.PowerRecord.PowerRecordSample
56 import android.health.connect.datatypes.Record
57 import android.health.connect.datatypes.RespiratoryRateRecord
58 import android.health.connect.datatypes.RestingHeartRateRecord
59 import android.health.connect.datatypes.SexualActivityRecord
60 import android.health.connect.datatypes.SkinTemperatureRecord
61 import android.health.connect.datatypes.SleepSessionRecord
62 import android.health.connect.datatypes.SpeedRecord
63 import android.health.connect.datatypes.SpeedRecord.SpeedRecordSample
64 import android.health.connect.datatypes.StepsCadenceRecord
65 import android.health.connect.datatypes.StepsCadenceRecord.StepsCadenceRecordSample
66 import android.health.connect.datatypes.StepsRecord
67 import android.health.connect.datatypes.TotalCaloriesBurnedRecord
68 import android.health.connect.datatypes.Vo2MaxRecord
69 import android.health.connect.datatypes.WeightRecord
70 import android.health.connect.datatypes.WheelchairPushesRecord
71 import android.health.connect.datatypes.units.BloodGlucose
72 import android.health.connect.datatypes.units.Energy
73 import android.health.connect.datatypes.units.Length
74 import android.health.connect.datatypes.units.Mass
75 import android.health.connect.datatypes.units.Percentage
76 import android.health.connect.datatypes.units.Power
77 import android.health.connect.datatypes.units.Pressure
78 import android.health.connect.datatypes.units.Temperature
79 import android.health.connect.datatypes.units.Volume
80 import com.android.healthconnect.testapps.toolbox.data.ExerciseRoutesTestData
81 import com.android.healthconnect.testapps.toolbox.data.ExerciseRoutesTestData.Companion.generateExerciseRouteFromLocations
82 import com.android.healthconnect.testapps.toolbox.fieldviews.InputFieldView
83 import com.android.healthconnect.testapps.toolbox.utils.GeneralUtils.Companion.getMetaData
84 import java.time.Instant
85 import kotlin.reflect.KClass
86 
87 class InsertOrUpdateRecords {
88 
89     companion object {
90 
getStringValuenull91         private fun getStringValue(
92             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
93             fieldName: String,
94         ): String {
95             return mFieldNameToFieldInput[fieldName]?.getFieldValue().toString()
96         }
97 
getIntegerValuenull98         private fun getIntegerValue(
99             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
100             fieldName: String,
101         ): Int {
102             return getStringValue(mFieldNameToFieldInput, fieldName).toInt()
103         }
104 
getLongValuenull105         private fun getLongValue(
106             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
107             fieldName: String,
108         ): Long {
109             return getStringValue(mFieldNameToFieldInput, fieldName).toLong()
110         }
111 
getDoubleValuenull112         private fun getDoubleValue(
113             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
114             fieldName: String,
115         ): Double {
116             return getStringValue(mFieldNameToFieldInput, fieldName).toDouble()
117         }
118 
getStartTimenull119         private fun getStartTime(mFieldNameToFieldInput: HashMap<String, InputFieldView>): Instant {
120             return mFieldNameToFieldInput["startTime"]?.getFieldValue() as Instant
121         }
122 
getEndTimenull123         private fun getEndTime(mFieldNameToFieldInput: HashMap<String, InputFieldView>): Instant {
124             return mFieldNameToFieldInput["endTime"]?.getFieldValue() as Instant
125         }
126 
getTimenull127         private fun getTime(mFieldNameToFieldInput: HashMap<String, InputFieldView>): Instant {
128             return mFieldNameToFieldInput["time"]?.getFieldValue() as Instant
129         }
130 
getMassnull131         private fun getMass(
132             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
133             fieldName: String,
134         ): Mass {
135             return Mass.fromGrams(getDoubleValue(mFieldNameToFieldInput, fieldName))
136         }
137 
getTemperaturenull138         private fun getTemperature(
139             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
140             fieldName: String,
141         ): Temperature {
142             return Temperature.fromCelsius(getDoubleValue(mFieldNameToFieldInput, fieldName))
143         }
144 
createRecordObjectnull145         fun createRecordObject(
146             recordClass: KClass<out Record>,
147             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
148             context: Context,
149             recordUuid: String,
150         ): Record {
151             return createRecordObjectHelper(
152                 recordClass,
153                 mFieldNameToFieldInput,
154                 getMetaData(context, recordUuid),
155             )
156         }
157 
createRecordObjectnull158         fun createRecordObject(
159             recordClass: KClass<out Record>,
160             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
161             context: Context,
162         ): Record {
163             return createRecordObjectHelper(
164                 recordClass,
165                 mFieldNameToFieldInput,
166                 getMetaData(context),
167             )
168         }
169 
createRecordObjectHelpernull170         private fun createRecordObjectHelper(
171             recordClass: KClass<out Record>,
172             mFieldNameToFieldInput: HashMap<String, InputFieldView>,
173             metaData: Metadata,
174         ): Record {
175             return when (recordClass) {
176                 StepsRecord::class ->
177                     StepsRecord.Builder(
178                         metaData,
179                         getStartTime(mFieldNameToFieldInput),
180                         getEndTime(mFieldNameToFieldInput),
181                         getLongValue(mFieldNameToFieldInput, "mCount"),
182                     )
183                         .build()
184 
185                 DistanceRecord::class ->
186                     DistanceRecord.Builder(
187                         metaData,
188                         getStartTime(mFieldNameToFieldInput),
189                         getEndTime(mFieldNameToFieldInput),
190                         Length.fromMeters(getDoubleValue(mFieldNameToFieldInput, "mDistance")),
191                     )
192                         .build()
193 
194                 ActiveCaloriesBurnedRecord::class ->
195                     ActiveCaloriesBurnedRecord.Builder(
196                         metaData,
197                         getStartTime(mFieldNameToFieldInput),
198                         getEndTime(mFieldNameToFieldInput),
199                         Energy.fromCalories(getDoubleValue(mFieldNameToFieldInput, "mEnergy")),
200                     )
201                         .build()
202 
203                 ElevationGainedRecord::class ->
204                     ElevationGainedRecord.Builder(
205                         metaData,
206                         getStartTime(mFieldNameToFieldInput),
207                         getEndTime(mFieldNameToFieldInput),
208                         Length.fromMeters(getDoubleValue(mFieldNameToFieldInput, "mElevation")),
209                     )
210                         .build()
211 
212                 BasalMetabolicRateRecord::class ->
213                     BasalMetabolicRateRecord.Builder(
214                         metaData,
215                         getTime(mFieldNameToFieldInput),
216                         Power.fromWatts(
217                             getDoubleValue(mFieldNameToFieldInput, "mBasalMetabolicRate")
218                         ),
219                     )
220                         .build()
221 
222                 SpeedRecord::class ->
223                     SpeedRecord.Builder(
224                         metaData,
225                         getStartTime(mFieldNameToFieldInput),
226                         getEndTime(mFieldNameToFieldInput),
227                         mFieldNameToFieldInput["mSpeedRecordSamples"]?.getFieldValue()
228                                 as List<SpeedRecordSample>,
229                     )
230                         .build()
231 
232                 HeartRateRecord::class ->
233                     HeartRateRecord.Builder(
234                         metaData,
235                         getStartTime(mFieldNameToFieldInput),
236                         getEndTime(mFieldNameToFieldInput),
237                         mFieldNameToFieldInput["mHeartRateSamples"]?.getFieldValue()
238                                 as List<HeartRateSample>,
239                     )
240                         .build()
241 
242                 PowerRecord::class ->
243                     PowerRecord.Builder(
244                         metaData,
245                         getStartTime(mFieldNameToFieldInput),
246                         getEndTime(mFieldNameToFieldInput),
247                         mFieldNameToFieldInput["mPowerRecordSamples"]?.getFieldValue()
248                                 as List<PowerRecordSample>,
249                     )
250                         .build()
251 
252                 CyclingPedalingCadenceRecord::class ->
253                     CyclingPedalingCadenceRecord.Builder(
254                         metaData,
255                         getStartTime(mFieldNameToFieldInput),
256                         getEndTime(mFieldNameToFieldInput),
257                         mFieldNameToFieldInput["mCyclingPedalingCadenceRecordSamples"]
258                             ?.getFieldValue() as List<CyclingPedalingCadenceRecordSample>,
259                     )
260                         .build()
261 
262                 FloorsClimbedRecord::class ->
263                     FloorsClimbedRecord.Builder(
264                         metaData,
265                         getStartTime(mFieldNameToFieldInput),
266                         getEndTime(mFieldNameToFieldInput),
267                         getDoubleValue(mFieldNameToFieldInput, "mFloors"),
268                     )
269                         .build()
270 
271                 TotalCaloriesBurnedRecord::class ->
272                     TotalCaloriesBurnedRecord.Builder(
273                         metaData,
274                         getStartTime(mFieldNameToFieldInput),
275                         getEndTime(mFieldNameToFieldInput),
276                         Energy.fromCalories(getDoubleValue(mFieldNameToFieldInput, "mEnergy")),
277                     )
278                         .build()
279 
280                 WheelchairPushesRecord::class ->
281                     WheelchairPushesRecord.Builder(
282                         metaData,
283                         getStartTime(mFieldNameToFieldInput),
284                         getEndTime(mFieldNameToFieldInput),
285                         getLongValue(mFieldNameToFieldInput, "mCount"),
286                     )
287                         .build()
288 
289                 Vo2MaxRecord::class ->
290                     Vo2MaxRecord.Builder(
291                         metaData,
292                         getTime(mFieldNameToFieldInput),
293                         getIntegerValue(mFieldNameToFieldInput, "mMeasurementMethod"),
294                         getDoubleValue(
295                             mFieldNameToFieldInput,
296                             "mVo2MillilitersPerMinuteKilogram",
297                         ),
298                     )
299                         .build()
300 
301                 BodyFatRecord::class ->
302                     BodyFatRecord.Builder(
303                         metaData,
304                         getTime(mFieldNameToFieldInput),
305                         Percentage.fromValue(
306                             getDoubleValue(mFieldNameToFieldInput, "mPercentage")
307                         ),
308                     )
309                         .build()
310 
311                 BodyWaterMassRecord::class ->
312                     BodyWaterMassRecord.Builder(
313                         metaData,
314                         getTime(mFieldNameToFieldInput),
315                         getMass(mFieldNameToFieldInput, "mBodyWaterMass"),
316                     )
317                         .build()
318 
319                 BoneMassRecord::class ->
320                     BoneMassRecord.Builder(
321                         metaData,
322                         getTime(mFieldNameToFieldInput),
323                         getMass(mFieldNameToFieldInput, "mMass"),
324                     )
325                         .build()
326 
327                 HeightRecord::class ->
328                     HeightRecord.Builder(
329                         metaData,
330                         getTime(mFieldNameToFieldInput),
331                         Length.fromMeters(getDoubleValue(mFieldNameToFieldInput, "mHeight")),
332                     )
333                         .build()
334 
335                 LeanBodyMassRecord::class ->
336                     LeanBodyMassRecord.Builder(
337                         metaData,
338                         getTime(mFieldNameToFieldInput),
339                         getMass(mFieldNameToFieldInput, "mMass"),
340                     )
341                         .build()
342 
343                 WeightRecord::class ->
344                     WeightRecord.Builder(
345                         metaData,
346                         getTime(mFieldNameToFieldInput),
347                         getMass(mFieldNameToFieldInput, "mWeight"),
348                     )
349                         .build()
350 
351                 CervicalMucusRecord::class ->
352                     CervicalMucusRecord.Builder(
353                         metaData,
354                         getTime(mFieldNameToFieldInput),
355                         getIntegerValue(mFieldNameToFieldInput, "mSensation"),
356                         getIntegerValue(mFieldNameToFieldInput, "mAppearance"),
357                     )
358                         .build()
359 
360                 MenstruationFlowRecord::class ->
361                     MenstruationFlowRecord.Builder(
362                         metaData,
363                         getTime(mFieldNameToFieldInput),
364                         getIntegerValue(mFieldNameToFieldInput, "mFlow"),
365                     )
366                         .build()
367 
368                 OvulationTestRecord::class ->
369                     OvulationTestRecord.Builder(
370                         metaData,
371                         getTime(mFieldNameToFieldInput),
372                         getIntegerValue(mFieldNameToFieldInput, "mResult"),
373                     )
374                         .build()
375 
376                 SexualActivityRecord::class ->
377                     SexualActivityRecord.Builder(
378                         metaData,
379                         getTime(mFieldNameToFieldInput),
380                         getIntegerValue(mFieldNameToFieldInput, "mProtectionUsed"),
381                     )
382                         .build()
383 
384                 HydrationRecord::class ->
385                     HydrationRecord.Builder(
386                         metaData,
387                         getStartTime(mFieldNameToFieldInput),
388                         getEndTime(mFieldNameToFieldInput),
389                         Volume.fromLiters(getDoubleValue(mFieldNameToFieldInput, "mVolume")),
390                     )
391                         .build()
392 
393                 IntermenstrualBleedingRecord::class ->
394                     IntermenstrualBleedingRecord.Builder(metaData, getTime(mFieldNameToFieldInput))
395                         .build()
396 
397                 BasalBodyTemperatureRecord::class ->
398                     BasalBodyTemperatureRecord.Builder(
399                         metaData,
400                         getTime(mFieldNameToFieldInput),
401                         getIntegerValue(
402                             mFieldNameToFieldInput,
403                             "mBodyTemperatureMeasurementLocation",
404                         ),
405                         Temperature.fromCelsius(
406                             getDoubleValue(mFieldNameToFieldInput, "mTemperature")
407                         ),
408                     )
409                         .build()
410 
411                 BloodGlucoseRecord::class ->
412                     BloodGlucoseRecord.Builder(
413                         metaData,
414                         getTime(mFieldNameToFieldInput),
415                         getIntegerValue(mFieldNameToFieldInput, "mSpecimenSource"),
416                         BloodGlucose.fromMillimolesPerLiter(
417                             getDoubleValue(mFieldNameToFieldInput, "mLevel")
418                         ),
419                         getIntegerValue(mFieldNameToFieldInput, "mRelationToMeal"),
420                         getIntegerValue(mFieldNameToFieldInput, "mMealType"),
421                     )
422                         .build()
423 
424                 BloodPressureRecord::class ->
425                     BloodPressureRecord.Builder(
426                         metaData,
427                         getTime(mFieldNameToFieldInput),
428                         getIntegerValue(mFieldNameToFieldInput, "mMeasurementLocation"),
429                         Pressure.fromMillimetersOfMercury(
430                             getDoubleValue(mFieldNameToFieldInput, "mSystolic")
431                         ),
432                         Pressure.fromMillimetersOfMercury(
433                             getDoubleValue(mFieldNameToFieldInput, "mDiastolic")
434                         ),
435                         getIntegerValue(mFieldNameToFieldInput, "mBodyPosition"),
436                     )
437                         .build()
438 
439                 BodyTemperatureRecord::class ->
440                     BodyTemperatureRecord.Builder(
441                         metaData,
442                         getTime(mFieldNameToFieldInput),
443                         getIntegerValue(mFieldNameToFieldInput, "mMeasurementLocation"),
444                         Temperature.fromCelsius(
445                             getDoubleValue(mFieldNameToFieldInput, "mTemperature")
446                         ),
447                     )
448                         .build()
449 
450                 HeartRateVariabilityRmssdRecord::class ->
451                     HeartRateVariabilityRmssdRecord.Builder(
452                         metaData,
453                         getTime(mFieldNameToFieldInput),
454                         getDoubleValue(mFieldNameToFieldInput, "mHeartRateVariabilityMillis"),
455                     )
456                         .build()
457 
458                 OxygenSaturationRecord::class ->
459                     OxygenSaturationRecord.Builder(
460                         metaData,
461                         getTime(mFieldNameToFieldInput),
462                         Percentage.fromValue(
463                             getDoubleValue(mFieldNameToFieldInput, "mPercentage")
464                         ),
465                     )
466                         .build()
467 
468                 RespiratoryRateRecord::class ->
469                     RespiratoryRateRecord.Builder(
470                         metaData,
471                         getTime(mFieldNameToFieldInput),
472                         getDoubleValue(mFieldNameToFieldInput, "mRate"),
473                     )
474                         .build()
475 
476                 RestingHeartRateRecord::class ->
477                     RestingHeartRateRecord.Builder(
478                         metaData,
479                         getTime(mFieldNameToFieldInput),
480                         getLongValue(mFieldNameToFieldInput, "mBeatsPerMinute"),
481                     )
482                         .build()
483 
484                 SkinTemperatureRecord::class ->
485                     SkinTemperatureRecord.Builder(
486                         metaData,
487                         getStartTime(mFieldNameToFieldInput),
488                         getEndTime(mFieldNameToFieldInput),
489                     )
490                         .apply {
491                             OxygenSaturationRecord.Builder(
492                                 metaData,
493                                 getTime(mFieldNameToFieldInput),
494                                 Percentage.fromValue(
495                                     getDoubleValue(mFieldNameToFieldInput, "mPercentage")
496                                 ),
497                             )
498                                 .build()
499                             if (!mFieldNameToFieldInput["mDeltas"]!!.isEmpty()) {
500                                 setDeltas(
501                                     mFieldNameToFieldInput["mDeltas"]?.getFieldValue()
502                                             as List<SkinTemperatureRecord.Delta>
503                                 )
504                             }
505                             if (!mFieldNameToFieldInput["mBaseline"]!!.isEmpty()) {
506                                 setBaseline(getTemperature(mFieldNameToFieldInput, "mBaseline"))
507                             }
508                             if (!mFieldNameToFieldInput["mMeasurementLocation"]!!.isEmpty()) {
509                                 setMeasurementLocation(
510                                     getIntegerValue(mFieldNameToFieldInput, "mMeasurementLocation")
511                                 )
512                             }
513                         }
514                         .build()
515 
516                 SleepSessionRecord::class ->
517                     SleepSessionRecord.Builder(
518                         metaData,
519                         getStartTime(mFieldNameToFieldInput),
520                         getEndTime(mFieldNameToFieldInput),
521                     )
522                         .apply {
523                             if (!mFieldNameToFieldInput["mNotes"]!!.isEmpty()) {
524                                 setNotes(getStringValue(mFieldNameToFieldInput, "mNotes"))
525                             }
526                             if (!mFieldNameToFieldInput["mTitle"]!!.isEmpty()) {
527                                 setTitle(getStringValue(mFieldNameToFieldInput, "mTitle"))
528                             }
529                             if (!mFieldNameToFieldInput["mStages"]!!.isEmpty()) {
530                                 setStages(
531                                     mFieldNameToFieldInput["mStages"]?.getFieldValue()
532                                             as List<SleepSessionRecord.Stage>
533                                 )
534                             }
535                         }
536                         .build()
537 
538                 StepsCadenceRecord::class ->
539                     StepsCadenceRecord.Builder(
540                         metaData,
541                         getStartTime(mFieldNameToFieldInput),
542                         getEndTime(mFieldNameToFieldInput),
543                         mFieldNameToFieldInput["mStepsCadenceRecordSamples"]?.getFieldValue()
544                                 as List<StepsCadenceRecordSample>,
545                     )
546                         .build()
547 
548                 MenstruationPeriodRecord::class ->
549                     MenstruationPeriodRecord.Builder(
550                         metaData,
551                         getStartTime(mFieldNameToFieldInput),
552                         getEndTime(mFieldNameToFieldInput),
553                     )
554                         .build()
555 
556                 ExerciseSessionRecord::class -> {
557                     val startTime = mFieldNameToFieldInput["startTime"]?.getFieldValue() as Instant
558 
559                     ExerciseSessionRecord.Builder(
560                         metaData,
561                         startTime,
562                         mFieldNameToFieldInput["endTime"]?.getFieldValue() as Instant,
563                         mFieldNameToFieldInput["mExerciseType"]
564                             ?.getFieldValue()
565                             .toString()
566                             .toInt(),
567                     )
568                         .apply {
569                             if (!mFieldNameToFieldInput["mNotes"]!!.isEmpty()) {
570                                 setNotes(getStringValue(mFieldNameToFieldInput, "mNotes"))
571                             }
572                             if (!mFieldNameToFieldInput["mTitle"]!!.isEmpty()) {
573                                 setTitle(getStringValue(mFieldNameToFieldInput, "mTitle"))
574                             }
575                             if (!mFieldNameToFieldInput["mExerciseRoute"]!!.isEmpty()) {
576                                 val exerciseRoutes =
577                                     mFieldNameToFieldInput["mExerciseRoute"]?.getFieldValue()
578                                             as List<ExerciseRoutesTestData.ExerciseRouteLocationData>
579                                 setRoute(
580                                     generateExerciseRouteFromLocations(
581                                         exerciseRoutes,
582                                         startTime.toEpochMilli(),
583                                     )
584                                 )
585                             }
586                             if (!mFieldNameToFieldInput["mSegments"]!!.isEmpty()) {
587                                 setSegments(
588                                     mFieldNameToFieldInput["mSegments"]?.getFieldValue()
589                                             as List<ExerciseSegment>
590                                 )
591                             }
592                             if (!mFieldNameToFieldInput["mLaps"]!!.isEmpty()) {
593                                 setLaps(
594                                     mFieldNameToFieldInput["mLaps"]?.getFieldValue()
595                                             as List<ExerciseLap>
596                                 )
597                             }
598                         }
599                         .build()
600                 }
601 
602                 PlannedExerciseSessionRecord::class -> {
603                     val startTime = mFieldNameToFieldInput["startTime"]?.getFieldValue() as Instant
604                     PlannedExerciseSessionRecord.Builder(
605                         metaData,
606                         mFieldNameToFieldInput["mPlannedExerciseType"]
607                             ?.getFieldValue()
608                             .toString()
609                             .toInt(),
610                         startTime,
611                         mFieldNameToFieldInput["endTime"]?.getFieldValue() as Instant,
612                     )
613                         .apply {
614                             if (!mFieldNameToFieldInput["mNotes"]!!.isEmpty()) {
615                                 setNotes(getStringValue(mFieldNameToFieldInput, "mNotes"))
616                             }
617                             if (!mFieldNameToFieldInput["mTitle"]!!.isEmpty()) {
618                                 setTitle(getStringValue(mFieldNameToFieldInput, "mTitle"))
619                             }
620                             if (!mFieldNameToFieldInput["mBlocks"]!!.isEmpty()) {
621                                 setBlocks(
622                                     mFieldNameToFieldInput["mBlocks"]?.getFieldValue()
623                                             as List<PlannedExerciseBlock>
624                                 )
625                             }
626                         }
627                         .build()
628                 }
629 
630                 NutritionRecord::class ->
631                     NutritionRecord.Builder(
632                         metaData,
633                         getStartTime(mFieldNameToFieldInput),
634                         getEndTime(mFieldNameToFieldInput),
635                     )
636                         .apply {
637                             if (!mFieldNameToFieldInput["mBiotin"]!!.isEmpty()) {
638                                 setBiotin(getMass(mFieldNameToFieldInput, "mBiotin"))
639                             }
640                             if (!mFieldNameToFieldInput["mCaffeine"]!!.isEmpty()) {
641                                 setCaffeine(getMass(mFieldNameToFieldInput, "mCaffeine"))
642                             }
643                             if (!mFieldNameToFieldInput["mCalcium"]!!.isEmpty()) {
644                                 setCalcium(getMass(mFieldNameToFieldInput, "mCalcium"))
645                             }
646                             if (!mFieldNameToFieldInput["mChloride"]!!.isEmpty()) {
647                                 setChloride(getMass(mFieldNameToFieldInput, "mChloride"))
648                             }
649                             if (!mFieldNameToFieldInput["mCholesterol"]!!.isEmpty()) {
650                                 setCholesterol(getMass(mFieldNameToFieldInput, "mCholesterol"))
651                             }
652                             if (!mFieldNameToFieldInput["mChromium"]!!.isEmpty()) {
653                                 setChromium(getMass(mFieldNameToFieldInput, "mChromium"))
654                             }
655                             if (!mFieldNameToFieldInput["mDietaryFiber"]!!.isEmpty()) {
656                                 setDietaryFiber(getMass(mFieldNameToFieldInput, "mDietaryFiber"))
657                             }
658                             if (!mFieldNameToFieldInput["mCopper"]!!.isEmpty()) {
659                                 setCopper(getMass(mFieldNameToFieldInput, "mCopper"))
660                             }
661                             if (!mFieldNameToFieldInput["mEnergy"]!!.isEmpty()) {
662                                 setEnergy(
663                                     Energy.fromCalories(
664                                         getDoubleValue(mFieldNameToFieldInput, "mEnergy")
665                                     )
666                                 )
667                             }
668                             if (!mFieldNameToFieldInput["mFolate"]!!.isEmpty()) {
669                                 setFolate(getMass(mFieldNameToFieldInput, "mFolate"))
670                             }
671                             if (!mFieldNameToFieldInput["mEnergyFromFat"]!!.isEmpty()) {
672                                 setEnergyFromFat(
673                                     Energy.fromCalories(
674                                         getDoubleValue(mFieldNameToFieldInput, "mEnergyFromFat")
675                                     )
676                                 )
677                             }
678                             if (!mFieldNameToFieldInput["mFolicAcid"]!!.isEmpty()) {
679                                 setFolicAcid(getMass(mFieldNameToFieldInput, "mFolicAcid"))
680                             }
681                             if (!mFieldNameToFieldInput["mIodine"]!!.isEmpty()) {
682                                 setIodine(getMass(mFieldNameToFieldInput, "mIodine"))
683                             }
684                             if (!mFieldNameToFieldInput["mIron"]!!.isEmpty()) {
685                                 setIron(getMass(mFieldNameToFieldInput, "mIron"))
686                             }
687                             if (!mFieldNameToFieldInput["mMagnesium"]!!.isEmpty()) {
688                                 setMagnesium(getMass(mFieldNameToFieldInput, "mMagnesium"))
689                             }
690                             if (!mFieldNameToFieldInput["mManganese"]!!.isEmpty()) {
691                                 setManganese(getMass(mFieldNameToFieldInput, "mManganese"))
692                             }
693                         }
694                         .build()
695 
696                 MindfulnessSessionRecord::class ->
697                     MindfulnessSessionRecord.Builder(
698                         metaData,
699                         getStartTime(mFieldNameToFieldInput),
700                         getEndTime(mFieldNameToFieldInput),
701                         mFieldNameToFieldInput["mMindfulnessSessionType"]
702                             ?.getFieldValue()
703                             .toString()
704                             .toInt(),
705                     )
706                         .apply {
707                             mFieldNameToFieldInput["mTitle"]
708                                 ?.takeIf { !it.isEmpty() }
709                                 ?.let { setTitle(it.getFieldValue().toString()) }
710                             mFieldNameToFieldInput["mNotes"]
711                                 ?.takeIf { !it.isEmpty() }
712                                 ?.let { setNotes(it.getFieldValue().toString()) }
713                         }
714                         .build()
715 
716                 ActivityIntensityRecord::class ->
717                     ActivityIntensityRecord.Builder(
718                         metaData,
719                         getStartTime(mFieldNameToFieldInput),
720                         getEndTime(mFieldNameToFieldInput),
721                         mFieldNameToFieldInput["mActivityIntensityType"]
722                             ?.getFieldValue()
723                             .toString()
724                             .toInt(),
725                     )
726                         .build()
727 
728                 else -> throw NotImplementedError("Record type not implemented")
729             }
730         }
731     }
732 }
733