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.datatypes; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.health.connect.datatypes.units.Length; 22 import android.health.connect.datatypes.validation.ValidationUtils; 23 import android.health.connect.internal.datatypes.ExerciseLapInternal; 24 25 import java.time.Instant; 26 import java.util.Objects; 27 28 /** 29 * Captures the time of a lap within exercise session. Part of {@link ExerciseSessionRecord}. 30 * 31 * <p>Each record contains the start and end time and optional {@link Length} of the lap (e.g. pool 32 * length while swimming or a track lap while running). There may or may not be direct correlation 33 * with {@link ExerciseSegment} start and end times, e.g. {@link ExerciseSessionRecord} of type 34 * running without any segments can be divided as laps of different lengths. 35 */ 36 public final class ExerciseLap implements TimeInterval.TimeIntervalHolder { 37 private static final int MAX_LAP_LENGTH_METRES = 1000000; 38 39 private final TimeInterval mInterval; 40 private final Length mLength; 41 42 @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression ExerciseLap( @onNull TimeInterval interval, @Nullable Length length, boolean skipValidation)43 private ExerciseLap( 44 @NonNull TimeInterval interval, @Nullable Length length, boolean skipValidation) { 45 Objects.requireNonNull(interval); 46 if (!skipValidation) { 47 ValidationUtils.requireInRangeIfExists( 48 length, 49 Length.fromMeters(0.0), 50 Length.fromMeters(MAX_LAP_LENGTH_METRES), 51 "length"); 52 } 53 mInterval = interval; 54 mLength = length; 55 } 56 57 /* 58 * Returns Length of the lap. 59 */ 60 @Nullable getLength()61 public Length getLength() { 62 return mLength; 63 } 64 65 /* 66 * Returns start time of the lap. 67 */ 68 @NonNull getStartTime()69 public Instant getStartTime() { 70 return mInterval.getStartTime(); 71 } 72 73 /* 74 * Returns end time of the lap. 75 */ 76 @NonNull getEndTime()77 public Instant getEndTime() { 78 return mInterval.getEndTime(); 79 } 80 81 /** @hide */ 82 @Override getInterval()83 public TimeInterval getInterval() { 84 return mInterval; 85 } 86 87 /** @hide */ getType()88 public int getType() { 89 return 0; 90 } 91 92 @Override equals(Object o)93 public boolean equals(Object o) { 94 if (this == o) return true; 95 if (!(o instanceof ExerciseLap)) return false; 96 ExerciseLap that = (ExerciseLap) o; 97 return Objects.equals(mInterval, that.mInterval) 98 && Objects.equals(getLength(), that.getLength()); 99 } 100 101 @Override hashCode()102 public int hashCode() { 103 return Objects.hash(mInterval, getLength()); 104 } 105 106 /** @hide */ 107 @NonNull toExerciseLapInternal()108 public ExerciseLapInternal toExerciseLapInternal() { 109 ExerciseLapInternal internalLap = 110 new ExerciseLapInternal() 111 .setStarTime(getStartTime().toEpochMilli()) 112 .setEndTime(getEndTime().toEpochMilli()); 113 if (getLength() != null) { 114 internalLap.setLength(getLength().getInMeters()); 115 } 116 117 return internalLap; 118 } 119 120 /** Builder class for {@link ExerciseLap} */ 121 public static final class Builder { 122 private final TimeInterval mInterval; 123 private Length mLength; 124 125 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression Builder(@onNull Instant startTime, @NonNull Instant endTime)126 public Builder(@NonNull Instant startTime, @NonNull Instant endTime) { 127 mInterval = new TimeInterval(startTime, endTime); 128 } 129 130 /** 131 * Sets the length of this lap 132 * 133 * @param length Length of the lap, in {@link Length} unit. Optional field. Valid range: 134 * 0-1000000 meters. 135 */ 136 @NonNull setLength(@onNull Length length)137 public ExerciseLap.Builder setLength(@NonNull Length length) { 138 Objects.requireNonNull(length); 139 mLength = length; 140 return this; 141 } 142 143 /** 144 * @return Object of {@link ExerciseLap} without validating the values. 145 * @hide 146 */ 147 @NonNull buildWithoutValidation()148 public ExerciseLap buildWithoutValidation() { 149 return new ExerciseLap(mInterval, mLength, true); 150 } 151 152 /** Builds {@link ExerciseLap} instance. */ 153 @NonNull build()154 public ExerciseLap build() { 155 return new ExerciseLap(mInterval, mLength, false); 156 } 157 } 158 } 159