1 /* 2 * Copyright (C) 2022 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.adservices; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.List; 30 31 /** 32 * Represent the result from the getTopics API. 33 * 34 * @hide 35 */ 36 public final class GetTopicsResponse implements Parcelable { 37 /** 38 * Result codes from {@link getTopics} methods. 39 * 40 * @hide 41 */ 42 @IntDef( 43 value = { 44 RESULT_OK, 45 RESULT_INTERNAL_ERROR, 46 RESULT_INVALID_ARGUMENT, 47 RESULT_IO_ERROR, 48 RESULT_RATE_LIMIT_REACHED, 49 }) 50 @Retention(RetentionPolicy.SOURCE) 51 public @interface ResultCode {} 52 53 /** The call was successful. */ 54 public static final int RESULT_OK = 0; 55 56 /** 57 * An internal error occurred within Topics API, which the caller cannot address. 58 * 59 * <p>This error may be considered similar to {@link IllegalStateException} 60 */ 61 public static final int RESULT_INTERNAL_ERROR = 1; 62 63 /** 64 * The caller supplied invalid arguments to the call. 65 * 66 * <p>This error may be considered similar to {@link IllegalArgumentException}. 67 */ 68 public static final int RESULT_INVALID_ARGUMENT = 2; 69 70 /** 71 * An issue occurred reading or writing to storage. The call might succeed if repeated. 72 * 73 * <p>This error may be considered similar to {@link java.io.IOException}. 74 */ 75 public static final int RESULT_IO_ERROR = 3; 76 77 /** 78 * The caller has reached the API call limit. 79 * 80 * <p>The caller should back off and try later. 81 */ 82 public static final int RESULT_RATE_LIMIT_REACHED = 4; 83 84 private final @ResultCode int mResultCode; 85 @Nullable private final String mErrorMessage; 86 private final List<Long> mTaxonomyVersions; 87 private final List<Long> mModelVersions; 88 private final List<String> mTopics; 89 GetTopicsResponse( @esultCode int resultCode, @Nullable String errorMessage, @NonNull List<Long> taxonomyVersions, @NonNull List<Long> modelVersions, @NonNull List<String> topics)90 private GetTopicsResponse( 91 @ResultCode int resultCode, 92 @Nullable String errorMessage, 93 @NonNull List<Long> taxonomyVersions, 94 @NonNull List<Long> modelVersions, 95 @NonNull List<String> topics) { 96 mResultCode = resultCode; 97 mErrorMessage = errorMessage; 98 mTaxonomyVersions = taxonomyVersions; 99 mModelVersions = modelVersions; 100 mTopics = topics; 101 } 102 GetTopicsResponse(@onNull Parcel in)103 private GetTopicsResponse(@NonNull Parcel in) { 104 mResultCode = in.readInt(); 105 mErrorMessage = in.readString(); 106 107 mTaxonomyVersions = Collections.unmodifiableList(readLongList(in)); 108 mModelVersions = Collections.unmodifiableList(readLongList(in)); 109 110 List<String> topicsMutable = new ArrayList<>(); 111 in.readStringList(topicsMutable); 112 mTopics = Collections.unmodifiableList(topicsMutable); 113 } 114 115 public static final @NonNull Creator<GetTopicsResponse> CREATOR = 116 new Parcelable.Creator<GetTopicsResponse>() { 117 @Override 118 public GetTopicsResponse createFromParcel(Parcel in) { 119 return new GetTopicsResponse(in); 120 } 121 122 @Override 123 public GetTopicsResponse[] newArray(int size) { 124 return new GetTopicsResponse[size]; 125 } 126 }; 127 128 /** @hide */ 129 @Override describeContents()130 public int describeContents() { 131 return 0; 132 } 133 134 /** @hide */ 135 @Override writeToParcel(@onNull Parcel out, int flags)136 public void writeToParcel(@NonNull Parcel out, int flags) { 137 out.writeInt(mResultCode); 138 out.writeString(mErrorMessage); 139 writeLongList(out, mTaxonomyVersions); 140 writeLongList(out, mModelVersions); 141 out.writeStringList(mTopics); 142 } 143 144 /** 145 * Returns {@code true} if {@link #getResultCode} equals {@link GetTopicsResponse#RESULT_OK}. 146 */ isSuccess()147 public boolean isSuccess() { 148 return getResultCode() == RESULT_OK; 149 } 150 151 /** Returns one of the {@code RESULT} constants defined in {@link GetTopicsResponse}. */ getResultCode()152 public int getResultCode() { 153 return mResultCode; 154 } 155 156 /** 157 * Returns the error message associated with this result. 158 * 159 * <p>If {@link #isSuccess} is {@code true}, the error message is always {@code null}. The error 160 * message may be {@code null} even if {@link #isSuccess} is {@code false}. 161 */ 162 @Nullable getErrorMessage()163 public String getErrorMessage() { 164 return mErrorMessage; 165 } 166 167 /** Get the Taxonomy Versions. */ getTaxonomyVersions()168 public List<Long> getTaxonomyVersions() { 169 return mTaxonomyVersions; 170 } 171 172 /** Get the Model Versions. */ getModelVersions()173 public List<Long> getModelVersions() { 174 return mModelVersions; 175 } 176 177 @NonNull getTopics()178 public List<String> getTopics() { 179 return mTopics; 180 } 181 182 // Read the list of long from parcel. readLongList(@onNull Parcel in)183 private static List<Long> readLongList(@NonNull Parcel in) { 184 List<Long> list = new ArrayList<>(); 185 186 int toReadCount = in.readInt(); 187 // Negative toReadCount is handled implicitly 188 for (int i = 0; i < toReadCount; i++) { 189 list.add(in.readLong()); 190 } 191 192 return list; 193 } 194 195 // Write a List of Long to parcel. writeLongList(@onNull Parcel out, @Nullable List<Long> val)196 private static void writeLongList(@NonNull Parcel out, @Nullable List<Long> val) { 197 if (val == null) { 198 out.writeInt(-1); 199 return; 200 } 201 out.writeInt(val.size()); 202 for (Long l : val) { 203 out.writeLong(l); 204 } 205 } 206 207 /** 208 * Builder for {@link GetTopicsResponse} objects. 209 * 210 * @hide 211 */ 212 public static final class Builder { 213 private @ResultCode int mResultCode; 214 @Nullable private String mErrorMessage; 215 private List<Long> mTaxonomyVersions = new ArrayList<>(); 216 private List<Long> mModelVersions = new ArrayList<>(); 217 private List<String> mTopics = new ArrayList<>(); 218 Builder()219 public Builder() {} 220 221 /** Set the Result Code. */ setResultCode(@esultCode int resultCode)222 public @NonNull Builder setResultCode(@ResultCode int resultCode) { 223 mResultCode = resultCode; 224 return this; 225 } 226 227 /** Set the Error Message. */ setErrorMessage(@ullable String errorMessage)228 public @NonNull Builder setErrorMessage(@Nullable String errorMessage) { 229 mErrorMessage = errorMessage; 230 return this; 231 } 232 233 /** Set the Taxonomy Version. */ setTaxonomyVersions(@onNull List<Long> taxonomyVersions)234 public @NonNull Builder setTaxonomyVersions(@NonNull List<Long> taxonomyVersions) { 235 mTaxonomyVersions = taxonomyVersions; 236 return this; 237 } 238 239 /** Set the Model Version. */ setModelVersions(@onNull List<Long> modelVersions)240 public @NonNull Builder setModelVersions(@NonNull List<Long> modelVersions) { 241 mModelVersions = modelVersions; 242 return this; 243 } 244 245 /** Set the list of the returned Topics */ setTopics(@onNull List<String> topics)246 public @NonNull Builder setTopics(@NonNull List<String> topics) { 247 mTopics = topics; 248 return this; 249 } 250 251 /** 252 * Builds a {@link GetTopicsResponse} instance. 253 * 254 * <p>throws IllegalArgumentException if any of the params are null or there is any mismatch 255 * in the size of ModelVersions and TaxonomyVersions. 256 */ build()257 public @NonNull GetTopicsResponse build() { 258 if (mTopics == null || mTaxonomyVersions == null || mModelVersions == null) { 259 throw new IllegalArgumentException( 260 "Topics or TaxonomyVersion or ModelVersion is null"); 261 } 262 263 if (mTopics.size() != mTaxonomyVersions.size() 264 || mTopics.size() != mModelVersions.size()) { 265 throw new IllegalArgumentException("Size mismatch in Topics"); 266 } 267 268 return new GetTopicsResponse( 269 mResultCode, mErrorMessage, mTaxonomyVersions, mModelVersions, mTopics); 270 } 271 } 272 } 273