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 android.health.connect.internal.datatypes;
18 
19 import android.health.connect.datatypes.ExercisePerformanceGoal;
20 import android.health.connect.datatypes.units.Mass;
21 import android.health.connect.datatypes.units.Power;
22 import android.health.connect.datatypes.units.Velocity;
23 import android.os.Parcel;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 /**
29  * Internal representation of {@link android.health.connect.datatypes.PlannedExerciseSessionRecord}.
30  *
31  * @hide
32  */
33 public abstract class ExercisePerformanceGoalInternal {
34     /** Convert to external representation. */
toExternalObject()35     public abstract ExercisePerformanceGoal toExternalObject();
36 
writeFieldsToParcel(Parcel parcel)37     abstract void writeFieldsToParcel(Parcel parcel);
38 
39     /** Subclass identifier used during serialization/deserialization. */
getTypeId()40     public abstract int getTypeId();
41 
42     /** Serialize to parcel. */
writeToParcel( List<ExercisePerformanceGoalInternal> performanceGoals, Parcel parcel)43     public static void writeToParcel(
44             List<ExercisePerformanceGoalInternal> performanceGoals, Parcel parcel) {
45         parcel.writeInt(performanceGoals.size());
46         for (ExercisePerformanceGoalInternal performanceGoal : performanceGoals) {
47             parcel.writeInt(performanceGoal.getTypeId());
48             performanceGoal.writeFieldsToParcel(parcel);
49         }
50     }
51 
52     /** Deserialize from parcel. */
readFromParcel(Parcel parcel)53     public static List<ExercisePerformanceGoalInternal> readFromParcel(Parcel parcel) {
54         List<ExercisePerformanceGoalInternal> result = new ArrayList<>();
55         int count = parcel.readInt();
56         for (int i = 0; i < count; i++) {
57             int goalTypeId = parcel.readInt();
58             switch (goalTypeId) {
59                 case PowerGoalInternal.POWER_GOAL_TYPE_ID:
60                     result.add(PowerGoalInternal.readFieldsFromParcel(parcel));
61                     break;
62                 case SpeedGoalInternal.SPEED_GOAL_TYPE_ID:
63                     result.add(SpeedGoalInternal.readFieldsFromParcel(parcel));
64                     break;
65                 case CadenceGoalInternal.CADENCE_GOAL_TYPE_ID:
66                     result.add(CadenceGoalInternal.readFieldsFromParcel(parcel));
67                     break;
68                 case HeartRateGoalInternal.HEART_RATE_GOAL_TYPE_ID:
69                     result.add(HeartRateGoalInternal.readFieldsFromParcel(parcel));
70                     break;
71                 case WeightGoalInternal.WEIGHT_GOAL_TYPE_ID:
72                     result.add(WeightGoalInternal.readFieldsFromParcel(parcel));
73                     break;
74                 case RateOfPerceivedExertionGoalInternal.RATE_OF_PERCEIVED_EXERTION_TYPE_ID:
75                     result.add(RateOfPerceivedExertionGoalInternal.readFieldsFromParcel(parcel));
76                     break;
77                 case AmrapGoalInternal.AMRAP_GOAL_TYPE_ID:
78                     result.add(AmrapGoalInternal.INSTANCE);
79                     break;
80                 case ExercisePerformanceGoalInternal.UnknownGoalInternal.UNKNOWN_GOAL_TYPE_ID:
81                     result.add(UnknownGoalInternal.INSTANCE);
82                     break;
83                 default:
84                     // Can never happen. Client side and service side always have consistent
85                     // version.
86                     break;
87             }
88         }
89         return result;
90     }
91 
92     /** Convert to internal representation. */
fromExternalObject( ExercisePerformanceGoal externalObject)93     public static ExercisePerformanceGoalInternal fromExternalObject(
94             ExercisePerformanceGoal externalObject) {
95         if (externalObject instanceof ExercisePerformanceGoal.PowerGoal) {
96             ExercisePerformanceGoal.PowerGoal goal =
97                     (ExercisePerformanceGoal.PowerGoal) externalObject;
98             return new PowerGoalInternal(goal.getMinPower(), goal.getMaxPower());
99         } else if (externalObject instanceof ExercisePerformanceGoal.SpeedGoal) {
100             ExercisePerformanceGoal.SpeedGoal goal =
101                     (ExercisePerformanceGoal.SpeedGoal) externalObject;
102             return new SpeedGoalInternal(goal.getMinSpeed(), goal.getMaxSpeed());
103         } else if (externalObject instanceof ExercisePerformanceGoal.CadenceGoal) {
104             ExercisePerformanceGoal.CadenceGoal goal =
105                     (ExercisePerformanceGoal.CadenceGoal) externalObject;
106             return new CadenceGoalInternal(goal.getMinRpm(), goal.getMaxRpm());
107         } else if (externalObject instanceof ExercisePerformanceGoal.HeartRateGoal) {
108             ExercisePerformanceGoal.HeartRateGoal goal =
109                     (ExercisePerformanceGoal.HeartRateGoal) externalObject;
110             return new HeartRateGoalInternal(goal.getMinBpm(), goal.getMaxBpm());
111         } else if (externalObject instanceof ExercisePerformanceGoal.WeightGoal) {
112             ExercisePerformanceGoal.WeightGoal goal =
113                     (ExercisePerformanceGoal.WeightGoal) externalObject;
114             return new WeightGoalInternal(goal.getMass());
115         } else if (externalObject instanceof ExercisePerformanceGoal.RateOfPerceivedExertionGoal) {
116             ExercisePerformanceGoal.RateOfPerceivedExertionGoal goal =
117                     (ExercisePerformanceGoal.RateOfPerceivedExertionGoal) externalObject;
118             return new RateOfPerceivedExertionGoalInternal(goal.getRpe());
119         } else if (externalObject instanceof ExercisePerformanceGoal.AmrapGoal) {
120             return AmrapGoalInternal.INSTANCE;
121         } else {
122             return UnknownGoalInternal.INSTANCE;
123         }
124     }
125 
126     /**
127      * Represents a goal that is not recognised by the platform. This could happen when e.g. a
128      * version rollback occurs, i.e. a version is stored in the database that is not supported by
129      * the current (older) version.
130      */
131     public static final class UnknownGoalInternal extends ExercisePerformanceGoalInternal {
132         public static final UnknownGoalInternal INSTANCE = new UnknownGoalInternal();
133 
134         public static final int UNKNOWN_GOAL_TYPE_ID = 0;
135 
136         @Override
writeFieldsToParcel(Parcel parcel)137         void writeFieldsToParcel(Parcel parcel) {
138             // No fields to write.
139         }
140 
141         @Override
getTypeId()142         public int getTypeId() {
143             return UNKNOWN_GOAL_TYPE_ID;
144         }
145 
UnknownGoalInternal()146         UnknownGoalInternal() {}
147 
148         @Override
toExternalObject()149         public ExercisePerformanceGoal toExternalObject() {
150             return ExercisePerformanceGoal.UnknownGoal.INSTANCE;
151         }
152     }
153 
154     public static final class PowerGoalInternal extends ExercisePerformanceGoalInternal {
155         public static final int POWER_GOAL_TYPE_ID = 1;
156 
157         @Override
writeFieldsToParcel(Parcel parcel)158         void writeFieldsToParcel(Parcel parcel) {
159             parcel.writeDouble(this.mMinPower.getInWatts());
160             parcel.writeDouble(this.mMaxPower.getInWatts());
161         }
162 
readFieldsFromParcel(Parcel parcel)163         static PowerGoalInternal readFieldsFromParcel(Parcel parcel) {
164             return new PowerGoalInternal(
165                     Power.fromWatts(parcel.readDouble()), Power.fromWatts(parcel.readDouble()));
166         }
167 
168         @Override
getTypeId()169         public int getTypeId() {
170             return POWER_GOAL_TYPE_ID;
171         }
172 
173         private final Power mMinPower;
174         private final Power mMaxPower;
175 
PowerGoalInternal(Power minPower, Power maxPower)176         public PowerGoalInternal(Power minPower, Power maxPower) {
177             this.mMinPower = minPower;
178             this.mMaxPower = maxPower;
179         }
180 
getMinPower()181         public Power getMinPower() {
182             return mMinPower;
183         }
184 
getMaxPower()185         public Power getMaxPower() {
186             return mMaxPower;
187         }
188 
189         @Override
toExternalObject()190         public ExercisePerformanceGoal toExternalObject() {
191             return new ExercisePerformanceGoal.PowerGoal(mMinPower, mMaxPower);
192         }
193     }
194 
195     public static final class SpeedGoalInternal extends ExercisePerformanceGoalInternal {
196         public static final int SPEED_GOAL_TYPE_ID = 2;
197 
198         @Override
writeFieldsToParcel(Parcel parcel)199         void writeFieldsToParcel(Parcel parcel) {
200             parcel.writeDouble(this.mMinSpeed.getInMetersPerSecond());
201             parcel.writeDouble(this.mMaxSpeed.getInMetersPerSecond());
202         }
203 
readFieldsFromParcel(Parcel parcel)204         static SpeedGoalInternal readFieldsFromParcel(Parcel parcel) {
205             return new SpeedGoalInternal(
206                     Velocity.fromMetersPerSecond(parcel.readDouble()),
207                     Velocity.fromMetersPerSecond(parcel.readDouble()));
208         }
209 
210         @Override
getTypeId()211         public int getTypeId() {
212             return SPEED_GOAL_TYPE_ID;
213         }
214 
215         private final Velocity mMinSpeed;
216         private final Velocity mMaxSpeed;
217 
SpeedGoalInternal(Velocity minSpeed, Velocity maxSpeed)218         public SpeedGoalInternal(Velocity minSpeed, Velocity maxSpeed) {
219             this.mMinSpeed = minSpeed;
220             this.mMaxSpeed = maxSpeed;
221         }
222 
getMinSpeed()223         public Velocity getMinSpeed() {
224             return mMinSpeed;
225         }
226 
getMaxSpeed()227         public Velocity getMaxSpeed() {
228             return mMaxSpeed;
229         }
230 
231         @Override
toExternalObject()232         public ExercisePerformanceGoal toExternalObject() {
233             return new ExercisePerformanceGoal.SpeedGoal(mMinSpeed, mMaxSpeed);
234         }
235     }
236 
237     public static final class CadenceGoalInternal extends ExercisePerformanceGoalInternal {
238         public static final int CADENCE_GOAL_TYPE_ID = 3;
239 
240         @Override
writeFieldsToParcel(Parcel parcel)241         void writeFieldsToParcel(Parcel parcel) {
242             parcel.writeDouble(this.mMinRpm);
243             parcel.writeDouble(this.mMaxRpm);
244         }
245 
readFieldsFromParcel(Parcel parcel)246         static CadenceGoalInternal readFieldsFromParcel(Parcel parcel) {
247             return new CadenceGoalInternal(parcel.readDouble(), parcel.readDouble());
248         }
249 
250         @Override
getTypeId()251         public int getTypeId() {
252             return CADENCE_GOAL_TYPE_ID;
253         }
254 
255         private final double mMinRpm;
256         private final double mMaxRpm;
257 
CadenceGoalInternal(double minRpm, double maxRpm)258         public CadenceGoalInternal(double minRpm, double maxRpm) {
259             this.mMinRpm = minRpm;
260             this.mMaxRpm = maxRpm;
261         }
262 
getMinRpm()263         public double getMinRpm() {
264             return mMinRpm;
265         }
266 
getMaxRpm()267         public double getMaxRpm() {
268             return mMaxRpm;
269         }
270 
271         @Override
toExternalObject()272         public ExercisePerformanceGoal toExternalObject() {
273             return new ExercisePerformanceGoal.CadenceGoal(mMinRpm, mMaxRpm);
274         }
275     }
276 
277     public static final class HeartRateGoalInternal extends ExercisePerformanceGoalInternal {
278         public static final int HEART_RATE_GOAL_TYPE_ID = 4;
279 
280         @Override
writeFieldsToParcel(Parcel parcel)281         void writeFieldsToParcel(Parcel parcel) {
282             parcel.writeInt(this.mMinBpm);
283             parcel.writeInt(this.mMaxBpm);
284         }
285 
readFieldsFromParcel(Parcel parcel)286         static HeartRateGoalInternal readFieldsFromParcel(Parcel parcel) {
287             return new HeartRateGoalInternal(parcel.readInt(), parcel.readInt());
288         }
289 
290         @Override
getTypeId()291         public int getTypeId() {
292             return HEART_RATE_GOAL_TYPE_ID;
293         }
294 
295         private final int mMinBpm;
296         private final int mMaxBpm;
297 
HeartRateGoalInternal(int minBpm, int maxBpm)298         public HeartRateGoalInternal(int minBpm, int maxBpm) {
299             this.mMinBpm = minBpm;
300             this.mMaxBpm = maxBpm;
301         }
302 
getMinBpm()303         public int getMinBpm() {
304             return mMinBpm;
305         }
306 
getMaxBpm()307         public int getMaxBpm() {
308             return mMaxBpm;
309         }
310 
311         @Override
toExternalObject()312         public ExercisePerformanceGoal toExternalObject() {
313             return new ExercisePerformanceGoal.HeartRateGoal(mMinBpm, mMaxBpm);
314         }
315     }
316 
317     public static final class WeightGoalInternal extends ExercisePerformanceGoalInternal {
318         public static final int WEIGHT_GOAL_TYPE_ID = 5;
319 
320         @Override
writeFieldsToParcel(Parcel parcel)321         void writeFieldsToParcel(Parcel parcel) {
322             parcel.writeDouble(this.mMass.getInGrams());
323         }
324 
readFieldsFromParcel(Parcel parcel)325         static WeightGoalInternal readFieldsFromParcel(Parcel parcel) {
326             return new WeightGoalInternal(Mass.fromGrams(parcel.readDouble()));
327         }
328 
329         @Override
getTypeId()330         public int getTypeId() {
331             return WEIGHT_GOAL_TYPE_ID;
332         }
333 
334         private final Mass mMass;
335 
WeightGoalInternal(Mass mass)336         public WeightGoalInternal(Mass mass) {
337             this.mMass = mass;
338         }
339 
getMass()340         public Mass getMass() {
341             return mMass;
342         }
343 
344         @Override
toExternalObject()345         public ExercisePerformanceGoal toExternalObject() {
346             return new ExercisePerformanceGoal.WeightGoal(mMass);
347         }
348     }
349 
350     public static final class RateOfPerceivedExertionGoalInternal
351             extends ExercisePerformanceGoalInternal {
352         public static final int RATE_OF_PERCEIVED_EXERTION_TYPE_ID = 6;
353 
354         @Override
writeFieldsToParcel(Parcel parcel)355         void writeFieldsToParcel(Parcel parcel) {
356             parcel.writeInt(this.mRpe);
357         }
358 
readFieldsFromParcel(Parcel parcel)359         static RateOfPerceivedExertionGoalInternal readFieldsFromParcel(Parcel parcel) {
360             return new RateOfPerceivedExertionGoalInternal(parcel.readInt());
361         }
362 
363         @Override
getTypeId()364         public int getTypeId() {
365             return RATE_OF_PERCEIVED_EXERTION_TYPE_ID;
366         }
367 
368         private final int mRpe;
369 
RateOfPerceivedExertionGoalInternal(int rpe)370         public RateOfPerceivedExertionGoalInternal(int rpe) {
371             this.mRpe = rpe;
372         }
373 
getRpe()374         public int getRpe() {
375             return mRpe;
376         }
377 
378         @Override
toExternalObject()379         public ExercisePerformanceGoal toExternalObject() {
380             return new ExercisePerformanceGoal.RateOfPerceivedExertionGoal(mRpe);
381         }
382     }
383 
384     public static final class AmrapGoalInternal extends ExercisePerformanceGoalInternal {
385         public static final AmrapGoalInternal INSTANCE = new AmrapGoalInternal();
386 
387         public static final int AMRAP_GOAL_TYPE_ID = 7;
388 
389         @Override
writeFieldsToParcel(Parcel parcel)390         void writeFieldsToParcel(Parcel parcel) {
391             // No fields to write.
392         }
393 
394         @Override
getTypeId()395         public int getTypeId() {
396             return AMRAP_GOAL_TYPE_ID;
397         }
398 
AmrapGoalInternal()399         AmrapGoalInternal() {}
400 
401         @Override
toExternalObject()402         public ExercisePerformanceGoal toExternalObject() {
403             return ExercisePerformanceGoal.AmrapGoal.INSTANCE;
404         }
405     }
406 }
407