1 /*
2  * Copyright (C) 2023 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 android.health.connect.internal.datatypes.utils;
18 
19 import android.annotation.NonNull;
20 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord;
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.DistanceRecord;
32 import android.health.connect.datatypes.ElevationGainedRecord;
33 import android.health.connect.datatypes.ExerciseSessionRecord;
34 import android.health.connect.datatypes.FloorsClimbedRecord;
35 import android.health.connect.datatypes.HeartRateRecord;
36 import android.health.connect.datatypes.HeartRateVariabilityRmssdRecord;
37 import android.health.connect.datatypes.HeightRecord;
38 import android.health.connect.datatypes.HydrationRecord;
39 import android.health.connect.datatypes.IntermenstrualBleedingRecord;
40 import android.health.connect.datatypes.LeanBodyMassRecord;
41 import android.health.connect.datatypes.MenstruationFlowRecord;
42 import android.health.connect.datatypes.MenstruationPeriodRecord;
43 import android.health.connect.datatypes.NutritionRecord;
44 import android.health.connect.datatypes.OvulationTestRecord;
45 import android.health.connect.datatypes.OxygenSaturationRecord;
46 import android.health.connect.datatypes.PlannedExerciseSessionRecord;
47 import android.health.connect.datatypes.PowerRecord;
48 import android.health.connect.datatypes.Record;
49 import android.health.connect.datatypes.RecordTypeIdentifier;
50 import android.health.connect.datatypes.RespiratoryRateRecord;
51 import android.health.connect.datatypes.RestingHeartRateRecord;
52 import android.health.connect.datatypes.SexualActivityRecord;
53 import android.health.connect.datatypes.SkinTemperatureRecord;
54 import android.health.connect.datatypes.SleepSessionRecord;
55 import android.health.connect.datatypes.SpeedRecord;
56 import android.health.connect.datatypes.StepsCadenceRecord;
57 import android.health.connect.datatypes.StepsRecord;
58 import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
59 import android.health.connect.datatypes.Vo2MaxRecord;
60 import android.health.connect.datatypes.WeightRecord;
61 import android.health.connect.datatypes.WheelchairPushesRecord;
62 import android.health.connect.internal.datatypes.ActiveCaloriesBurnedRecordInternal;
63 import android.health.connect.internal.datatypes.BasalBodyTemperatureRecordInternal;
64 import android.health.connect.internal.datatypes.BasalMetabolicRateRecordInternal;
65 import android.health.connect.internal.datatypes.BloodGlucoseRecordInternal;
66 import android.health.connect.internal.datatypes.BloodPressureRecordInternal;
67 import android.health.connect.internal.datatypes.BodyFatRecordInternal;
68 import android.health.connect.internal.datatypes.BodyTemperatureRecordInternal;
69 import android.health.connect.internal.datatypes.BodyWaterMassRecordInternal;
70 import android.health.connect.internal.datatypes.BoneMassRecordInternal;
71 import android.health.connect.internal.datatypes.CervicalMucusRecordInternal;
72 import android.health.connect.internal.datatypes.CyclingPedalingCadenceRecordInternal;
73 import android.health.connect.internal.datatypes.DistanceRecordInternal;
74 import android.health.connect.internal.datatypes.ElevationGainedRecordInternal;
75 import android.health.connect.internal.datatypes.ExerciseSessionRecordInternal;
76 import android.health.connect.internal.datatypes.FloorsClimbedRecordInternal;
77 import android.health.connect.internal.datatypes.HeartRateRecordInternal;
78 import android.health.connect.internal.datatypes.HeartRateVariabilityRmssdRecordInternal;
79 import android.health.connect.internal.datatypes.HeightRecordInternal;
80 import android.health.connect.internal.datatypes.HydrationRecordInternal;
81 import android.health.connect.internal.datatypes.IntermenstrualBleedingRecordInternal;
82 import android.health.connect.internal.datatypes.LeanBodyMassRecordInternal;
83 import android.health.connect.internal.datatypes.MenstruationFlowRecordInternal;
84 import android.health.connect.internal.datatypes.MenstruationPeriodRecordInternal;
85 import android.health.connect.internal.datatypes.NutritionRecordInternal;
86 import android.health.connect.internal.datatypes.OvulationTestRecordInternal;
87 import android.health.connect.internal.datatypes.OxygenSaturationRecordInternal;
88 import android.health.connect.internal.datatypes.PlannedExerciseSessionRecordInternal;
89 import android.health.connect.internal.datatypes.PowerRecordInternal;
90 import android.health.connect.internal.datatypes.RecordInternal;
91 import android.health.connect.internal.datatypes.RespiratoryRateRecordInternal;
92 import android.health.connect.internal.datatypes.RestingHeartRateRecordInternal;
93 import android.health.connect.internal.datatypes.SexualActivityRecordInternal;
94 import android.health.connect.internal.datatypes.SkinTemperatureRecordInternal;
95 import android.health.connect.internal.datatypes.SleepSessionRecordInternal;
96 import android.health.connect.internal.datatypes.SpeedRecordInternal;
97 import android.health.connect.internal.datatypes.StepsCadenceRecordInternal;
98 import android.health.connect.internal.datatypes.StepsRecordInternal;
99 import android.health.connect.internal.datatypes.TotalCaloriesBurnedRecordInternal;
100 import android.health.connect.internal.datatypes.Vo2MaxRecordInternal;
101 import android.health.connect.internal.datatypes.WeightRecordInternal;
102 import android.health.connect.internal.datatypes.WheelchairPushesRecordInternal;
103 import android.util.ArrayMap;
104 
105 import java.util.Map;
106 
107 /** @hide */
108 public final class RecordMapper {
109     private static final int NUM_ENTRIES = 35;
110 
111     @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression
112     private static volatile RecordMapper sRecordMapper;
113 
114     private final Map<Integer, Class<? extends RecordInternal<?>>>
115             mRecordIdToInternalRecordClassMap;
116     private final Map<Integer, Class<? extends Record>> mRecordIdToExternalRecordClassMap;
117     private final Map<Class<? extends Record>, Integer> mExternalRecordClassToRecordIdMap;
118 
RecordMapper()119     private RecordMapper() {
120         mRecordIdToInternalRecordClassMap = new ArrayMap<>(NUM_ENTRIES);
121         mRecordIdToInternalRecordClassMap.put(
122                 RecordTypeIdentifier.RECORD_TYPE_STEPS, StepsRecordInternal.class);
123         mRecordIdToInternalRecordClassMap.put(
124                 RecordTypeIdentifier.RECORD_TYPE_HEART_RATE, HeartRateRecordInternal.class);
125         mRecordIdToInternalRecordClassMap.put(
126                 RecordTypeIdentifier.RECORD_TYPE_FLOORS_CLIMBED, FloorsClimbedRecordInternal.class);
127         mRecordIdToInternalRecordClassMap.put(
128                 RecordTypeIdentifier.RECORD_TYPE_HYDRATION, HydrationRecordInternal.class);
129         mRecordIdToInternalRecordClassMap.put(
130                 RecordTypeIdentifier.RECORD_TYPE_ACTIVE_CALORIES_BURNED,
131                 ActiveCaloriesBurnedRecordInternal.class);
132         mRecordIdToInternalRecordClassMap.put(
133                 RecordTypeIdentifier.RECORD_TYPE_ELEVATION_GAINED,
134                 ElevationGainedRecordInternal.class);
135 
136         mRecordIdToInternalRecordClassMap.put(
137                 RecordTypeIdentifier.RECORD_TYPE_WHEELCHAIR_PUSHES,
138                 WheelchairPushesRecordInternal.class);
139 
140         mRecordIdToInternalRecordClassMap.put(
141                 RecordTypeIdentifier.RECORD_TYPE_TOTAL_CALORIES_BURNED,
142                 TotalCaloriesBurnedRecordInternal.class);
143 
144         mRecordIdToInternalRecordClassMap.put(
145                 RecordTypeIdentifier.RECORD_TYPE_DISTANCE, DistanceRecordInternal.class);
146         mRecordIdToInternalRecordClassMap.put(
147                 RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE,
148                 BasalMetabolicRateRecordInternal.class);
149         mRecordIdToInternalRecordClassMap.put(
150                 RecordTypeIdentifier.RECORD_TYPE_CYCLING_PEDALING_CADENCE,
151                 CyclingPedalingCadenceRecordInternal.class);
152         mRecordIdToInternalRecordClassMap.put(
153                 RecordTypeIdentifier.RECORD_TYPE_POWER, PowerRecordInternal.class);
154         mRecordIdToInternalRecordClassMap.put(
155                 RecordTypeIdentifier.RECORD_TYPE_NUTRITION, NutritionRecordInternal.class);
156         mRecordIdToInternalRecordClassMap.put(
157                 RecordTypeIdentifier.RECORD_TYPE_SPEED, SpeedRecordInternal.class);
158         mRecordIdToInternalRecordClassMap.put(
159                 RecordTypeIdentifier.RECORD_TYPE_STEPS_CADENCE, StepsCadenceRecordInternal.class);
160         mRecordIdToInternalRecordClassMap.put(
161                 RecordTypeIdentifier.RECORD_TYPE_BODY_WATER_MASS,
162                 BodyWaterMassRecordInternal.class);
163         mRecordIdToInternalRecordClassMap.put(
164                 RecordTypeIdentifier.RECORD_TYPE_HEART_RATE_VARIABILITY_RMSSD,
165                 HeartRateVariabilityRmssdRecordInternal.class);
166         mRecordIdToInternalRecordClassMap.put(
167                 RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_PERIOD,
168                 MenstruationPeriodRecordInternal.class);
169         mRecordIdToInternalRecordClassMap.put(
170                 RecordTypeIdentifier.RECORD_TYPE_INTERMENSTRUAL_BLEEDING,
171                 IntermenstrualBleedingRecordInternal.class);
172 
173         mRecordIdToInternalRecordClassMap.put(
174                 RecordTypeIdentifier.RECORD_TYPE_VO2_MAX, Vo2MaxRecordInternal.class);
175         mRecordIdToInternalRecordClassMap.put(
176                 RecordTypeIdentifier.RECORD_TYPE_SEXUAL_ACTIVITY,
177                 SexualActivityRecordInternal.class);
178         mRecordIdToInternalRecordClassMap.put(
179                 RecordTypeIdentifier.RECORD_TYPE_RESTING_HEART_RATE,
180                 RestingHeartRateRecordInternal.class);
181         mRecordIdToInternalRecordClassMap.put(
182                 RecordTypeIdentifier.RECORD_TYPE_WEIGHT, WeightRecordInternal.class);
183         mRecordIdToInternalRecordClassMap.put(
184                 RecordTypeIdentifier.RECORD_TYPE_OXYGEN_SATURATION,
185                 OxygenSaturationRecordInternal.class);
186         mRecordIdToInternalRecordClassMap.put(
187                 RecordTypeIdentifier.RECORD_TYPE_RESPIRATORY_RATE,
188                 RespiratoryRateRecordInternal.class);
189         mRecordIdToInternalRecordClassMap.put(
190                 RecordTypeIdentifier.RECORD_TYPE_BODY_TEMPERATURE,
191                 BodyTemperatureRecordInternal.class);
192         mRecordIdToInternalRecordClassMap.put(
193                 RecordTypeIdentifier.RECORD_TYPE_BONE_MASS, BoneMassRecordInternal.class);
194         mRecordIdToInternalRecordClassMap.put(
195                 RecordTypeIdentifier.RECORD_TYPE_BLOOD_PRESSURE, BloodPressureRecordInternal.class);
196         mRecordIdToInternalRecordClassMap.put(
197                 RecordTypeIdentifier.RECORD_TYPE_BODY_FAT, BodyFatRecordInternal.class);
198         mRecordIdToInternalRecordClassMap.put(
199                 RecordTypeIdentifier.RECORD_TYPE_BLOOD_GLUCOSE, BloodGlucoseRecordInternal.class);
200         mRecordIdToInternalRecordClassMap.put(
201                 RecordTypeIdentifier.RECORD_TYPE_BASAL_BODY_TEMPERATURE,
202                 BasalBodyTemperatureRecordInternal.class);
203         mRecordIdToInternalRecordClassMap.put(
204                 RecordTypeIdentifier.RECORD_TYPE_OVULATION_TEST, OvulationTestRecordInternal.class);
205         mRecordIdToInternalRecordClassMap.put(
206                 RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_FLOW,
207                 MenstruationFlowRecordInternal.class);
208         mRecordIdToInternalRecordClassMap.put(
209                 RecordTypeIdentifier.RECORD_TYPE_CERVICAL_MUCUS, CervicalMucusRecordInternal.class);
210         mRecordIdToInternalRecordClassMap.put(
211                 RecordTypeIdentifier.RECORD_TYPE_HEIGHT, HeightRecordInternal.class);
212         mRecordIdToInternalRecordClassMap.put(
213                 RecordTypeIdentifier.RECORD_TYPE_LEAN_BODY_MASS, LeanBodyMassRecordInternal.class);
214         mRecordIdToInternalRecordClassMap.put(
215                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION,
216                 ExerciseSessionRecordInternal.class);
217         mRecordIdToInternalRecordClassMap.put(
218                 RecordTypeIdentifier.RECORD_TYPE_PLANNED_EXERCISE_SESSION,
219                 PlannedExerciseSessionRecordInternal.class);
220         mRecordIdToInternalRecordClassMap.put(
221                 RecordTypeIdentifier.RECORD_TYPE_SLEEP_SESSION, SleepSessionRecordInternal.class);
222         mRecordIdToInternalRecordClassMap.put(
223                 RecordTypeIdentifier.RECORD_TYPE_SKIN_TEMPERATURE,
224                 SkinTemperatureRecordInternal.class);
225 
226         mRecordIdToExternalRecordClassMap = new ArrayMap<>(NUM_ENTRIES);
227         mRecordIdToExternalRecordClassMap.put(
228                 RecordTypeIdentifier.RECORD_TYPE_STEPS, StepsRecord.class);
229         mRecordIdToExternalRecordClassMap.put(
230                 RecordTypeIdentifier.RECORD_TYPE_HEART_RATE, HeartRateRecord.class);
231 
232         mRecordIdToExternalRecordClassMap.put(
233                 RecordTypeIdentifier.RECORD_TYPE_HYDRATION, HydrationRecord.class);
234         mRecordIdToExternalRecordClassMap.put(
235                 RecordTypeIdentifier.RECORD_TYPE_ACTIVE_CALORIES_BURNED,
236                 ActiveCaloriesBurnedRecord.class);
237         mRecordIdToExternalRecordClassMap.put(
238                 RecordTypeIdentifier.RECORD_TYPE_ELEVATION_GAINED, ElevationGainedRecord.class);
239         mRecordIdToExternalRecordClassMap.put(
240                 RecordTypeIdentifier.RECORD_TYPE_DISTANCE, DistanceRecord.class);
241         mRecordIdToExternalRecordClassMap.put(
242                 RecordTypeIdentifier.RECORD_TYPE_NUTRITION, NutritionRecord.class);
243         mRecordIdToExternalRecordClassMap.put(
244                 RecordTypeIdentifier.RECORD_TYPE_FLOORS_CLIMBED, FloorsClimbedRecord.class);
245         mRecordIdToExternalRecordClassMap.put(
246                 RecordTypeIdentifier.RECORD_TYPE_WHEELCHAIR_PUSHES, WheelchairPushesRecord.class);
247         mRecordIdToExternalRecordClassMap.put(
248                 RecordTypeIdentifier.RECORD_TYPE_TOTAL_CALORIES_BURNED,
249                 TotalCaloriesBurnedRecord.class);
250 
251         mRecordIdToExternalRecordClassMap.put(
252                 RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE,
253                 BasalMetabolicRateRecord.class);
254         mRecordIdToExternalRecordClassMap.put(
255                 RecordTypeIdentifier.RECORD_TYPE_CYCLING_PEDALING_CADENCE,
256                 CyclingPedalingCadenceRecord.class);
257         mRecordIdToExternalRecordClassMap.put(
258                 RecordTypeIdentifier.RECORD_TYPE_POWER, PowerRecord.class);
259         mRecordIdToExternalRecordClassMap.put(
260                 RecordTypeIdentifier.RECORD_TYPE_SPEED, SpeedRecord.class);
261         mRecordIdToExternalRecordClassMap.put(
262                 RecordTypeIdentifier.RECORD_TYPE_STEPS_CADENCE, StepsCadenceRecord.class);
263 
264         mRecordIdToExternalRecordClassMap.put(
265                 RecordTypeIdentifier.RECORD_TYPE_BODY_TEMPERATURE, BodyTemperatureRecord.class);
266         mRecordIdToExternalRecordClassMap.put(
267                 RecordTypeIdentifier.RECORD_TYPE_BONE_MASS, BoneMassRecord.class);
268         mRecordIdToExternalRecordClassMap.put(
269                 RecordTypeIdentifier.RECORD_TYPE_BLOOD_PRESSURE, BloodPressureRecord.class);
270         mRecordIdToExternalRecordClassMap.put(
271                 RecordTypeIdentifier.RECORD_TYPE_BODY_FAT, BodyFatRecord.class);
272         mRecordIdToExternalRecordClassMap.put(
273                 RecordTypeIdentifier.RECORD_TYPE_BLOOD_GLUCOSE, BloodGlucoseRecord.class);
274         mRecordIdToExternalRecordClassMap.put(
275                 RecordTypeIdentifier.RECORD_TYPE_BASAL_BODY_TEMPERATURE,
276                 BasalBodyTemperatureRecord.class);
277         mRecordIdToExternalRecordClassMap.put(
278                 RecordTypeIdentifier.RECORD_TYPE_CERVICAL_MUCUS, CervicalMucusRecord.class);
279         mRecordIdToExternalRecordClassMap.put(
280                 RecordTypeIdentifier.RECORD_TYPE_LEAN_BODY_MASS, LeanBodyMassRecord.class);
281         mRecordIdToExternalRecordClassMap.put(
282                 RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_FLOW, MenstruationFlowRecord.class);
283         mRecordIdToExternalRecordClassMap.put(
284                 RecordTypeIdentifier.RECORD_TYPE_HEIGHT, HeightRecord.class);
285         mRecordIdToExternalRecordClassMap.put(
286                 RecordTypeIdentifier.RECORD_TYPE_OVULATION_TEST, OvulationTestRecord.class);
287         mRecordIdToExternalRecordClassMap.put(
288                 RecordTypeIdentifier.RECORD_TYPE_VO2_MAX, Vo2MaxRecord.class);
289         mRecordIdToExternalRecordClassMap.put(
290                 RecordTypeIdentifier.RECORD_TYPE_SEXUAL_ACTIVITY, SexualActivityRecord.class);
291         mRecordIdToExternalRecordClassMap.put(
292                 RecordTypeIdentifier.RECORD_TYPE_SLEEP_SESSION, SleepSessionRecord.class);
293         mRecordIdToExternalRecordClassMap.put(
294                 RecordTypeIdentifier.RECORD_TYPE_SKIN_TEMPERATURE, SkinTemperatureRecord.class);
295 
296         mRecordIdToExternalRecordClassMap.put(
297                 RecordTypeIdentifier.RECORD_TYPE_RESPIRATORY_RATE, RespiratoryRateRecord.class);
298         mRecordIdToExternalRecordClassMap.put(
299                 RecordTypeIdentifier.RECORD_TYPE_OXYGEN_SATURATION, OxygenSaturationRecord.class);
300         mRecordIdToExternalRecordClassMap.put(
301                 RecordTypeIdentifier.RECORD_TYPE_RESTING_HEART_RATE, RestingHeartRateRecord.class);
302         mRecordIdToExternalRecordClassMap.put(
303                 RecordTypeIdentifier.RECORD_TYPE_WEIGHT, WeightRecord.class);
304         mRecordIdToExternalRecordClassMap.put(
305                 RecordTypeIdentifier.RECORD_TYPE_BODY_WATER_MASS, BodyWaterMassRecord.class);
306         mRecordIdToExternalRecordClassMap.put(
307                 RecordTypeIdentifier.RECORD_TYPE_HEART_RATE_VARIABILITY_RMSSD,
308                 HeartRateVariabilityRmssdRecord.class);
309         mRecordIdToExternalRecordClassMap.put(
310                 RecordTypeIdentifier.RECORD_TYPE_MENSTRUATION_PERIOD,
311                 MenstruationPeriodRecord.class);
312         mRecordIdToExternalRecordClassMap.put(
313                 RecordTypeIdentifier.RECORD_TYPE_INTERMENSTRUAL_BLEEDING,
314                 IntermenstrualBleedingRecord.class);
315         mRecordIdToExternalRecordClassMap.put(
316                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION, ExerciseSessionRecord.class);
317         mRecordIdToExternalRecordClassMap.put(
318                 RecordTypeIdentifier.RECORD_TYPE_PLANNED_EXERCISE_SESSION,
319                 PlannedExerciseSessionRecord.class);
320 
321         mExternalRecordClassToRecordIdMap =
322                 new ArrayMap<>(mRecordIdToExternalRecordClassMap.size());
323         mRecordIdToExternalRecordClassMap.forEach(
324                 (id, recordClass) -> mExternalRecordClassToRecordIdMap.put(recordClass, id));
325     }
326 
327     @NonNull
getInstance()328     public static synchronized RecordMapper getInstance() {
329         if (sRecordMapper == null) {
330             sRecordMapper = new RecordMapper();
331         }
332 
333         return sRecordMapper;
334     }
335 
336     @NonNull
getRecordIdToInternalRecordClassMap()337     public Map<Integer, Class<? extends RecordInternal<?>>> getRecordIdToInternalRecordClassMap() {
338         return mRecordIdToInternalRecordClassMap;
339     }
340 
341     @NonNull
getRecordIdToExternalRecordClassMap()342     public Map<Integer, Class<? extends Record>> getRecordIdToExternalRecordClassMap() {
343         return mRecordIdToExternalRecordClassMap;
344     }
345 
346     @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression
347     @RecordTypeIdentifier.RecordType
getRecordType(Class<? extends Record> recordClass)348     public int getRecordType(Class<? extends Record> recordClass) {
349         return mExternalRecordClassToRecordIdMap.get(recordClass);
350     }
351 
352     /** Checks whether the given {@code recordClass} can be mapped. */
hasRecordType(Class<? extends Record> recordClass)353     public boolean hasRecordType(Class<? extends Record> recordClass) {
354         return mExternalRecordClassToRecordIdMap.containsKey(recordClass);
355     }
356 }
357