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