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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.health.connect.datatypes.ExerciseSessionRecord; 22 import android.health.connect.datatypes.ExerciseSessionType; 23 import android.health.connect.datatypes.Identifier; 24 import android.health.connect.datatypes.PlannedExerciseSessionRecord; 25 import android.health.connect.datatypes.RecordTypeIdentifier; 26 import android.os.Parcel; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Objects; 31 import java.util.UUID; 32 33 /** 34 * @see ExerciseSessionRecord 35 * @hide 36 */ 37 @Identifier(recordIdentifier = RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION) 38 public final class ExerciseSessionRecordInternal 39 extends IntervalRecordInternal<ExerciseSessionRecord> { 40 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression 41 private String mNotes; 42 43 private int mExerciseType; 44 45 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression 46 private String mTitle; 47 48 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression 49 private ExerciseRouteInternal mExerciseRoute; 50 51 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression 52 private List<ExerciseLapInternal> mExerciseLaps; 53 54 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression 55 private List<ExerciseSegmentInternal> mExerciseSegments; 56 57 private boolean mHasRoute; 58 59 @Nullable private UUID mPlannedExerciseSessionId; 60 61 @Nullable getNotes()62 public String getNotes() { 63 return mNotes; 64 } 65 66 /** returns this object with the specified notes */ 67 @NonNull setNotes(String notes)68 public ExerciseSessionRecordInternal setNotes(String notes) { 69 this.mNotes = notes; 70 return this; 71 } 72 73 @ExerciseSessionType.ExerciseSessionTypes getExerciseType()74 public int getExerciseType() { 75 return mExerciseType; 76 } 77 78 /** returns this object with the specified exerciseType */ 79 @NonNull setExerciseType(int exerciseType)80 public ExerciseSessionRecordInternal setExerciseType(int exerciseType) { 81 this.mExerciseType = exerciseType; 82 return this; 83 } 84 85 @Nullable getTitle()86 public String getTitle() { 87 return mTitle; 88 } 89 90 /** returns this object with the specified title */ 91 @NonNull setTitle(String title)92 public ExerciseSessionRecordInternal setTitle(String title) { 93 this.mTitle = title; 94 return this; 95 } 96 97 /** 98 * @return route of this activity 99 */ 100 @Nullable getRoute()101 public ExerciseRouteInternal getRoute() { 102 return mExerciseRoute; 103 } 104 105 /** returns this object with the specified route */ 106 @NonNull setRoute(ExerciseRouteInternal route)107 public ExerciseSessionRecordInternal setRoute(ExerciseRouteInternal route) { 108 this.mExerciseRoute = route; 109 if (route != null) { 110 this.mHasRoute = true; 111 } 112 return this; 113 } 114 115 /** returns if this session has route */ hasRoute()116 public boolean hasRoute() { 117 return mHasRoute; 118 } 119 120 /** returns this object with hasRoute set */ 121 @NonNull setHasRoute(boolean hasRoute)122 public ExerciseSessionRecordInternal setHasRoute(boolean hasRoute) { 123 if (mExerciseRoute != null && !hasRoute) { 124 throw new IllegalArgumentException("HasRoute must be true if the route is not null"); 125 } 126 this.mHasRoute = hasRoute; 127 return this; 128 } 129 130 /** returns laps of this session */ 131 @Nullable getLaps()132 public List<ExerciseLapInternal> getLaps() { 133 return mExerciseLaps; 134 } 135 136 /** returns this object with exercise laps set */ setExerciseLaps( @onNull List<ExerciseLapInternal> exerciseLaps)137 public ExerciseSessionRecordInternal setExerciseLaps( 138 @NonNull List<ExerciseLapInternal> exerciseLaps) { 139 Objects.requireNonNull(exerciseLaps); 140 mExerciseLaps = new ArrayList<>(exerciseLaps); 141 return this; 142 } 143 144 @Nullable getSegments()145 public List<ExerciseSegmentInternal> getSegments() { 146 return mExerciseSegments; 147 } 148 149 /** returns this object with exercise segments set */ 150 @NonNull setExerciseSegments( @onNull List<ExerciseSegmentInternal> exerciseSegments)151 public ExerciseSessionRecordInternal setExerciseSegments( 152 @NonNull List<ExerciseSegmentInternal> exerciseSegments) { 153 Objects.requireNonNull(exerciseSegments); 154 mExerciseSegments = new ArrayList<>(exerciseSegments); 155 return this; 156 } 157 158 /** Sets the {@link PlannedExerciseSessionRecord} that this session was based upon. */ 159 @NonNull setPlannedExerciseSessionId(@ullable UUID id)160 public ExerciseSessionRecordInternal setPlannedExerciseSessionId(@Nullable UUID id) { 161 mPlannedExerciseSessionId = id; 162 return this; 163 } 164 165 /** 166 * Returns the ID of the {@link PlannedExerciseSessionRecord} that this session was based upon. 167 * If not set, returns null. 168 */ 169 @Nullable getPlannedExerciseSessionId()170 public UUID getPlannedExerciseSessionId() { 171 return mPlannedExerciseSessionId; 172 } 173 174 @NonNull 175 @Override toExternalRecord()176 public ExerciseSessionRecord toExternalRecord() { 177 ExerciseSessionRecord.Builder builder = 178 new ExerciseSessionRecord.Builder( 179 buildMetaData(), getStartTime(), getEndTime(), getExerciseType()); 180 181 if (getStartZoneOffset() != null) { 182 builder.setStartZoneOffset(getStartZoneOffset()); 183 } 184 185 if (getEndZoneOffset() != null) { 186 builder.setEndZoneOffset(getEndZoneOffset()); 187 } 188 189 if (getNotes() != null) { 190 builder.setNotes(getNotes()); 191 } 192 193 if (getTitle() != null) { 194 builder.setTitle(getTitle()); 195 } 196 197 if (mExerciseRoute != null) { 198 builder.setRoute(mExerciseRoute.toExternalRoute()); 199 } 200 201 builder.setHasRoute(mHasRoute); 202 203 if (getLaps() != null) { 204 builder.setLaps(ExerciseLapInternal.getExternalLaps(mExerciseLaps)); 205 } 206 207 if (getSegments() != null) { 208 builder.setSegments(ExerciseSegmentInternal.getExternalSegments(mExerciseSegments)); 209 } 210 211 builder.setPlannedExerciseSessionId( 212 mPlannedExerciseSessionId == null ? null : mPlannedExerciseSessionId.toString()); 213 return builder.buildWithoutValidation(); 214 } 215 216 @Override populateIntervalRecordTo(@onNull Parcel parcel)217 public void populateIntervalRecordTo(@NonNull Parcel parcel) { 218 parcel.writeString(mNotes); 219 parcel.writeInt(mExerciseType); 220 parcel.writeString(mTitle); 221 parcel.writeBoolean(mHasRoute); 222 ExerciseRouteInternal.writeToParcel(mExerciseRoute, parcel); 223 ExerciseLapInternal.writeLapsToParcel(mExerciseLaps, parcel); 224 ExerciseSegmentInternal.writeSegmentsToParcel(mExerciseSegments, parcel); 225 parcel.writeString( 226 mPlannedExerciseSessionId == null ? null : mPlannedExerciseSessionId.toString()); 227 } 228 229 @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression 230 @Override populateIntervalRecordFrom(@onNull Parcel parcel)231 public void populateIntervalRecordFrom(@NonNull Parcel parcel) { 232 mNotes = parcel.readString(); 233 mExerciseType = parcel.readInt(); 234 mTitle = parcel.readString(); 235 mHasRoute = parcel.readBoolean(); 236 mExerciseRoute = ExerciseRouteInternal.readFromParcel(parcel); 237 mExerciseLaps = ExerciseLapInternal.populateLapsFromParcel(parcel); 238 mExerciseSegments = ExerciseSegmentInternal.populateSegmentsFromParcel(parcel); 239 String uuid = parcel.readString(); 240 mPlannedExerciseSessionId = uuid == null ? null : UUID.fromString(uuid); 241 } 242 243 /** Add route location to the session */ addRouteLocation(ExerciseRouteInternal.LocationInternal location)244 public void addRouteLocation(ExerciseRouteInternal.LocationInternal location) { 245 if (mExerciseRoute == null) { 246 mExerciseRoute = new ExerciseRouteInternal(List.of(location)); 247 mHasRoute = true; 248 } else { 249 mExerciseRoute.addLocation(location); 250 } 251 } 252 } 253