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