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.DEFAULT_LONG; 20 import static android.health.connect.Constants.DEFAULT_PAGE_SIZE; 21 import static android.health.connect.Constants.MAXIMUM_PAGE_SIZE; 22 import static android.health.connect.Constants.MINIMUM_PAGE_SIZE; 23 24 import android.annotation.IntRange; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.health.connect.aidl.ReadRecordsRequestParcel; 28 import android.health.connect.datatypes.DataOrigin; 29 import android.health.connect.datatypes.Record; 30 import android.os.OutcomeReceiver; 31 import android.util.ArraySet; 32 33 import java.util.Objects; 34 import java.util.Set; 35 import java.util.concurrent.Executor; 36 37 /** 38 * Class to represent a request based on time range and data origin filters for {@link 39 * HealthConnectManager#readRecords(ReadRecordsRequest, Executor, OutcomeReceiver)} 40 * 41 * @param <T> the type of the Record for the request 42 */ 43 public final class ReadRecordsRequestUsingFilters<T extends Record> extends ReadRecordsRequest<T> { 44 private final TimeRangeFilter mTimeRangeFilter; 45 private final Set<DataOrigin> mDataOrigins; 46 private final int mPageSize; 47 private final long mPageToken; 48 private final boolean mAscending; 49 50 /** 51 * @see Builder 52 */ ReadRecordsRequestUsingFilters( @onNull TimeRangeFilter timeRangeFilter, @NonNull Class<T> recordType, @NonNull Set<DataOrigin> dataOrigins, int pageSize, long pageToken, boolean ascending)53 private ReadRecordsRequestUsingFilters( 54 @NonNull TimeRangeFilter timeRangeFilter, 55 @NonNull Class<T> recordType, 56 @NonNull Set<DataOrigin> dataOrigins, 57 int pageSize, 58 long pageToken, 59 boolean ascending) { 60 super(recordType); 61 Objects.requireNonNull(dataOrigins); 62 mTimeRangeFilter = timeRangeFilter; 63 mDataOrigins = dataOrigins; 64 mPageSize = pageSize; 65 mAscending = PageTokenWrapper.from(pageToken, ascending).isAscending(); 66 mPageToken = pageToken; 67 } 68 69 /** Returns time range b/w which the read operation is to be performed */ 70 @Nullable getTimeRangeFilter()71 public TimeRangeFilter getTimeRangeFilter() { 72 return mTimeRangeFilter; 73 } 74 75 /** 76 * Returns the set of {@link DataOrigin data origins} to be read, or empty list for no filter 77 */ 78 @NonNull getDataOrigins()79 public Set<DataOrigin> getDataOrigins() { 80 return mDataOrigins; 81 } 82 83 /** Returns maximum number of records to be returned by the read operation */ 84 @IntRange(from = 1, to = 5000) getPageSize()85 public int getPageSize() { 86 return mPageSize; 87 } 88 89 /** Returns page token to read the current page of the result. -1 if none available */ getPageToken()90 public long getPageToken() { 91 return mPageToken; 92 } 93 94 /** Returns ordering of results to be returned */ isAscending()95 public boolean isAscending() { 96 return mAscending; 97 } 98 99 /** 100 * Returns an object of ReadRecordsRequestParcel to carry read request 101 * 102 * @hide 103 */ 104 @NonNull toReadRecordsRequestParcel()105 public ReadRecordsRequestParcel toReadRecordsRequestParcel() { 106 return new ReadRecordsRequestParcel(this); 107 } 108 109 /** Builder class for {@link ReadRecordsRequestUsingFilters} */ 110 public static final class Builder<T extends Record> { 111 private final Class<T> mRecordType; 112 private final Set<DataOrigin> mDataOrigins = new ArraySet<>(); 113 private TimeRangeFilter mTimeRangeFilter; 114 private int mPageSize = DEFAULT_PAGE_SIZE; 115 private long mPageToken = DEFAULT_LONG; 116 private boolean mAscending = true; 117 private boolean mIsOrderingSet = false; 118 119 /** 120 * @param recordType Class object of {@link Record} type that needs to be read 121 */ 122 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression Builder(@onNull Class<T> recordType)123 public Builder(@NonNull Class<T> recordType) { 124 Objects.requireNonNull(recordType); 125 126 mRecordType = recordType; 127 } 128 129 /** 130 * Sets the data origin filter based on which the read operation is to be performed 131 * 132 * @param dataOrigin Adds {@link DataOrigin} for which to read records. 133 * <p>If no {@link DataOrigin} is added then records by all {@link DataOrigin}s will be 134 * read 135 */ 136 @NonNull addDataOrigins(@onNull DataOrigin dataOrigin)137 public Builder<T> addDataOrigins(@NonNull DataOrigin dataOrigin) { 138 Objects.requireNonNull(dataOrigin); 139 mDataOrigins.add(dataOrigin); 140 141 return this; 142 } 143 144 /** 145 * Sets time range b/w which the read operation is to be performed 146 * 147 * @param timeRangeFilter Time range b/w which the read operation is to be performed. 148 * <p>If not time range filter is present all the records will be read without any time 149 * constraints. 150 */ 151 @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression 152 @NonNull setTimeRangeFilter(@ullable TimeRangeFilter timeRangeFilter)153 public Builder<T> setTimeRangeFilter(@Nullable TimeRangeFilter timeRangeFilter) { 154 mTimeRangeFilter = timeRangeFilter; 155 return this; 156 } 157 158 /** 159 * Sets maximum number of records to be returned by the read operation 160 * 161 * @param pageSize number of records to be returned by the read operation. 162 * <p>This sets to limit number of rows returned by a read. If not set default is 1000 163 * and maximum of 5000 records can be sent. 164 */ 165 @NonNull setPageSize(@ntRangefrom = 1, to = 5000) int pageSize)166 public Builder<T> setPageSize(@IntRange(from = 1, to = 5000) int pageSize) { 167 if (pageSize < MINIMUM_PAGE_SIZE || pageSize > MAXIMUM_PAGE_SIZE) { 168 throw new IllegalArgumentException( 169 "Valid pageSize range is " 170 + MINIMUM_PAGE_SIZE 171 + " - " 172 + MAXIMUM_PAGE_SIZE 173 + ", requested " 174 + pageSize); 175 } 176 mPageSize = pageSize; 177 return this; 178 } 179 180 /** 181 * Sets page token to read the requested page of the result. 182 * 183 * @param pageToken to read the requested page of the result. -1 if none available 184 */ 185 @NonNull setPageToken(long pageToken)186 public Builder<T> setPageToken(long pageToken) { 187 mPageToken = pageToken; 188 return this; 189 } 190 191 /** 192 * Sets ordering of results to be returned based on start time. Ordering cannot be set along 193 * with page token for subsequent requests. IllegalState exception is thrown when ordering 194 * is set along with the page token. 195 * 196 * @param ascending specifies sorting order of results, if set to true records are sorted on 197 * start time in ascending fashion, else if set to false then in descending. 198 */ 199 @NonNull setAscending(boolean ascending)200 public Builder<T> setAscending(boolean ascending) { 201 mAscending = ascending; 202 mIsOrderingSet = true; 203 return this; 204 } 205 206 /** 207 * Returns an Object of {@link ReadRecordsRequestUsingFilters} 208 * 209 * <p>For subsequent read requests, {@link ReadRecordsRequestUsingFilters} does not allow 210 * both pageToken and sort order to be set together. 211 * 212 * <p>If pageToken is set then records will be sorted in same order as the previous result 213 * 214 * <p>If both pageToken and sortOrder are not set then by default records will be sorted by 215 * start time in ascending order. 216 * 217 * @throws IllegalStateException if both pageToken and sort order is set. 218 */ 219 @NonNull build()220 public ReadRecordsRequestUsingFilters<T> build() { 221 if (mPageToken != DEFAULT_LONG && mIsOrderingSet) { 222 throw new IllegalStateException("Cannot set both pageToken and sort order"); 223 } 224 return new ReadRecordsRequestUsingFilters<>( 225 mTimeRangeFilter, mRecordType, mDataOrigins, mPageSize, mPageToken, mAscending); 226 } 227 } 228 } 229