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;
18 
19 import static android.health.connect.Constants.MAXIMUM_PAGE_SIZE;
20 
21 import android.annotation.NonNull;
22 import android.annotation.SuppressLint;
23 import android.health.connect.aidl.ReadRecordsRequestParcel;
24 import android.health.connect.datatypes.Metadata;
25 import android.health.connect.datatypes.Record;
26 import android.os.OutcomeReceiver;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Objects;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * A request class to represent request based on {@link RecordIdFilter RecordIdFilters} for {@link
35  * HealthConnectManager#readRecords(ReadRecordsRequest, Executor, OutcomeReceiver)}
36  *
37  * <p>A {@link RecordIdFilter} can be constructed with either {@link RecordIdFilter#fromId(Class,
38  * String) record ID} or {@link RecordIdFilter#fromClientRecordId(Class, String) client record ID}.
39  * However, it's worth noting that only reading with own client record IDs is allowed, using client
40  * record IDs to read records inserted by another app will return no result.
41  *
42  * @param <T> the type of the Record for the request
43  */
44 public final class ReadRecordsRequestUsingIds<T extends Record> extends ReadRecordsRequest<T> {
45     /** List of {@link RecordIdFilter} */
46     private final List<RecordIdFilter> mRecordIdFiltersList;
47 
48     /**
49      * @see Builder
50      */
ReadRecordsRequestUsingIds( @onNull Class<T> recordType, @NonNull List<RecordIdFilter> recordIdFiltersList)51     private ReadRecordsRequestUsingIds(
52             @NonNull Class<T> recordType, @NonNull List<RecordIdFilter> recordIdFiltersList) {
53         super(recordType);
54         Objects.requireNonNull(recordIdFiltersList);
55         mRecordIdFiltersList = recordIdFiltersList;
56     }
57 
58     /** Returns List of RecordId */
59     @NonNull
getRecordIdFilters()60     public List<RecordIdFilter> getRecordIdFilters() {
61         return mRecordIdFiltersList;
62     }
63 
64     /**
65      * Returns an object of ReadRecordsRequestParcel to carry read request
66      *
67      * @hide
68      */
69     @NonNull
toReadRecordsRequestParcel()70     public ReadRecordsRequestParcel toReadRecordsRequestParcel() {
71         return new ReadRecordsRequestParcel(this);
72     }
73 
74     /** Builder class for {@link ReadRecordsRequestUsingIds} */
75     public static final class Builder<T extends Record> {
76         private final Class<T> mRecordType;
77         private final List<RecordIdFilter> mRecordIdFiltersList = new ArrayList<>();
78 
79         /**
80          * @param recordType Record class for which the id is being set
81          */
Builder(@onNull Class<T> recordType)82         public Builder(@NonNull Class<T> recordType) {
83             Objects.requireNonNull(recordType);
84 
85             mRecordType = recordType;
86         }
87 
88         /**
89          * Add an UUID to the read request.
90          *
91          * <p>The maximum number of ids in a single {@link ReadRecordsRequestUsingIds} that Health
92          * Connect accepts is 5000. The limit includes all {@code id}s and {@code clientId}s.
93          *
94          * @param id Identifier generated by the platform and returned by {@link
95          *     HealthConnectManager#insertRecords}
96          * @see #addClientRecordId(String)
97          */
98         @NonNull
99         @SuppressLint("MissingGetterMatchingBuilder")
addId(@onNull String id)100         public Builder<T> addId(@NonNull String id) {
101             if (mRecordIdFiltersList.size() >= MAXIMUM_PAGE_SIZE) {
102                 throw new IllegalArgumentException(
103                         "Maximum allowed pageSize is " + MAXIMUM_PAGE_SIZE);
104             }
105             mRecordIdFiltersList.add(RecordIdFilter.fromId(mRecordType, id));
106             return this;
107         }
108 
109         /**
110          * Add a client id to the read request.
111          *
112          * <p>The maximum number of ids in a single {@link ReadRecordsRequestUsingIds} that Health
113          * Connect accepts is 5000. The limit includes all {@code id}s and {@code clientId}s.
114          *
115          * @param clientRecordId identifier that was set while inserting the record
116          * @see Metadata
117          * @see #addId(String)
118          */
119         @SuppressLint("MissingGetterMatchingBuilder")
120         @NonNull
addClientRecordId(@onNull String clientRecordId)121         public Builder<T> addClientRecordId(@NonNull String clientRecordId) {
122             if (mRecordIdFiltersList.size() >= MAXIMUM_PAGE_SIZE) {
123                 throw new IllegalArgumentException(
124                         "Maximum allowed pageSize is " + MAXIMUM_PAGE_SIZE);
125             }
126             mRecordIdFiltersList.add(
127                     RecordIdFilter.fromClientRecordId(mRecordType, clientRecordId));
128             return this;
129         }
130 
131         /** Returns Object of {@link ReadRecordsRequestUsingIds} */
132         @NonNull
build()133         public ReadRecordsRequestUsingIds<T> build() {
134             if (mRecordIdFiltersList.isEmpty()) {
135                 throw new IllegalArgumentException(
136                         "RecordIdFilter list is empty, "
137                                 + "Either record id or client record id must be set");
138             }
139             return new ReadRecordsRequestUsingIds<>(mRecordType, mRecordIdFiltersList);
140         }
141     }
142 }
143