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.adselection;
18 
19 import static android.adservices.adselection.AdSelectionOutcome.UNSET_AD_SELECTION_ID;
20 import static android.adservices.adselection.AdSelectionOutcome.UNSET_AD_SELECTION_ID_MESSAGE;
21 import static android.adservices.common.FrequencyCapFilters.AD_EVENT_TYPE_WIN;
22 
23 import android.adservices.common.AdTechIdentifier;
24 import android.adservices.common.FrequencyCapFilters;
25 import android.annotation.NonNull;
26 import android.os.OutcomeReceiver;
27 
28 import com.android.internal.util.Preconditions;
29 
30 import java.util.Objects;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * Request object wrapping the required arguments needed to update an ad counter histogram.
35  *
36  * <p>The ad counter histograms, which are historical logs of events which are associated with an ad
37  * counter key and an ad event type, are used to inform frequency cap filtering when using the
38  * Protected Audience APIs.
39  */
40 public class UpdateAdCounterHistogramRequest {
41     /** @hide */
42     public static final String UNSET_AD_EVENT_TYPE_MESSAGE = "Ad event type must be set";
43 
44     /** @hide */
45     public static final String DISALLOW_AD_EVENT_TYPE_WIN_MESSAGE =
46             "Win event types cannot be manually updated";
47 
48     /** @hide */
49     public static final String INVALID_AD_EVENT_TYPE_MESSAGE =
50             "Ad event type must be one of AD_EVENT_TYPE_IMPRESSION, AD_EVENT_TYPE_VIEW, or"
51                     + " AD_EVENT_TYPE_CLICK";
52 
53     /** @hide */
54     public static final String UNSET_CALLER_ADTECH_MESSAGE = "Caller ad tech must not be null";
55 
56     private final long mAdSelectionId;
57     @FrequencyCapFilters.AdEventType private final int mAdEventType;
58     @NonNull private final AdTechIdentifier mCallerAdTech;
59 
UpdateAdCounterHistogramRequest(@onNull Builder builder)60     private UpdateAdCounterHistogramRequest(@NonNull Builder builder) {
61         Objects.requireNonNull(builder);
62 
63         mAdSelectionId = builder.mAdSelectionId;
64         mAdEventType = builder.mAdEventType;
65         mCallerAdTech = builder.mCallerAdTech;
66     }
67 
68     /**
69      * Gets the ad selection ID with which the rendered ad's events are associated.
70      *
71      * <p>For more information about the ad selection ID, see {@link AdSelectionOutcome}.
72      *
73      * <p>The ad must have been selected from Protected Audience ad selection in the last 24 hours,
74      * and the ad selection call must have been initiated from the same app as the current calling
75      * app. Event histograms for all ad counter keys associated with the ad specified by the ad
76      * selection ID will be updated for the ad event type from {@link #getAdEventType()}, to be used
77      * in Protected Audience frequency cap filtering.
78      */
getAdSelectionId()79     public long getAdSelectionId() {
80         return mAdSelectionId;
81     }
82 
83     /**
84      * Gets the ad event type which, along with an ad's counter keys, identifies which histogram
85      * should be updated.
86      */
87     @FrequencyCapFilters.AdEventType
getAdEventType()88     public int getAdEventType() {
89         return mAdEventType;
90     }
91 
92     /**
93      * Gets the caller adtech entity's {@link AdTechIdentifier}.
94      *
95      * <p>The adtech using this {@link UpdateAdCounterHistogramRequest} object must have enrolled
96      * with the Privacy Sandbox and be allowed to act on behalf of the calling app. The specified
97      * adtech is not required to be the same adtech as either the buyer which owns the rendered ad
98      * or the seller which initiated the ad selection associated with the ID returned by {@link
99      * #getAdSelectionId()}.
100      *
101      * <p>For more information about API requirements and exceptions, see {@link
102      * AdSelectionManager#updateAdCounterHistogram(UpdateAdCounterHistogramRequest, Executor,
103      * OutcomeReceiver)}.
104      */
105     @NonNull
getCallerAdTech()106     public AdTechIdentifier getCallerAdTech() {
107         return mCallerAdTech;
108     }
109 
110     /**
111      * Checks whether the {@link UpdateAdCounterHistogramRequest} objects contain the same
112      * information.
113      */
114     @Override
equals(Object o)115     public boolean equals(Object o) {
116         if (this == o) return true;
117         if (!(o instanceof UpdateAdCounterHistogramRequest)) return false;
118         UpdateAdCounterHistogramRequest that = (UpdateAdCounterHistogramRequest) o;
119         return mAdSelectionId == that.mAdSelectionId
120                 && mAdEventType == that.mAdEventType
121                 && mCallerAdTech.equals(that.mCallerAdTech);
122     }
123 
124     /** Returns the hash of the {@link UpdateAdCounterHistogramRequest} object's data. */
125     @Override
hashCode()126     public int hashCode() {
127         return Objects.hash(mAdSelectionId, mAdEventType, mCallerAdTech);
128     }
129 
130     @Override
toString()131     public String toString() {
132         return "UpdateAdCounterHistogramRequest{"
133                 + "mAdSelectionId="
134                 + mAdSelectionId
135                 + ", mAdEventType="
136                 + mAdEventType
137                 + ", mCallerAdTech="
138                 + mCallerAdTech
139                 + '}';
140     }
141 
142     /** Builder for {@link UpdateAdCounterHistogramRequest} objects. */
143     public static final class Builder {
144         private long mAdSelectionId;
145         @FrequencyCapFilters.AdEventType private int mAdEventType;
146         @NonNull private AdTechIdentifier mCallerAdTech;
147 
Builder( long adSelectionId, int adEventType, @NonNull AdTechIdentifier callerAdTech)148         public Builder(
149                 long adSelectionId, int adEventType, @NonNull AdTechIdentifier callerAdTech) {
150             Preconditions.checkArgument(
151                     adSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
152             Preconditions.checkArgument(
153                     adEventType != AD_EVENT_TYPE_WIN, DISALLOW_AD_EVENT_TYPE_WIN_MESSAGE);
154             Preconditions.checkArgument(
155                     adEventType >= FrequencyCapFilters.AD_EVENT_TYPE_MIN
156                             && adEventType <= FrequencyCapFilters.AD_EVENT_TYPE_MAX,
157                     INVALID_AD_EVENT_TYPE_MESSAGE);
158             Objects.requireNonNull(callerAdTech, UNSET_CALLER_ADTECH_MESSAGE);
159 
160             mAdSelectionId = adSelectionId;
161             mAdEventType = adEventType;
162             mCallerAdTech = callerAdTech;
163         }
164 
165         /**
166          * Sets the ad selection ID with which the rendered ad's events are associated.
167          *
168          * <p>See {@link #getAdSelectionId()} for more information.
169          */
170         @NonNull
setAdSelectionId(long adSelectionId)171         public Builder setAdSelectionId(long adSelectionId) {
172             Preconditions.checkArgument(
173                     adSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
174             mAdSelectionId = adSelectionId;
175             return this;
176         }
177 
178         /**
179          * Sets the ad event type which, along with an ad's counter keys, identifies which histogram
180          * should be updated.
181          *
182          * <p>See {@link #getAdEventType()} for more information.
183          */
184         @NonNull
setAdEventType(@requencyCapFilters.AdEventType int adEventType)185         public Builder setAdEventType(@FrequencyCapFilters.AdEventType int adEventType) {
186             Preconditions.checkArgument(
187                     adEventType != AD_EVENT_TYPE_WIN, DISALLOW_AD_EVENT_TYPE_WIN_MESSAGE);
188             Preconditions.checkArgument(
189                     adEventType >= FrequencyCapFilters.AD_EVENT_TYPE_MIN
190                             && adEventType <= FrequencyCapFilters.AD_EVENT_TYPE_MAX,
191                     INVALID_AD_EVENT_TYPE_MESSAGE);
192             mAdEventType = adEventType;
193             return this;
194         }
195 
196         /**
197          * Sets the caller adtech entity's {@link AdTechIdentifier}.
198          *
199          * <p>See {@link #getCallerAdTech()} for more information.
200          */
201         @NonNull
setCallerAdTech(@onNull AdTechIdentifier callerAdTech)202         public Builder setCallerAdTech(@NonNull AdTechIdentifier callerAdTech) {
203             Objects.requireNonNull(callerAdTech, UNSET_CALLER_ADTECH_MESSAGE);
204             mCallerAdTech = callerAdTech;
205             return this;
206         }
207 
208         /** Builds the {@link UpdateAdCounterHistogramRequest} object. */
209         @NonNull
build()210         public UpdateAdCounterHistogramRequest build() {
211             return new UpdateAdCounterHistogramRequest(this);
212         }
213     }
214 }
215