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.AggregationType.AggregationTypeIdentifier.WHEEL_CHAIR_PUSHES_RECORD_COUNT_TOTAL;
19 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_WHEELCHAIR_PUSHES;
20 
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.health.connect.HealthConnectManager;
25 import android.health.connect.datatypes.validation.ValidationUtils;
26 import android.health.connect.internal.datatypes.WheelchairPushesRecordInternal;
27 
28 import java.time.Instant;
29 import java.time.ZoneOffset;
30 import java.util.Objects;
31 
32 /**
33  * Captures the number of wheelchair pushes done over a time interval. Each push is only reported
34  * once so records shouldn't have overlapping time. The start time of each record should represent
35  * the start of the interval in which pushes were made.
36  */
37 @Identifier(recordIdentifier = RECORD_TYPE_WHEELCHAIR_PUSHES)
38 public final class WheelchairPushesRecord extends IntervalRecord {
39 
40     private final long mCount;
41 
42     /**
43      * Metric identifier to get total wheelchair push count using aggregate APIs in {@link
44      * HealthConnectManager}
45      */
46     @android.annotation.NonNull
47     public static final AggregationType<Long> WHEEL_CHAIR_PUSHES_COUNT_TOTAL =
48             new AggregationType<>(
49                     WHEEL_CHAIR_PUSHES_RECORD_COUNT_TOTAL,
50                     AggregationType.SUM,
51                     RECORD_TYPE_WHEELCHAIR_PUSHES,
52                     Long.class);
53 
54     /**
55      * @param metadata Metadata to be associated with the record. See {@link Metadata}.
56      * @param startTime Start time of this activity
57      * @param startZoneOffset Zone offset of the user when the activity started
58      * @param endTime End time of this activity
59      * @param endZoneOffset Zone offset of the user when the activity finished
60      * @param count Count of pushes
61      * @param skipValidation Boolean flag to skip validation of record values.
62      */
WheelchairPushesRecord( @onNull Metadata metadata, @NonNull Instant startTime, @NonNull ZoneOffset startZoneOffset, @NonNull Instant endTime, @NonNull ZoneOffset endZoneOffset, long count, boolean skipValidation)63     private WheelchairPushesRecord(
64             @NonNull Metadata metadata,
65             @NonNull Instant startTime,
66             @NonNull ZoneOffset startZoneOffset,
67             @NonNull Instant endTime,
68             @NonNull ZoneOffset endZoneOffset,
69             long count,
70             boolean skipValidation) {
71         super(
72                 metadata,
73                 startTime,
74                 startZoneOffset,
75                 endTime,
76                 endZoneOffset,
77                 skipValidation,
78                 /* enforceFutureTimeRestrictions= */ true);
79         Objects.requireNonNull(metadata);
80         Objects.requireNonNull(startTime);
81         Objects.requireNonNull(startZoneOffset);
82         Objects.requireNonNull(startTime);
83         Objects.requireNonNull(endZoneOffset);
84         if (!skipValidation) {
85             ValidationUtils.requireInRange(count, 0, 1000000, "count");
86         }
87         mCount = count;
88     }
89 
90     /**
91      * @return wheelchair pushes count.
92      */
getCount()93     public long getCount() {
94         return mCount;
95     }
96 
97     /**
98      * Indicates whether some other object is "equal to" this one.
99      *
100      * @param object the reference object with which to compare.
101      * @return {@code true} if this object is the same as the object argument; {@code false}
102      *     otherwise.
103      */
104     @Override
equals(@ullable Object object)105     public boolean equals(@Nullable Object object) {
106         if (super.equals(object) && object instanceof WheelchairPushesRecord) {
107             WheelchairPushesRecord other = (WheelchairPushesRecord) object;
108             return this.getCount() == other.getCount();
109         }
110         return false;
111     }
112 
113     /** Returns a hash code value for the object. */
114     @Override
hashCode()115     public int hashCode() {
116         return Objects.hash(super.hashCode(), this.getCount());
117     }
118 
119     /** Builder class for {@link WheelchairPushesRecord} */
120     public static final class Builder {
121         private final Metadata mMetadata;
122         private final Instant mStartTime;
123         private final Instant mEndTime;
124         private ZoneOffset mStartZoneOffset;
125         private ZoneOffset mEndZoneOffset;
126         private final long mCount;
127 
128         /**
129          * @param metadata Metadata to be associated with the record. See {@link Metadata}.
130          * @param startTime Start time of this activity
131          * @param endTime End time of this activity
132          * @param count Count of pushes. Required field. Valid range: 1-1000000.
133          */
Builder( @onNull Metadata metadata, @NonNull Instant startTime, @NonNull Instant endTime, @IntRange(from = 1, to = 1000000) long count)134         public Builder(
135                 @NonNull Metadata metadata,
136                 @NonNull Instant startTime,
137                 @NonNull Instant endTime,
138                 @IntRange(from = 1, to = 1000000) long count) {
139             Objects.requireNonNull(metadata);
140             Objects.requireNonNull(startTime);
141             Objects.requireNonNull(endTime);
142             mMetadata = metadata;
143             mStartTime = startTime;
144             mEndTime = endTime;
145             mCount = count;
146             mStartZoneOffset = ZoneOffset.systemDefault().getRules().getOffset(startTime);
147             mEndZoneOffset = ZoneOffset.systemDefault().getRules().getOffset(endTime);
148         }
149 
150         /** Sets the zone offset of the user when the activity started */
151         @NonNull
setStartZoneOffset(@onNull ZoneOffset startZoneOffset)152         public Builder setStartZoneOffset(@NonNull ZoneOffset startZoneOffset) {
153             Objects.requireNonNull(startZoneOffset);
154 
155             mStartZoneOffset = startZoneOffset;
156             return this;
157         }
158 
159         /** Sets the zone offset of the user when the activity ended */
160         @NonNull
setEndZoneOffset(@onNull ZoneOffset endZoneOffset)161         public Builder setEndZoneOffset(@NonNull ZoneOffset endZoneOffset) {
162             Objects.requireNonNull(endZoneOffset);
163 
164             mEndZoneOffset = endZoneOffset;
165             return this;
166         }
167 
168         /** Sets the start zone offset of this record to system default. */
169         @NonNull
clearStartZoneOffset()170         public Builder clearStartZoneOffset() {
171             mStartZoneOffset = RecordUtils.getDefaultZoneOffset();
172             return this;
173         }
174 
175         /** Sets the start zone offset of this record to system default. */
176         @NonNull
clearEndZoneOffset()177         public Builder clearEndZoneOffset() {
178             mEndZoneOffset = RecordUtils.getDefaultZoneOffset();
179             return this;
180         }
181 
182         /**
183          * @return Object of {@link WheelchairPushesRecord} without validating the values.
184          * @hide
185          */
186         @NonNull
buildWithoutValidation()187         public WheelchairPushesRecord buildWithoutValidation() {
188             return new WheelchairPushesRecord(
189                     mMetadata,
190                     mStartTime,
191                     mStartZoneOffset,
192                     mEndTime,
193                     mEndZoneOffset,
194                     mCount,
195                     true);
196         }
197 
198         /**
199          * @return Object of {@link WheelchairPushesRecord}
200          */
201         @NonNull
build()202         public WheelchairPushesRecord build() {
203             return new WheelchairPushesRecord(
204                     mMetadata,
205                     mStartTime,
206                     mStartZoneOffset,
207                     mEndTime,
208                     mEndZoneOffset,
209                     mCount,
210                     false);
211         }
212     }
213 
214     /** @hide */
215     @Override
toRecordInternal()216     public WheelchairPushesRecordInternal toRecordInternal() {
217         WheelchairPushesRecordInternal recordInternal =
218                 (WheelchairPushesRecordInternal)
219                         new WheelchairPushesRecordInternal()
220                                 .setUuid(getMetadata().getId())
221                                 .setPackageName(getMetadata().getDataOrigin().getPackageName())
222                                 .setLastModifiedTime(
223                                         getMetadata().getLastModifiedTime().toEpochMilli())
224                                 .setClientRecordId(getMetadata().getClientRecordId())
225                                 .setClientRecordVersion(getMetadata().getClientRecordVersion())
226                                 .setManufacturer(getMetadata().getDevice().getManufacturer())
227                                 .setModel(getMetadata().getDevice().getModel())
228                                 .setDeviceType(getMetadata().getDevice().getType())
229                                 .setRecordingMethod(getMetadata().getRecordingMethod());
230         recordInternal.setStartTime(getStartTime().toEpochMilli());
231         recordInternal.setEndTime(getEndTime().toEpochMilli());
232         recordInternal.setStartZoneOffset(getStartZoneOffset().getTotalSeconds());
233         recordInternal.setEndZoneOffset(getEndZoneOffset().getTotalSeconds());
234         recordInternal.setCount((int) mCount);
235         return recordInternal;
236     }
237 }
238