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.annotation.NonNull; 20 import android.health.connect.datatypes.ExerciseCompletionGoal; 21 import android.health.connect.datatypes.units.Energy; 22 import android.health.connect.datatypes.units.Length; 23 import android.os.Parcel; 24 25 import java.time.Duration; 26 27 /** 28 * Internal ExerciseBlock. Part of {@link PlannedExerciseSessionRecordInternal}. 29 * 30 * @hide 31 */ 32 public abstract class ExerciseCompletionGoalInternal { 33 34 /** Convert to {@link ExerciseCompletionGoal}. */ 35 @NonNull toExternalObject()36 public abstract ExerciseCompletionGoal toExternalObject(); 37 38 /** Subclass identifier used during serialization/deserialization. */ getTypeId()39 public abstract int getTypeId(); 40 writeFieldsToParcel(@onNull Parcel parcel)41 abstract void writeFieldsToParcel(@NonNull Parcel parcel); 42 43 /** Convert from external representation. */ fromExternalObject( ExerciseCompletionGoal externalObject)44 public static ExerciseCompletionGoalInternal fromExternalObject( 45 ExerciseCompletionGoal externalObject) { 46 if (externalObject instanceof ExerciseCompletionGoal.DistanceGoal) { 47 ExerciseCompletionGoal.DistanceGoal goal = 48 (ExerciseCompletionGoal.DistanceGoal) externalObject; 49 return new DistanceGoalInternal(goal.getDistance()); 50 } else if (externalObject instanceof ExerciseCompletionGoal.DistanceWithVariableRestGoal) { 51 ExerciseCompletionGoal.DistanceWithVariableRestGoal goal = 52 (ExerciseCompletionGoal.DistanceWithVariableRestGoal) externalObject; 53 return new DistanceWithVariableRestGoalInternal(goal.getDistance(), goal.getDuration()); 54 } else if (externalObject instanceof ExerciseCompletionGoal.StepsGoal) { 55 ExerciseCompletionGoal.StepsGoal goal = 56 (ExerciseCompletionGoal.StepsGoal) externalObject; 57 return new StepsGoalInternal(goal.getSteps()); 58 } else if (externalObject instanceof ExerciseCompletionGoal.DurationGoal) { 59 ExerciseCompletionGoal.DurationGoal goal = 60 (ExerciseCompletionGoal.DurationGoal) externalObject; 61 return new DurationGoalInternal(goal.getDuration()); 62 } else if (externalObject instanceof ExerciseCompletionGoal.RepetitionsGoal) { 63 ExerciseCompletionGoal.RepetitionsGoal goal = 64 (ExerciseCompletionGoal.RepetitionsGoal) externalObject; 65 return new RepetitionsGoalInternal(goal.getRepetitions()); 66 } else if (externalObject instanceof ExerciseCompletionGoal.TotalCaloriesBurnedGoal) { 67 ExerciseCompletionGoal.TotalCaloriesBurnedGoal goal = 68 (ExerciseCompletionGoal.TotalCaloriesBurnedGoal) externalObject; 69 return new TotalCaloriesBurnedGoalInternal(goal.getTotalCalories()); 70 } else if (externalObject instanceof ExerciseCompletionGoal.ActiveCaloriesBurnedGoal) { 71 ExerciseCompletionGoal.ActiveCaloriesBurnedGoal goal = 72 (ExerciseCompletionGoal.ActiveCaloriesBurnedGoal) externalObject; 73 return new ActiveCaloriesBurnedGoalInternal(goal.getActiveCalories()); 74 } else if (externalObject instanceof ExerciseCompletionGoal.UnspecifiedGoal) { 75 return UnspecifiedGoalInternal.INSTANCE; 76 } else { 77 return UnknownGoalInternal.INSTANCE; 78 } 79 } 80 81 /** Serialize to parcel. */ writeToParcel(@onNull Parcel parcel)82 public void writeToParcel(@NonNull Parcel parcel) { 83 parcel.writeInt(getTypeId()); 84 writeFieldsToParcel(parcel); 85 } 86 87 /** Deserialize from parcel. */ 88 @NonNull readFromParcel(@onNull Parcel parcel)89 public static ExerciseCompletionGoalInternal readFromParcel(@NonNull Parcel parcel) { 90 int goalTypeId = parcel.readInt(); 91 switch (goalTypeId) { 92 case DistanceGoalInternal.DISTANCE_GOAL_TYPE_ID: 93 return DistanceGoalInternal.readFieldsFromParcel(parcel); 94 case StepsGoalInternal.STEPS_GOAL_TYPE_ID: 95 return StepsGoalInternal.readFieldsFromParcel(parcel); 96 case DurationGoalInternal.DURATION_GOAL_TYPE_ID: 97 return DurationGoalInternal.readFieldsFromParcel(parcel); 98 case RepetitionsGoalInternal.REPETITIONS_GOAL_TYPE_ID: 99 return RepetitionsGoalInternal.readFieldsFromParcel(parcel); 100 case TotalCaloriesBurnedGoalInternal.TOTAL_CALORIES_BURNED_GOAL_TYPE_ID: 101 return TotalCaloriesBurnedGoalInternal.readFieldsFromParcel(parcel); 102 case ActiveCaloriesBurnedGoalInternal.ACTIVE_CALORIES_BURNED_GOAL_TYPE_ID: 103 return ActiveCaloriesBurnedGoalInternal.readFieldsFromParcel(parcel); 104 case DistanceWithVariableRestGoalInternal.DISTANCE_WITH_VARIABLE_REST_GOAL_TYPE_ID: 105 return DistanceWithVariableRestGoalInternal.readFieldsFromParcel(parcel); 106 case UnspecifiedGoalInternal.UNSPECIFIED_GOAL_TYPE_ID: 107 return UnspecifiedGoalInternal.INSTANCE; 108 case UnknownGoalInternal.UNKNOWN_GOAL_TYPE_ID: 109 // Fall through. 110 default: 111 // Can never happen. Client side and service side always have consistent version. 112 return UnknownGoalInternal.INSTANCE; 113 } 114 } 115 116 public static final class DistanceGoalInternal extends ExerciseCompletionGoalInternal { 117 public static final int DISTANCE_GOAL_TYPE_ID = 2; 118 119 @Override writeFieldsToParcel(@onNull Parcel parcel)120 void writeFieldsToParcel(@NonNull Parcel parcel) { 121 parcel.writeDouble(this.mDistance.getInMeters()); 122 } 123 124 /** Read from parcel. */ 125 @NonNull readFieldsFromParcel(@onNull Parcel parcel)126 public static DistanceGoalInternal readFieldsFromParcel(@NonNull Parcel parcel) { 127 return new DistanceGoalInternal(Length.fromMeters(parcel.readDouble())); 128 } 129 130 private final Length mDistance; 131 DistanceGoalInternal(@onNull Length distance)132 public DistanceGoalInternal(@NonNull Length distance) { 133 this.mDistance = distance; 134 } 135 136 @NonNull getDistance()137 public Length getDistance() { 138 return mDistance; 139 } 140 141 @Override 142 @NonNull toExternalObject()143 public ExerciseCompletionGoal toExternalObject() { 144 return new ExerciseCompletionGoal.DistanceGoal(mDistance); 145 } 146 147 @Override getTypeId()148 public int getTypeId() { 149 return DISTANCE_GOAL_TYPE_ID; 150 } 151 } 152 153 public static final class StepsGoalInternal extends ExerciseCompletionGoalInternal { 154 public static final int STEPS_GOAL_TYPE_ID = 3; 155 156 @Override writeFieldsToParcel(@onNull Parcel parcel)157 void writeFieldsToParcel(@NonNull Parcel parcel) { 158 parcel.writeInt(this.mSteps); 159 } 160 161 /** Read from parcel. */ 162 @NonNull readFieldsFromParcel(@onNull Parcel parcel)163 public static StepsGoalInternal readFieldsFromParcel(@NonNull Parcel parcel) { 164 return new StepsGoalInternal(parcel.readInt()); 165 } 166 167 private final int mSteps; 168 StepsGoalInternal(int steps)169 public StepsGoalInternal(int steps) { 170 this.mSteps = steps; 171 } 172 getSteps()173 public int getSteps() { 174 return mSteps; 175 } 176 177 @Override 178 @NonNull toExternalObject()179 public ExerciseCompletionGoal toExternalObject() { 180 return new ExerciseCompletionGoal.StepsGoal(mSteps); 181 } 182 183 @Override getTypeId()184 public int getTypeId() { 185 return STEPS_GOAL_TYPE_ID; 186 } 187 } 188 189 public static final class DurationGoalInternal extends ExerciseCompletionGoalInternal { 190 public static final int DURATION_GOAL_TYPE_ID = 4; 191 192 @Override writeFieldsToParcel(@onNull Parcel parcel)193 void writeFieldsToParcel(@NonNull Parcel parcel) { 194 parcel.writeLong(this.mDuration.toMillis()); 195 } 196 197 /** Read from parcel. */ 198 @NonNull readFieldsFromParcel(@onNull Parcel parcel)199 public static DurationGoalInternal readFieldsFromParcel(@NonNull Parcel parcel) { 200 return new DurationGoalInternal(Duration.ofMillis(parcel.readLong())); 201 } 202 203 private final Duration mDuration; 204 DurationGoalInternal(@onNull Duration duration)205 public DurationGoalInternal(@NonNull Duration duration) { 206 this.mDuration = duration; 207 } 208 209 @NonNull getDuration()210 public Duration getDuration() { 211 return mDuration; 212 } 213 214 @Override 215 @NonNull toExternalObject()216 public ExerciseCompletionGoal toExternalObject() { 217 return new ExerciseCompletionGoal.DurationGoal(mDuration); 218 } 219 220 @Override getTypeId()221 public int getTypeId() { 222 return DURATION_GOAL_TYPE_ID; 223 } 224 } 225 226 public static final class RepetitionsGoalInternal extends ExerciseCompletionGoalInternal { 227 public static final int REPETITIONS_GOAL_TYPE_ID = 5; 228 229 @Override writeFieldsToParcel(@onNull Parcel parcel)230 void writeFieldsToParcel(@NonNull Parcel parcel) { 231 parcel.writeInt(this.mReps); 232 } 233 234 /** Read from parcel. */ 235 @NonNull readFieldsFromParcel(@onNull Parcel parcel)236 public static RepetitionsGoalInternal readFieldsFromParcel(@NonNull Parcel parcel) { 237 return new RepetitionsGoalInternal(parcel.readInt()); 238 } 239 240 private final int mReps; 241 RepetitionsGoalInternal(int reps)242 public RepetitionsGoalInternal(int reps) { 243 this.mReps = reps; 244 } 245 getReps()246 public int getReps() { 247 return mReps; 248 } 249 250 @Override 251 @NonNull toExternalObject()252 public ExerciseCompletionGoal toExternalObject() { 253 return new ExerciseCompletionGoal.RepetitionsGoal(mReps); 254 } 255 256 @Override getTypeId()257 public int getTypeId() { 258 return REPETITIONS_GOAL_TYPE_ID; 259 } 260 } 261 262 public static final class TotalCaloriesBurnedGoalInternal 263 extends ExerciseCompletionGoalInternal { 264 public static final int TOTAL_CALORIES_BURNED_GOAL_TYPE_ID = 6; 265 266 @Override writeFieldsToParcel(@onNull Parcel parcel)267 void writeFieldsToParcel(@NonNull Parcel parcel) { 268 parcel.writeDouble(this.mTotalCalories.getInCalories()); 269 } 270 271 /** Read from parcel. */ 272 @NonNull readFieldsFromParcel(@onNull Parcel parcel)273 public static TotalCaloriesBurnedGoalInternal readFieldsFromParcel(@NonNull Parcel parcel) { 274 return new TotalCaloriesBurnedGoalInternal(Energy.fromCalories(parcel.readDouble())); 275 } 276 277 private final Energy mTotalCalories; 278 TotalCaloriesBurnedGoalInternal(@onNull Energy totalCalories)279 public TotalCaloriesBurnedGoalInternal(@NonNull Energy totalCalories) { 280 this.mTotalCalories = totalCalories; 281 } 282 283 @NonNull getTotalCalories()284 public Energy getTotalCalories() { 285 return mTotalCalories; 286 } 287 288 @Override toExternalObject()289 public ExerciseCompletionGoal toExternalObject() { 290 return new ExerciseCompletionGoal.TotalCaloriesBurnedGoal(mTotalCalories); 291 } 292 293 @Override getTypeId()294 public int getTypeId() { 295 return TOTAL_CALORIES_BURNED_GOAL_TYPE_ID; 296 } 297 } 298 299 public static final class ActiveCaloriesBurnedGoalInternal 300 extends ExerciseCompletionGoalInternal { 301 public static final int ACTIVE_CALORIES_BURNED_GOAL_TYPE_ID = 7; 302 303 @Override writeFieldsToParcel(@onNull Parcel parcel)304 void writeFieldsToParcel(@NonNull Parcel parcel) { 305 parcel.writeDouble(this.mActiveCalories.getInCalories()); 306 } 307 308 /** Read from parcel. */ 309 @NonNull readFieldsFromParcel( @onNull Parcel parcel)310 public static ActiveCaloriesBurnedGoalInternal readFieldsFromParcel( 311 @NonNull Parcel parcel) { 312 return new ActiveCaloriesBurnedGoalInternal(Energy.fromCalories(parcel.readDouble())); 313 } 314 315 private final Energy mActiveCalories; 316 ActiveCaloriesBurnedGoalInternal(@onNull Energy activeCalories)317 public ActiveCaloriesBurnedGoalInternal(@NonNull Energy activeCalories) { 318 this.mActiveCalories = activeCalories; 319 } 320 321 @NonNull getActiveCalories()322 public Energy getActiveCalories() { 323 return mActiveCalories; 324 } 325 326 @Override 327 @NonNull toExternalObject()328 public ExerciseCompletionGoal toExternalObject() { 329 return new ExerciseCompletionGoal.ActiveCaloriesBurnedGoal(mActiveCalories); 330 } 331 332 @Override getTypeId()333 public int getTypeId() { 334 return ACTIVE_CALORIES_BURNED_GOAL_TYPE_ID; 335 } 336 } 337 338 public static final class DistanceWithVariableRestGoalInternal 339 extends ExerciseCompletionGoalInternal { 340 public static final int DISTANCE_WITH_VARIABLE_REST_GOAL_TYPE_ID = 8; 341 342 @Override writeFieldsToParcel(@onNull Parcel parcel)343 void writeFieldsToParcel(@NonNull Parcel parcel) { 344 parcel.writeDouble(this.mDistance.getInMeters()); 345 parcel.writeLong(this.mDuration.toMillis()); 346 } 347 348 /** Read from parcel. */ 349 @NonNull readFieldsFromParcel( @onNull Parcel parcel)350 public static DistanceWithVariableRestGoalInternal readFieldsFromParcel( 351 @NonNull Parcel parcel) { 352 return new DistanceWithVariableRestGoalInternal( 353 Length.fromMeters(parcel.readDouble()), Duration.ofMillis(parcel.readLong())); 354 } 355 356 private final Length mDistance; 357 358 private final Duration mDuration; 359 DistanceWithVariableRestGoalInternal( @onNull Length distance, @NonNull Duration duration)360 public DistanceWithVariableRestGoalInternal( 361 @NonNull Length distance, @NonNull Duration duration) { 362 this.mDistance = distance; 363 this.mDuration = duration; 364 } 365 366 @NonNull getDistance()367 public Length getDistance() { 368 return mDistance; 369 } 370 371 @NonNull getDuration()372 public Duration getDuration() { 373 return mDuration; 374 } 375 376 @Override 377 @NonNull toExternalObject()378 public ExerciseCompletionGoal toExternalObject() { 379 return new ExerciseCompletionGoal.DistanceWithVariableRestGoal(mDistance, mDuration); 380 } 381 382 @Override getTypeId()383 public int getTypeId() { 384 return DISTANCE_WITH_VARIABLE_REST_GOAL_TYPE_ID; 385 } 386 } 387 388 /** 389 * Represents a goal that is not recognised by the platform. This could happen when e.g. a 390 * version rollback occurs, i.e. a version is stored in the database that is not supported by 391 * the current (older) version. 392 */ 393 public static final class UnknownGoalInternal extends ExerciseCompletionGoalInternal { 394 public static final int UNKNOWN_GOAL_TYPE_ID = 0; 395 396 public static final UnknownGoalInternal INSTANCE = new UnknownGoalInternal(); 397 398 @Override writeFieldsToParcel(@onNull Parcel parcel)399 void writeFieldsToParcel(@NonNull Parcel parcel) { 400 // No fields to write. 401 } 402 UnknownGoalInternal()403 UnknownGoalInternal() {} 404 405 @Override 406 @NonNull toExternalObject()407 public ExerciseCompletionGoal toExternalObject() { 408 return ExerciseCompletionGoal.UnknownGoal.INSTANCE; 409 } 410 411 @Override getTypeId()412 public int getTypeId() { 413 return UNKNOWN_GOAL_TYPE_ID; 414 } 415 } 416 417 /** 418 * Represents an open goal that has no specific metric associated with completion. It is up to 419 * the user to determine when the goal is complete. 420 */ 421 public static final class UnspecifiedGoalInternal extends ExerciseCompletionGoalInternal { 422 public static final int UNSPECIFIED_GOAL_TYPE_ID = 1; 423 424 public static final UnspecifiedGoalInternal INSTANCE = new UnspecifiedGoalInternal(); 425 426 @Override writeFieldsToParcel(@onNull Parcel parcel)427 void writeFieldsToParcel(@NonNull Parcel parcel) { 428 // No fields to write. 429 } 430 UnspecifiedGoalInternal()431 UnspecifiedGoalInternal() {} 432 433 @Override 434 @NonNull toExternalObject()435 public ExerciseCompletionGoal toExternalObject() { 436 return ExerciseCompletionGoal.UnspecifiedGoal.INSTANCE; 437 } 438 439 @Override getTypeId()440 public int getTypeId() { 441 return UNSPECIFIED_GOAL_TYPE_ID; 442 } 443 } 444 } 445