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.adservices.common; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import com.android.adservices.AdServicesParcelableUtil; 26 import com.android.adservices.flags.Flags; 27 28 import org.json.JSONException; 29 import org.json.JSONObject; 30 31 import java.util.Objects; 32 33 /** 34 * A container class for filters which are associated with an ad. 35 * 36 * <p>If any of the filters in an {@link AdFilters} instance are not satisfied, the associated ad 37 * will not be eligible for ad selection. Filters are optional ad parameters and are not required as 38 * part of {@link AdData}. 39 */ 40 public final class AdFilters implements Parcelable { 41 /** @hide */ 42 public static final String FREQUENCY_CAP_FIELD_NAME = "frequency_cap"; 43 /** @hide */ 44 public static final String APP_INSTALL_FIELD_NAME = "app_install"; 45 /** @hide */ 46 @Nullable private final FrequencyCapFilters mFrequencyCapFilters; 47 48 @Nullable private final AppInstallFilters mAppInstallFilters; 49 50 @NonNull 51 public static final Creator<AdFilters> CREATOR = 52 new Creator<AdFilters>() { 53 @Override 54 public AdFilters createFromParcel(@NonNull Parcel in) { 55 Objects.requireNonNull(in); 56 return new AdFilters(in); 57 } 58 59 @Override 60 public AdFilters[] newArray(int size) { 61 return new AdFilters[size]; 62 } 63 }; 64 AdFilters(@onNull Builder builder)65 private AdFilters(@NonNull Builder builder) { 66 Objects.requireNonNull(builder); 67 68 mFrequencyCapFilters = builder.mFrequencyCapFilters; 69 mAppInstallFilters = builder.mAppInstallFilters; 70 } 71 AdFilters(@onNull Parcel in)72 private AdFilters(@NonNull Parcel in) { 73 Objects.requireNonNull(in); 74 75 mFrequencyCapFilters = 76 AdServicesParcelableUtil.readNullableFromParcel( 77 in, FrequencyCapFilters.CREATOR::createFromParcel); 78 mAppInstallFilters = 79 AdServicesParcelableUtil.readNullableFromParcel( 80 in, AppInstallFilters.CREATOR::createFromParcel); 81 } 82 83 /** 84 * Gets the {@link FrequencyCapFilters} instance that represents all frequency cap filters for 85 * the ad. 86 * 87 * <p>If {@code null}, there are no frequency cap filters which apply to the ad. 88 */ 89 @Nullable getFrequencyCapFilters()90 public FrequencyCapFilters getFrequencyCapFilters() { 91 return mFrequencyCapFilters; 92 } 93 94 /** 95 * Gets the {@link AppInstallFilters} instance that represents all app install filters for the 96 * ad. 97 * 98 * <p>If {@code null}, there are no app install filters which apply to the ad. 99 */ 100 @FlaggedApi(Flags.FLAG_FLEDGE_AD_SELECTION_FILTERING_ENABLED) 101 @Nullable getAppInstallFilters()102 public AppInstallFilters getAppInstallFilters() { 103 return mAppInstallFilters; 104 } 105 106 /** 107 * @return The estimated size of this object, in bytes. 108 * @hide 109 */ getSizeInBytes()110 public int getSizeInBytes() { 111 int size = 0; 112 if (mFrequencyCapFilters != null) { 113 size += mFrequencyCapFilters.getSizeInBytes(); 114 } 115 if (mAppInstallFilters != null) { 116 size += mAppInstallFilters.getSizeInBytes(); 117 } 118 return size; 119 } 120 121 /** 122 * A JSON serializer. 123 * 124 * @return A JSON serialization of this object. 125 * @hide 126 */ toJson()127 public JSONObject toJson() throws JSONException { 128 JSONObject toReturn = new JSONObject(); 129 if (mFrequencyCapFilters != null) { 130 toReturn.put(FREQUENCY_CAP_FIELD_NAME, mFrequencyCapFilters.toJson()); 131 } 132 if (mAppInstallFilters != null) { 133 toReturn.put(APP_INSTALL_FIELD_NAME, mAppInstallFilters.toJson()); 134 } 135 return toReturn; 136 } 137 138 /** 139 * A JSON de-serializer. 140 * 141 * @param json A JSON representation of an {@link AdFilters} object as would be generated by 142 * {@link #toJson()}. 143 * @return An {@link AdFilters} object generated from the given JSON. 144 * @hide 145 */ fromJson(JSONObject json)146 public static AdFilters fromJson(JSONObject json) throws JSONException { 147 Builder builder = new Builder(); 148 if (json.has(FREQUENCY_CAP_FIELD_NAME)) { 149 builder.setFrequencyCapFilters( 150 FrequencyCapFilters.fromJson(json.getJSONObject(FREQUENCY_CAP_FIELD_NAME))); 151 } 152 if (json.has(APP_INSTALL_FIELD_NAME)) { 153 builder.setAppInstallFilters( 154 AppInstallFilters.fromJson(json.getJSONObject(APP_INSTALL_FIELD_NAME))); 155 } 156 return builder.build(); 157 } 158 159 @Override writeToParcel(@onNull Parcel dest, int flags)160 public void writeToParcel(@NonNull Parcel dest, int flags) { 161 Objects.requireNonNull(dest); 162 163 AdServicesParcelableUtil.writeNullableToParcel( 164 dest, 165 mFrequencyCapFilters, 166 (targetParcel, sourceFilters) -> sourceFilters.writeToParcel(targetParcel, flags)); 167 AdServicesParcelableUtil.writeNullableToParcel( 168 dest, 169 mAppInstallFilters, 170 (targetParcel, sourceFilters) -> sourceFilters.writeToParcel(targetParcel, flags)); 171 } 172 173 /** @hide */ 174 @Override describeContents()175 public int describeContents() { 176 return 0; 177 } 178 179 /** Checks whether the {@link AdFilters} objects represent the same set of filters. */ 180 @Override equals(Object o)181 public boolean equals(Object o) { 182 if (this == o) return true; 183 if (!(o instanceof AdFilters)) return false; 184 AdFilters adFilters = (AdFilters) o; 185 return Objects.equals(mFrequencyCapFilters, adFilters.mFrequencyCapFilters) 186 && Objects.equals(mAppInstallFilters, adFilters.mAppInstallFilters); 187 } 188 189 /** Returns the hash of the {@link AdFilters} object's data. */ 190 @Override hashCode()191 public int hashCode() { 192 return Objects.hash(mFrequencyCapFilters, mAppInstallFilters); 193 } 194 195 @Override toString()196 public String toString() { 197 return "AdFilters{" 198 + "mFrequencyCapFilters=" 199 + mFrequencyCapFilters 200 + ", mAppInstallFilters=" 201 + mAppInstallFilters 202 + '}'; 203 } 204 205 /** Builder for creating {@link AdFilters} objects. */ 206 public static final class Builder { 207 @Nullable private FrequencyCapFilters mFrequencyCapFilters; 208 @Nullable private AppInstallFilters mAppInstallFilters; 209 Builder()210 public Builder() {} 211 212 /** 213 * Sets the {@link FrequencyCapFilters} which will apply to the ad. 214 * 215 * <p>If set to {@code null} or not set, no frequency cap filters will be associated with 216 * the ad. 217 */ 218 @NonNull setFrequencyCapFilters(@ullable FrequencyCapFilters frequencyCapFilters)219 public Builder setFrequencyCapFilters(@Nullable FrequencyCapFilters frequencyCapFilters) { 220 mFrequencyCapFilters = frequencyCapFilters; 221 return this; 222 } 223 224 /** 225 * Sets the {@link AppInstallFilters} which will apply to the ad. 226 * 227 * <p>If set to {@code null} or not set, no app install filters will be associated with the 228 * ad. 229 */ 230 @FlaggedApi(Flags.FLAG_FLEDGE_AD_SELECTION_FILTERING_ENABLED) 231 @NonNull setAppInstallFilters(@ullable AppInstallFilters appInstallFilters)232 public Builder setAppInstallFilters(@Nullable AppInstallFilters appInstallFilters) { 233 mAppInstallFilters = appInstallFilters; 234 return this; 235 } 236 237 /** Builds and returns an {@link AdFilters} instance. */ 238 @NonNull build()239 public AdFilters build() { 240 return new AdFilters(this); 241 } 242 } 243 } 244