• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package android.health.connect.datatypes;
17 
18 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEIGHT;
19 
20 import android.annotation.NonNull;
21 import android.health.connect.HealthConnectManager;
22 import android.health.connect.datatypes.units.Length;
23 import android.health.connect.datatypes.validation.ValidationUtils;
24 import android.health.connect.internal.datatypes.HeightRecordInternal;
25 
26 import java.time.Instant;
27 import java.time.ZoneOffset;
28 import java.util.Objects;
29 
30 /** Captures the user's height. */
31 @Identifier(recordIdentifier = RecordTypeIdentifier.RECORD_TYPE_HEIGHT)
32 public final class HeightRecord extends InstantRecord {
33 
34     private final Length mHeight;
35 
36     /**
37      * Metric identifier to get average height using aggregate APIs in {@link HealthConnectManager}
38      */
39     @android.annotation.NonNull
40     public static final AggregationType<Length> HEIGHT_AVG =
41             new AggregationType<>(
42                     AggregationType.AggregationTypeIdentifier.HEIGHT_RECORD_HEIGHT_AVG,
43                     AggregationType.AVG,
44                     RECORD_TYPE_HEIGHT,
45                     Length.class);
46 
47     /**
48      * Metric identifier to get minimum height using aggregate APIs in {@link HealthConnectManager}
49      */
50     @android.annotation.NonNull
51     public static final AggregationType<Length> HEIGHT_MIN =
52             new AggregationType<>(
53                     AggregationType.AggregationTypeIdentifier.HEIGHT_RECORD_HEIGHT_MIN,
54                     AggregationType.MIN,
55                     RECORD_TYPE_HEIGHT,
56                     Length.class);
57 
58     /**
59      * Metric identifier to get maximum height using aggregate APIs in {@link HealthConnectManager}
60      */
61     @android.annotation.NonNull
62     public static final AggregationType<Length> HEIGHT_MAX =
63             new AggregationType<>(
64                     AggregationType.AggregationTypeIdentifier.HEIGHT_RECORD_HEIGHT_MAX,
65                     AggregationType.MAX,
66                     RECORD_TYPE_HEIGHT,
67                     Length.class);
68 
69     /**
70      * @param metadata Metadata to be associated with the record. See {@link Metadata}.
71      * @param time Start time of this activity
72      * @param zoneOffset Zone offset of the user when the activity started
73      * @param height Height of this activity
74      * @param skipValidation Boolean flag to skip validation of record values.
75      */
HeightRecord( @onNull Metadata metadata, @NonNull Instant time, @NonNull ZoneOffset zoneOffset, @NonNull Length height, boolean skipValidation)76     private HeightRecord(
77             @NonNull Metadata metadata,
78             @NonNull Instant time,
79             @NonNull ZoneOffset zoneOffset,
80             @NonNull Length height,
81             boolean skipValidation) {
82         super(metadata, time, zoneOffset, skipValidation);
83         Objects.requireNonNull(metadata);
84         Objects.requireNonNull(time);
85         Objects.requireNonNull(zoneOffset);
86         Objects.requireNonNull(height);
87         if (!skipValidation) {
88             ValidationUtils.requireInRange(height.getInMeters(), 0.0, 3.0, "height");
89         }
90         mHeight = height;
91     }
92     /**
93      * @return height in {@link Length} unit.
94      */
95     @NonNull
getHeight()96     public Length getHeight() {
97         return mHeight;
98     }
99 
100     /**
101      * Indicates whether some other object is "equal to" this one.
102      *
103      * @param o the reference object with which to compare.
104      * @return {@code true} if this object is the same as the obj
105      */
106     @Override
equals(Object o)107     public boolean equals(Object o) {
108         if (this == o) return true;
109         if (!super.equals(o)) return false;
110         HeightRecord that = (HeightRecord) o;
111         return getHeight().equals(that.getHeight());
112     }
113 
114     /** Returns a hash code value for the object. */
115     @Override
hashCode()116     public int hashCode() {
117         return Objects.hash(super.hashCode(), getHeight());
118     }
119 
120     /** Builder class for {@link HeightRecord} */
121     public static final class Builder {
122         private final Metadata mMetadata;
123         private final Instant mTime;
124         private ZoneOffset mZoneOffset;
125         private final Length mHeight;
126 
127         /**
128          * @param metadata Metadata to be associated with the record. See {@link Metadata}.
129          * @param time Start time of this activity
130          * @param height Height in {@link Length} unit. Required field. Valid range: 0-3 meters.
131          */
Builder(@onNull Metadata metadata, @NonNull Instant time, @NonNull Length height)132         public Builder(@NonNull Metadata metadata, @NonNull Instant time, @NonNull Length height) {
133             Objects.requireNonNull(metadata);
134             Objects.requireNonNull(time);
135             Objects.requireNonNull(height);
136             mMetadata = metadata;
137             mTime = time;
138             mHeight = height;
139             mZoneOffset = ZoneOffset.systemDefault().getRules().getOffset(time);
140         }
141 
142         /** Sets the zone offset of the user when the activity happened */
143         @NonNull
setZoneOffset(@onNull ZoneOffset zoneOffset)144         public Builder setZoneOffset(@NonNull ZoneOffset zoneOffset) {
145             Objects.requireNonNull(zoneOffset);
146             mZoneOffset = zoneOffset;
147             return this;
148         }
149 
150         /** Sets the zone offset of this record to system default. */
151         @NonNull
clearZoneOffset()152         public Builder clearZoneOffset() {
153             mZoneOffset = RecordUtils.getDefaultZoneOffset();
154             return this;
155         }
156 
157         /**
158          * @return Object of {@link HeightRecord} without validating the values.
159          * @hide
160          */
161         @NonNull
buildWithoutValidation()162         public HeightRecord buildWithoutValidation() {
163             return new HeightRecord(mMetadata, mTime, mZoneOffset, mHeight, true);
164         }
165 
166         /**
167          * @return Object of {@link HeightRecord}
168          */
169         @NonNull
build()170         public HeightRecord build() {
171             return new HeightRecord(mMetadata, mTime, mZoneOffset, mHeight, false);
172         }
173     }
174 
175     /** @hide */
176     @Override
toRecordInternal()177     public HeightRecordInternal toRecordInternal() {
178         HeightRecordInternal recordInternal =
179                 (HeightRecordInternal)
180                         new HeightRecordInternal()
181                                 .setUuid(getMetadata().getId())
182                                 .setPackageName(getMetadata().getDataOrigin().getPackageName())
183                                 .setLastModifiedTime(
184                                         getMetadata().getLastModifiedTime().toEpochMilli())
185                                 .setClientRecordId(getMetadata().getClientRecordId())
186                                 .setClientRecordVersion(getMetadata().getClientRecordVersion())
187                                 .setManufacturer(getMetadata().getDevice().getManufacturer())
188                                 .setModel(getMetadata().getDevice().getModel())
189                                 .setDeviceType(getMetadata().getDevice().getType())
190                                 .setRecordingMethod(getMetadata().getRecordingMethod());
191         recordInternal.setTime(getTime().toEpochMilli());
192         recordInternal.setZoneOffset(getZoneOffset().getTotalSeconds());
193         recordInternal.setHeight(mHeight.getInMeters());
194         return recordInternal;
195     }
196 }
197