• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.datatypes.MedicalDataSource.validateMedicalDataSourceIds;
20 import static android.health.connect.datatypes.MedicalResource.validateMedicalResourceType;
21 
22 import static com.android.healthfitness.flags.Flags.FLAG_PERSONAL_HEALTH_RECORD;
23 
24 import static java.util.Objects.hash;
25 import static java.util.Objects.requireNonNull;
26 
27 import android.annotation.FlaggedApi;
28 import android.annotation.NonNull;
29 import android.health.connect.datatypes.MedicalDataSource;
30 import android.health.connect.datatypes.MedicalResource;
31 import android.health.connect.datatypes.MedicalResource.MedicalResourceType;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 
35 import java.util.ArrayList;
36 import java.util.HashSet;
37 import java.util.Set;
38 
39 /**
40  * A delete request for {@link HealthConnectManager#deleteMedicalResources}.
41  *
42  * <p>Each field in the request acts as a cumulative filter. So if a set of data sources and a set
43  * of types are specified, then only resources which are both from data sources in the given set and
44  * of types in the given set are deleted.
45  *
46  * <p>At least one filter must be specified - you cannot construct a request to say delete
47  * everything. And for any given requirement set, it must be a non-empty set (empty means the filter
48  * does not exist).
49  */
50 @FlaggedApi(FLAG_PERSONAL_HEALTH_RECORD)
51 public final class DeleteMedicalResourcesRequest implements Parcelable {
52     @NonNull private final Set<String> mDataSourceIds;
53     @NonNull @MedicalResourceType private final Set<Integer> mMedicalResourceTypes;
54 
55     /**
56      * Creates a new instance of {@link DeleteMedicalResourcesRequest}. Please see {@link
57      * DeleteMedicalResourcesRequest.Builder} for more detailed parameters information.
58      */
DeleteMedicalResourcesRequest( @onNull Set<String> dataSourceIds, @NonNull @MedicalResourceType Set<Integer> medicalResourceTypes)59     private DeleteMedicalResourcesRequest(
60             @NonNull Set<String> dataSourceIds,
61             @NonNull @MedicalResourceType Set<Integer> medicalResourceTypes) {
62         if (dataSourceIds.isEmpty() && medicalResourceTypes.isEmpty()) {
63             throw new IllegalArgumentException(
64                     "No restrictions specified for delete. The request must restrict by data source"
65                             + " or resource type");
66         }
67         validateMedicalDataSourceIds(dataSourceIds);
68         medicalResourceTypes.forEach(MedicalResource::validateMedicalResourceType);
69         mDataSourceIds = dataSourceIds;
70         mMedicalResourceTypes = medicalResourceTypes;
71     }
72 
73     /**
74      * Constructs this object with the data present in {@code parcel}. It should be in the same
75      * order as {@link DeleteMedicalResourcesRequest#writeToParcel}.
76      */
DeleteMedicalResourcesRequest(@onNull Parcel in)77     private DeleteMedicalResourcesRequest(@NonNull Parcel in) {
78         requireNonNull(in);
79         ArrayList<String> dataSourceIdList = requireNonNull(in.createStringArrayList());
80         int[] resourceTypes = requireNonNull(in.createIntArray());
81         if (dataSourceIdList.isEmpty() && resourceTypes.length == 0) {
82             throw new IllegalArgumentException("Empty data sources and resource types in parcel");
83         }
84         mDataSourceIds = new HashSet<>(dataSourceIdList);
85         validateMedicalDataSourceIds(mDataSourceIds);
86         mMedicalResourceTypes = new HashSet<>();
87         for (int resourceType : resourceTypes) {
88             validateMedicalResourceType(resourceType);
89             mMedicalResourceTypes.add(resourceType);
90         }
91     }
92 
93     @NonNull
94     public static final Creator<DeleteMedicalResourcesRequest> CREATOR =
95             new Creator<>() {
96                 @Override
97                 public DeleteMedicalResourcesRequest createFromParcel(Parcel in) {
98                     return new DeleteMedicalResourcesRequest(in);
99                 }
100 
101                 @Override
102                 public DeleteMedicalResourcesRequest[] newArray(int size) {
103                     return new DeleteMedicalResourcesRequest[size];
104                 }
105             };
106 
107     /**
108      * Returns the IDs for the {@link MedicalDataSource} that are being requested to delete.
109      *
110      * <p>These IDs should come from {@link HealthConnectManager#createMedicalDataSource}, or other
111      * {@link HealthConnectManager} data source methods.
112      *
113      * <p>If the set is empty it means resources from any data source should be deleted.
114      */
115     @NonNull
getDataSourceIds()116     public Set<String> getDataSourceIds() {
117         return new HashSet<>(mDataSourceIds);
118     }
119 
120     /**
121      * Returns the {@link MedicalResource} types that should be deleted.
122      *
123      * <p>If the set is empty it means resources of all types should be deleted.
124      */
125     @NonNull
126     @MedicalResourceType
getMedicalResourceTypes()127     public Set<Integer> getMedicalResourceTypes() {
128         return new HashSet<>(mMedicalResourceTypes);
129     }
130 
131     @Override
describeContents()132     public int describeContents() {
133         return 0;
134     }
135 
136     @Override
writeToParcel(@onNull Parcel dest, int flags)137     public void writeToParcel(@NonNull Parcel dest, int flags) {
138         dest.writeStringList(new ArrayList<>(mDataSourceIds));
139         dest.writeIntArray(mMedicalResourceTypes.stream().mapToInt(Integer::intValue).toArray());
140     }
141 
142     @Override
equals(Object o)143     public boolean equals(Object o) {
144         if (this == o) return true;
145         if (!(o instanceof DeleteMedicalResourcesRequest that)) return false;
146         return mDataSourceIds.equals(that.mDataSourceIds)
147                 && mMedicalResourceTypes.equals(that.mMedicalResourceTypes);
148     }
149 
150     @Override
hashCode()151     public int hashCode() {
152         return hash(mDataSourceIds, mMedicalResourceTypes);
153     }
154 
155     @Override
toString()156     public String toString() {
157         StringBuilder sb = new StringBuilder();
158         sb.append(this.getClass().getSimpleName()).append("{");
159         sb.append("dataSourceIds=").append(mDataSourceIds);
160         sb.append(",medicalResourceTypes=").append(mMedicalResourceTypes);
161         sb.append("}");
162         return sb.toString();
163     }
164 
165     /** Builder class for {@link DeleteMedicalResourcesRequest}. */
166     public static final class Builder {
167         private final Set<String> mDataSourceIds = new HashSet<>();
168         @MedicalResourceType private final Set<Integer> mMedicalResourceTypes = new HashSet<>();
169 
170         /** Constructs a new {@link DeleteMedicalResourcesRequest.Builder} with no filters. */
Builder()171         public Builder() {}
172 
173         /** Constructs a clone of the other {@link DeleteMedicalResourcesRequest.Builder}. */
Builder(@onNull Builder other)174         public Builder(@NonNull Builder other) {
175             mDataSourceIds.addAll(other.mDataSourceIds);
176             mMedicalResourceTypes.addAll(other.mMedicalResourceTypes);
177         }
178 
179         /** Constructs a clone of the other {@link DeleteMedicalResourcesRequest} instance. */
Builder(@onNull DeleteMedicalResourcesRequest other)180         public Builder(@NonNull DeleteMedicalResourcesRequest other) {
181             mDataSourceIds.addAll(other.getDataSourceIds());
182             mMedicalResourceTypes.addAll(other.getMedicalResourceTypes());
183         }
184 
185         /**
186          * Adds the data source ID to request to delete. This should be an ID of the existing {@link
187          * MedicalDataSource}.
188          *
189          * <p>If the set of data source IDs is empty, it means resources from any data source should
190          * be deleted.
191          *
192          * @throws IllegalArgumentException if the provided {@code dataSourceId} is not a valid ID.
193          */
194         @NonNull
addDataSourceId(@onNull String dataSourceId)195         public Builder addDataSourceId(@NonNull String dataSourceId) {
196             mDataSourceIds.add(requireNonNull(dataSourceId));
197             validateMedicalDataSourceIds(Set.of(dataSourceId));
198             return this;
199         }
200 
201         /**
202          * Adds the medical resource type to request to delete.
203          *
204          * @throws IllegalArgumentException if the provided {@code resourceType} is not supported.
205          */
206         @NonNull
addMedicalResourceType(@edicalResourceType int resourceType)207         public Builder addMedicalResourceType(@MedicalResourceType int resourceType) {
208             validateMedicalResourceType(resourceType);
209             mMedicalResourceTypes.add(resourceType);
210             return this;
211         }
212 
213         /** Clears all data source IDs. */
214         @NonNull
clearDataSourceIds()215         public Builder clearDataSourceIds() {
216             mDataSourceIds.clear();
217             return this;
218         }
219 
220         /** Clears all medical resource types. */
221         @NonNull
clearMedicalResourceTypes()222         public Builder clearMedicalResourceTypes() {
223             mMedicalResourceTypes.clear();
224             return this;
225         }
226 
227         /**
228          * Returns a new instance of {@link DeleteMedicalResourcesRequest} with the specified
229          * parameters.
230          *
231          * @throws IllegalArgumentException if no data source IDs or medical resource types have
232          *     been added.
233          */
234         @NonNull
build()235         public DeleteMedicalResourcesRequest build() {
236             return new DeleteMedicalResourcesRequest(mDataSourceIds, mMedicalResourceTypes);
237         }
238     }
239 }
240