• 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 
17 package android.health.connect.datatypes;
18 
19 import static android.health.connect.datatypes.validation.ValidationUtils.validateIntDefValue;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.time.Instant;
28 import java.util.Objects;
29 import java.util.Set;
30 
31 /** Set of shared metadata fields for {@link Record} */
32 public final class Metadata {
33     /** Unknown recording method. */
34     public static final int RECORDING_METHOD_UNKNOWN = 0;
35 
36     /**
37      * For actively recorded data by the user.
38      *
39      * <p>For e.g. An exercise session actively recorded by the user using a phone or a watch
40      * device.
41      */
42     public static final int RECORDING_METHOD_ACTIVELY_RECORDED = 1;
43 
44     /**
45      * For passively recorded data by the app.
46      *
47      * <p>For e.g. Steps data recorded by a watch or phone without the user starting a session.
48      */
49     public static final int RECORDING_METHOD_AUTOMATICALLY_RECORDED = 2;
50 
51     /**
52      * For manually entered data by the user.
53      *
54      * <p>For e.g. Nutrition or weight data entered by the user.
55      */
56     public static final int RECORDING_METHOD_MANUAL_ENTRY = 3;
57     /**
58      * Valid set of values for this IntDef. Update this set when add new type or deprecate existing
59      * type.
60      *
61      * @hide
62      */
63     public static final Set<Integer> VALID_TYPES =
64             Set.of(
65                     RECORDING_METHOD_UNKNOWN,
66                     RECORDING_METHOD_ACTIVELY_RECORDED,
67                     RECORDING_METHOD_AUTOMATICALLY_RECORDED,
68                     RECORDING_METHOD_MANUAL_ENTRY);
69 
70     private final Device mDevice;
71     private final DataOrigin mDataOrigin;
72     private final Instant mLastModifiedTime;
73     private final String mClientRecordId;
74     private final long mClientRecordVersion;
75     @RecordingMethod private final int mRecordingMethod;
76     private String mId;
77 
78     /**
79      * @param device Optional client supplied device information associated with the data.
80      * @param dataOrigin Where the data comes from, such as application information originally
81      *     generated this data. When {@link Record} is created before insertion, this contains a
82      *     sentinel value, any assigned value will be ignored. After insertion, this will be
83      *     populated with inserted application.
84      * @param id Unique identifier of this data, assigned by the Android Health Platform at
85      *     insertion time. When {@link Record} is created before insertion, this takes a sentinel
86      *     value, any assigned value will be ignored.
87      * @param lastModifiedTime Automatically populated to when data was last modified (or originally
88      *     created). When {@link Record} is created before inserted, this contains a sentinel value,
89      *     any assigned value will be ignored.
90      * @param clientRecordId Optional client supplied record unique data identifier associated with
91      *     the data. There is guaranteed a single entry for any type of data with same client
92      *     provided identifier for a given client. Any new insertions with the same client provided
93      *     identifier will either replace or be ignored depending on associated {@code
94      *     clientRecordVersion}. @see clientRecordVersion
95      * @param clientRecordVersion Optional client supplied version associated with the data. This
96      *     determines conflict resolution outcome when there are multiple insertions of the same
97      *     {@code clientRecordId}. Data with the highest {@code clientRecordVersion} takes
98      *     precedence. {@code clientRecordVersion} starts with 0. @see clientRecordId
99      * @param recordingMethod Optional client supplied data recording method to help to understand
100      *     how the data was recorded.
101      */
Metadata( Device device, DataOrigin dataOrigin, String id, Instant lastModifiedTime, String clientRecordId, long clientRecordVersion, @RecordingMethod int recordingMethod)102     private Metadata(
103             Device device,
104             DataOrigin dataOrigin,
105             String id,
106             Instant lastModifiedTime,
107             String clientRecordId,
108             long clientRecordVersion,
109             @RecordingMethod int recordingMethod) {
110         validateIntDefValue(recordingMethod, VALID_TYPES, RecordingMethod.class.getSimpleName());
111         mDevice = device;
112         mDataOrigin = dataOrigin;
113         mId = id;
114         mLastModifiedTime = lastModifiedTime;
115         mClientRecordId = clientRecordId;
116         mClientRecordVersion = clientRecordVersion;
117         mRecordingMethod = recordingMethod;
118     }
119 
120     /**
121      * @return Client record ID if set, null otherwise
122      */
123     @Nullable
getClientRecordId()124     public String getClientRecordId() {
125         return mClientRecordId;
126     }
127 
128     /**
129      * @return Client record version if set, 0 otherwise
130      */
getClientRecordVersion()131     public long getClientRecordVersion() {
132         return mClientRecordVersion;
133     }
134 
135     /**
136      * @return Corresponds to package name if set. If no data origin is set {@code
137      *     getDataOrigin().getPackageName()} will return null
138      */
139     @NonNull
getDataOrigin()140     public DataOrigin getDataOrigin() {
141         return mDataOrigin;
142     }
143 
144     /**
145      * @return Record identifier if set, empty string otherwise
146      */
147     @NonNull
getId()148     public String getId() {
149         return mId;
150     }
151 
152     /**
153      * Sets record identifier
154      *
155      * @hide
156      */
setId(@onNull String id)157     public void setId(@NonNull String id) {
158         Objects.requireNonNull(id);
159 
160         mId = id;
161     }
162 
163     /** Returns recording method which indicates how data was recorded for the {@link Record} */
164     @RecordingMethod
getRecordingMethod()165     public int getRecordingMethod() {
166         return mRecordingMethod;
167     }
168 
169     /**
170      * @return Record's last modified time if set, Instant.EPOCH otherwise
171      */
172     @NonNull
getLastModifiedTime()173     public Instant getLastModifiedTime() {
174         return mLastModifiedTime;
175     }
176 
177     /**
178      * @return The device details that contributed to this record
179      */
180     @NonNull
getDevice()181     public Device getDevice() {
182         return mDevice;
183     }
184 
185     /**
186      * Indicates whether some other object is "equal to" this one.
187      *
188      * @param object the reference object with which to compare.
189      * @return {@code true} if this object is the same as the obj
190      */
191     @Override
equals(@onNull Object object)192     public boolean equals(@NonNull Object object) {
193         if (this == object) return true;
194         if (object instanceof Metadata) {
195             Metadata other = (Metadata) object;
196             return getDevice().equals(other.getDevice())
197                     && getDataOrigin().equals(other.getDataOrigin())
198                     && getId().equals(other.getId())
199                     && Objects.equals(getClientRecordId(), other.getClientRecordId())
200                     && getClientRecordVersion() == other.getClientRecordVersion()
201                     && getRecordingMethod() == other.getRecordingMethod();
202         }
203         return false;
204     }
205 
206     /**
207      * Returns a hash code value for the object.
208      *
209      * @return a hash code value for this object.
210      */
211     @Override
hashCode()212     public int hashCode() {
213         return Objects.hash(
214                 getDevice(),
215                 getDataOrigin(),
216                 getId(),
217                 getClientRecordId(),
218                 getClientRecordVersion(),
219                 getLastModifiedTime(),
220                 getRecordingMethod());
221     }
222 
223     /**
224      * List of possible Recording method for the {@link Record}.
225      *
226      * @hide
227      */
228     @IntDef({
229         RECORDING_METHOD_UNKNOWN,
230         RECORDING_METHOD_ACTIVELY_RECORDED,
231         RECORDING_METHOD_AUTOMATICALLY_RECORDED,
232         RECORDING_METHOD_MANUAL_ENTRY
233     })
234     @Retention(RetentionPolicy.SOURCE)
235     public @interface RecordingMethod {}
236 
237     /**
238      * @see Metadata
239      */
240     public static final class Builder {
241         private Device mDevice = new Device.Builder().build();
242         private DataOrigin mDataOrigin = new DataOrigin.Builder().build();
243         private String mId = "";
244         private Instant mLastModifiedTime = Instant.EPOCH;
245         private String mClientRecordId;
246         private long mClientRecordVersion = 0;
247 
248         @RecordingMethod private int mRecordingMethod = RECORDING_METHOD_UNKNOWN;
249 
Builder()250         public Builder() {}
251 
252         /** Sets optional client supplied device information associated with the data. */
253         @NonNull
setDevice(@onNull Device device)254         public Builder setDevice(@NonNull Device device) {
255             Objects.requireNonNull(device);
256 
257             mDevice = device;
258             return this;
259         }
260 
261         /**
262          * Sets where the data comes from, such as application information originally generated this
263          * data. When {@link Record} is created before insertion, this contains a sentinel value,
264          * any assigned value will be ignored. After insertion, this will be populated with inserted
265          * application.
266          */
267         @NonNull
setDataOrigin(@onNull DataOrigin dataOrigin)268         public Builder setDataOrigin(@NonNull DataOrigin dataOrigin) {
269             Objects.requireNonNull(dataOrigin);
270 
271             mDataOrigin = dataOrigin;
272             return this;
273         }
274 
275         /**
276          * Sets unique identifier of this data, assigned by the Android Health Platform at insertion
277          * time. When {@link Record} is created before insertion, this takes a sentinel value, any
278          * assigned value will be ignored.
279          */
280         @NonNull
setId(@onNull String id)281         public Builder setId(@NonNull String id) {
282             Objects.requireNonNull(id);
283 
284             mId = id;
285             return this;
286         }
287 
288         /**
289          * Sets when data was last modified (or originally created). When {@link Record} is created
290          * before inserted, this contains a sentinel value, any assigned value will be ignored.
291          */
292         @NonNull
setLastModifiedTime(@onNull Instant lastModifiedTime)293         public Builder setLastModifiedTime(@NonNull Instant lastModifiedTime) {
294             Objects.requireNonNull(lastModifiedTime);
295 
296             mLastModifiedTime = lastModifiedTime;
297             return this;
298         }
299 
300         /**
301          * Sets optional client supplied record unique data identifier associated with the data.
302          * There is guaranteed a single entry for any type of data with same client provided
303          * identifier for a given client. Any new insertions with the same client provided
304          * identifier will either replace or be ignored depending on associated {@code
305          * clientRecordVersion}. @see clientRecordVersion
306          *
307          * <p>A null value means that no clientRecordId is set
308          */
309         @NonNull
setClientRecordId(@ullable String clientRecordId)310         public Builder setClientRecordId(@Nullable String clientRecordId) {
311             mClientRecordId = clientRecordId;
312             return this;
313         }
314 
315         /**
316          * Sets optional client supplied version associated with the data. This determines conflict
317          * resolution outcome when there are multiple insertions of the same {@code clientRecordId}.
318          * Data with the highest {@code clientRecordVersion} takes precedence. {@code
319          * clientRecordVersion} starts with 0. @see clientRecordId
320          */
321         @NonNull
setClientRecordVersion(long clientRecordVersion)322         public Builder setClientRecordVersion(long clientRecordVersion) {
323             mClientRecordVersion = clientRecordVersion;
324             return this;
325         }
326 
327         /**
328          * Sets recording method for the {@link Record}. This detail helps to know how the data was
329          * recorded which can be useful for prioritization of the record
330          */
331         @NonNull
setRecordingMethod(@ecordingMethod int recordingMethod)332         public Builder setRecordingMethod(@RecordingMethod int recordingMethod) {
333 
334             mRecordingMethod = recordingMethod;
335             return this;
336         }
337 
338         /**
339          * @return {@link Metadata} object
340          */
341         @NonNull
build()342         public Metadata build() {
343             return new Metadata(
344                     mDevice,
345                     mDataOrigin,
346                     mId,
347                     mLastModifiedTime,
348                     mClientRecordId,
349                     mClientRecordVersion,
350                     mRecordingMethod);
351         }
352     }
353 }
354