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.aidl; 18 19 import static android.health.connect.Constants.DEFAULT_INT; 20 import static android.health.connect.Constants.DEFAULT_LONG; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.health.connect.AggregateRecordsRequest; 25 import android.health.connect.LocalTimeRangeFilter; 26 import android.health.connect.TimeInstantRangeFilter; 27 import android.health.connect.TimeRangeFilter; 28 import android.health.connect.TimeRangeFilterHelper; 29 import android.health.connect.datatypes.AggregationType; 30 import android.health.connect.datatypes.DataOrigin; 31 import android.os.Parcel; 32 import android.os.Parcelable; 33 34 import java.time.Duration; 35 import java.time.Instant; 36 import java.time.Period; 37 import java.util.List; 38 import java.util.stream.Collectors; 39 40 /** @hide */ 41 public class AggregateDataRequestParcel implements Parcelable { 42 public static final Creator<AggregateDataRequestParcel> CREATOR = 43 new Creator<>() { 44 @Override 45 public AggregateDataRequestParcel createFromParcel(Parcel in) { 46 return new AggregateDataRequestParcel(in); 47 } 48 49 @Override 50 public AggregateDataRequestParcel[] newArray(int size) { 51 return new AggregateDataRequestParcel[size]; 52 } 53 }; 54 private final long mStartTime; 55 private final long mEndTime; 56 private final int[] mAggregateIds; 57 private final List<String> mPackageFilters; 58 // If set represents that the aggregations have to be grouped by on {@code mDuration} 59 private Duration mDuration; 60 // If set represents that the aggregations have to be grouped by on {@code mPeriod}. If both are 61 // set the duration takes precedence, but there should not be case when both are set. 62 private Period mPeriod; 63 64 private final boolean mLocalTimeFilter; 65 66 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression AggregateDataRequestParcel(AggregateRecordsRequest<?> request)67 public AggregateDataRequestParcel(AggregateRecordsRequest<?> request) { 68 mStartTime = TimeRangeFilterHelper.getFilterStartTimeMillis(request.getTimeRangeFilter()); 69 mEndTime = TimeRangeFilterHelper.getFilterEndTimeMillis(request.getTimeRangeFilter()); 70 mAggregateIds = new int[request.getAggregationTypes().size()]; 71 mLocalTimeFilter = TimeRangeFilterHelper.isLocalTimeFilter(request.getTimeRangeFilter()); 72 73 int i = 0; 74 for (AggregationType<?> aggregationType : request.getAggregationTypes()) { 75 mAggregateIds[i++] = aggregationType.getAggregationTypeIdentifier(); 76 } 77 mPackageFilters = 78 request.getDataOriginsFilters().stream() 79 .map(DataOrigin::getPackageName) 80 .collect(Collectors.toList()); 81 // Use durations group by single queries as it support null values 82 mDuration = Duration.ofMillis(mEndTime - mStartTime); 83 } 84 AggregateDataRequestParcel(AggregateRecordsRequest request, Duration duration)85 public AggregateDataRequestParcel(AggregateRecordsRequest request, Duration duration) { 86 this(request); 87 mDuration = duration; 88 } 89 90 @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression AggregateDataRequestParcel(AggregateRecordsRequest request, Period period)91 public AggregateDataRequestParcel(AggregateRecordsRequest request, Period period) { 92 this(request); 93 mDuration = null; 94 mPeriod = period; 95 96 if (!TimeRangeFilterHelper.isLocalTimeFilter(request.getTimeRangeFilter())) { 97 throw new UnsupportedOperationException( 98 "For period requests should use LocalTimeRangeFilter"); 99 } 100 } 101 102 @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression AggregateDataRequestParcel(Parcel in)103 protected AggregateDataRequestParcel(Parcel in) { 104 mStartTime = in.readLong(); 105 mEndTime = in.readLong(); 106 mLocalTimeFilter = in.readBoolean(); 107 mAggregateIds = in.createIntArray(); 108 mPackageFilters = in.createStringArrayList(); 109 int periodDays = in.readInt(); 110 if (periodDays != DEFAULT_INT) { 111 int periodMonths = in.readInt(); 112 int periodYears = in.readInt(); 113 mPeriod = Period.of(periodYears, periodMonths, periodDays); 114 } 115 116 long duration = in.readLong(); 117 if (duration != DEFAULT_LONG) { 118 mDuration = Duration.ofMillis(duration); 119 } 120 } 121 122 @Nullable getDuration()123 public Duration getDuration() { 124 return mDuration; 125 } 126 127 @Nullable getPeriod()128 public Period getPeriod() { 129 return mPeriod; 130 } 131 132 /** Returns whether this request uses {@link LocalTimeRangeFilter}. */ useLocalTimeFilter()133 public boolean useLocalTimeFilter() { 134 return mLocalTimeFilter; 135 } 136 137 @Override describeContents()138 public int describeContents() { 139 return 0; 140 } 141 142 @Override writeToParcel(@onNull Parcel dest, int flags)143 public void writeToParcel(@NonNull Parcel dest, int flags) { 144 dest.writeLong(mStartTime); 145 dest.writeLong(mEndTime); 146 dest.writeBoolean(mLocalTimeFilter); 147 dest.writeIntArray(mAggregateIds); 148 dest.writeStringList(mPackageFilters); 149 if (mPeriod != null) { 150 dest.writeInt(mPeriod.getDays()); 151 dest.writeInt(mPeriod.getMonths()); 152 dest.writeInt(mPeriod.getYears()); 153 } else { 154 dest.writeInt(DEFAULT_INT); 155 } 156 157 if (mDuration != null) { 158 dest.writeLong(mDuration.toMillis()); 159 } else { 160 dest.writeLong(DEFAULT_LONG); 161 } 162 } 163 getStartTime()164 public long getStartTime() { 165 return mStartTime; 166 } 167 getEndTime()168 public long getEndTime() { 169 return mEndTime; 170 } 171 getAggregateIds()172 public int[] getAggregateIds() { 173 return mAggregateIds; 174 } 175 176 @NonNull getPackageFilters()177 public List<String> getPackageFilters() { 178 return mPackageFilters; 179 } 180 181 @NonNull getTimeRangeFilter()182 public TimeRangeFilter getTimeRangeFilter() { 183 if (mLocalTimeFilter) { 184 return new LocalTimeRangeFilter.Builder() 185 .setStartTime(TimeRangeFilterHelper.getLocalTimeFromMillis(mStartTime)) 186 .setEndTime(TimeRangeFilterHelper.getLocalTimeFromMillis(mEndTime)) 187 .build(); 188 } else { 189 return new TimeInstantRangeFilter.Builder() 190 .setStartTime(Instant.ofEpochMilli(mStartTime)) 191 .setEndTime(Instant.ofEpochMilli(mEndTime)) 192 .build(); 193 } 194 } 195 } 196