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