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