• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 import android.annotation.FlaggedApi;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.view.InputEvent;
27 
28 import com.android.adservices.flags.Flags;
29 import com.android.internal.util.Preconditions;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.nio.charset.StandardCharsets;
34 import java.util.Objects;
35 
36 /**
37  * Request object wrapping the required arguments needed to report an ad event.
38  */
39 public class ReportEventRequest {
40     /** This is used to represent seller as the destination for report event API */
41     public static final int FLAG_REPORTING_DESTINATION_SELLER = 1 << 0;
42 
43     /** This is used to represent buyer as the destination for report event API. */
44     public static final int FLAG_REPORTING_DESTINATION_BUYER = 1 << 1;
45 
46     /** This is used to component seller as the destination for report event API */
47     @FlaggedApi(Flags.FLAG_FLEDGE_ENABLE_REPORT_EVENT_FOR_COMPONENT_SELLER)
48     public static final int FLAG_REPORTING_DESTINATION_COMPONENT_SELLER = 1 << 2;
49 
50     private static final int UNSET_REPORTING_DESTINATIONS = 0;
51     private static final String UNSET_REPORTING_DESTINATIONS_MESSAGE =
52             "Reporting destinations bitfield not set.";
53     private static final String INVALID_REPORTING_DESTINATIONS_MESSAGE =
54             "Invalid reporting destinations bitfield!";
55 
56     /** @hide */
57     public static final long REPORT_EVENT_MAX_INTERACTION_DATA_SIZE_B = 64 * 1024; // 64 KB
58 
59     private static final String EVENT_DATA_SIZE_MAX_EXCEEDED =
60             "Event data should not exceed " + REPORT_EVENT_MAX_INTERACTION_DATA_SIZE_B + " bytes";
61 
62     private final long mAdSelectionId;
63     @NonNull private final String mEventKey;
64     @Nullable private final InputEvent mInputEvent;
65     @NonNull private final String mEventData;
66 
67     @ReportingDestination
68     private final int mReportingDestinations; // buyer, seller, component seller or all
69 
ReportEventRequest(@onNull Builder builder)70     private ReportEventRequest(@NonNull Builder builder) {
71         Objects.requireNonNull(builder);
72 
73         Preconditions.checkArgument(
74                 builder.mAdSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
75         Preconditions.checkArgument(
76                 builder.mReportingDestinations != UNSET_REPORTING_DESTINATIONS,
77                 UNSET_REPORTING_DESTINATIONS_MESSAGE);
78         Preconditions.checkArgument(
79                 isValidDestination(builder.mReportingDestinations),
80                 INVALID_REPORTING_DESTINATIONS_MESSAGE);
81         Preconditions.checkArgument(
82                 builder.mEventData.getBytes(StandardCharsets.UTF_8).length
83                         <= REPORT_EVENT_MAX_INTERACTION_DATA_SIZE_B,
84                 EVENT_DATA_SIZE_MAX_EXCEEDED);
85 
86         this.mAdSelectionId = builder.mAdSelectionId;
87         this.mEventKey = builder.mEventKey;
88         this.mInputEvent = builder.mInputEvent;
89         this.mEventData = builder.mEventData;
90         this.mReportingDestinations = builder.mReportingDestinations;
91     }
92 
93     /**
94      * Returns the adSelectionId, the primary identifier of an ad selection process.
95      */
getAdSelectionId()96     public long getAdSelectionId() {
97         return mAdSelectionId;
98     }
99 
100     /**
101      * Returns the event key, the type of ad event to be reported.
102      *
103      * <p>This field will be used to fetch the {@code reportingUri} associated with the {@code
104      * eventKey} registered in {@code registerAdBeacon} after ad selection.
105      *
106      * <p>This field should be an exact match to the {@code eventKey} registered in {@code
107      * registerAdBeacon}. Specific details about {@code registerAdBeacon} can be found at the
108      * documentation of {@link AdSelectionManager#reportImpression}
109      *
110      * <p>The event key (when inspecting its byte array with {@link String#getBytes()}) in {@code
111      * UTF-8} format should not exceed 40 bytes. Any key exceeding this limit will not be registered
112      * during the {@code registerAdBeacon} call.
113      */
114     @NonNull
getKey()115     public String getKey() {
116         return mEventKey;
117     }
118 
119     /**
120      * Returns the input event associated with the user interaction.
121      *
122      * <p>This field is either {@code null}, representing a <em>view</em> event, or has an {@link
123      * InputEvent} object, representing a <em>click</em> event.
124      */
125     @Nullable
getInputEvent()126     public InputEvent getInputEvent() {
127         return mInputEvent;
128     }
129 
130     /**
131      * Returns the ad event data.
132      *
133      * <p>After ad selection, this data is generated by the caller. The caller can then call {@link
134      * AdSelectionManager#reportEvent}. This data will be attached in a POST request to the {@code
135      * reportingUri} registered in {@code registerAdBeacon}.
136      *
137      * <p>The size of {@link String#getBytes()} in {@code UTF-8} format should be below 64KB.
138      */
139     @NonNull
getData()140     public String getData() {
141         return mEventData;
142     }
143 
144     /**
145      * Returns the bitfield of reporting destinations to report to (buyer, seller, component seller
146      * or any of the combination of them).
147      *
148      * <p>To create this bitfield, place an {@code |} bitwise operator between each {@code
149      * reportingDestination} to be reported to. For example to only report to buyer, set the
150      * reportingDestinations field to {@link #FLAG_REPORTING_DESTINATION_BUYER} To only report to
151      * seller, set the reportingDestinations field to {@link #FLAG_REPORTING_DESTINATION_SELLER} To
152      * report to buyers and sellers, set the reportingDestinations field to {@link
153      * #FLAG_REPORTING_DESTINATION_BUYER} | {@link #FLAG_REPORTING_DESTINATION_SELLER}. To report to
154      * buyer, seller and component seller, set the reportingDestinations field to {@link
155      * #FLAG_REPORTING_DESTINATION_BUYER} | {@link #FLAG_REPORTING_DESTINATION_SELLER} | {@link
156      * #FLAG_REPORTING_DESTINATION_COMPONENT_SELLER}.
157      */
158     @ReportingDestination
getReportingDestinations()159     public int getReportingDestinations() {
160         return mReportingDestinations;
161     }
162 
163     /** @hide */
164     @IntDef(
165             flag = true,
166             prefix = {"FLAG_REPORTING_DESTINATION"},
167             value = {
168                 FLAG_REPORTING_DESTINATION_SELLER,
169                 FLAG_REPORTING_DESTINATION_BUYER,
170                 FLAG_REPORTING_DESTINATION_COMPONENT_SELLER
171             })
172     @Retention(RetentionPolicy.SOURCE)
173     public @interface ReportingDestination {}
174 
isValidDestination(@eportingDestination int reportingDestinations)175     private static boolean isValidDestination(@ReportingDestination int reportingDestinations) {
176         return 0 < reportingDestinations
177                 && reportingDestinations
178                         <= (FLAG_REPORTING_DESTINATION_SELLER
179                                 | FLAG_REPORTING_DESTINATION_BUYER
180                                 | FLAG_REPORTING_DESTINATION_COMPONENT_SELLER);
181     }
182 
183     /** Builder for {@link ReportEventRequest} objects. */
184     public static final class Builder {
185 
186         private long mAdSelectionId;
187         @NonNull private String mEventKey;
188         @Nullable private InputEvent mInputEvent;
189         @NonNull private String mEventData;
190         @ReportingDestination private int mReportingDestinations; // buyer, seller, or both
191 
Builder( long adSelectionId, @NonNull String eventKey, @NonNull String eventData, @ReportingDestination int reportingDestinations)192         public Builder(
193                 long adSelectionId,
194                 @NonNull String eventKey,
195                 @NonNull String eventData,
196                 @ReportingDestination int reportingDestinations) {
197             Objects.requireNonNull(eventKey);
198             Objects.requireNonNull(eventData);
199 
200             Preconditions.checkArgument(
201                     adSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
202             Preconditions.checkArgument(
203                     reportingDestinations != UNSET_REPORTING_DESTINATIONS,
204                     UNSET_REPORTING_DESTINATIONS_MESSAGE);
205             Preconditions.checkArgument(
206                     isValidDestination(reportingDestinations),
207                     INVALID_REPORTING_DESTINATIONS_MESSAGE);
208             Preconditions.checkArgument(
209                     eventData.getBytes(StandardCharsets.UTF_8).length
210                             <= REPORT_EVENT_MAX_INTERACTION_DATA_SIZE_B,
211                     EVENT_DATA_SIZE_MAX_EXCEEDED);
212 
213             this.mAdSelectionId = adSelectionId;
214             this.mEventKey = eventKey;
215             this.mEventData = eventData;
216             this.mReportingDestinations = reportingDestinations;
217         }
218 
219         /**
220          * Sets the ad selection ID with which the rendered ad's events are associated.
221          *
222          * <p>See {@link #getAdSelectionId()} for more information.
223          */
224         @NonNull
setAdSelectionId(long adSelectionId)225         public Builder setAdSelectionId(long adSelectionId) {
226             Preconditions.checkArgument(
227                     adSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
228             mAdSelectionId = adSelectionId;
229             return this;
230         }
231 
232         /**
233          * Sets the event key, the type of ad event to be reported.
234          *
235          * <p>See {@link #getKey()} for more information.
236          */
237         @NonNull
setKey(@onNull String eventKey)238         public Builder setKey(@NonNull String eventKey) {
239             Objects.requireNonNull(eventKey);
240 
241             mEventKey = eventKey;
242             return this;
243         }
244 
245         /**
246          * Sets the input event associated with the user interaction.
247          *
248          * <p>See {@link #getInputEvent()} for more information.
249          */
250         @NonNull
setInputEvent(@ullable InputEvent inputEvent)251         public Builder setInputEvent(@Nullable InputEvent inputEvent) {
252             mInputEvent = inputEvent;
253             return this;
254         }
255 
256         /**
257          * Sets the ad event data.
258          *
259          * <p>See {@link #getData()} for more information.
260          */
261         @NonNull
setData(@onNull String eventData)262         public Builder setData(@NonNull String eventData) {
263             Objects.requireNonNull(eventData);
264 
265             mEventData = eventData;
266             return this;
267         }
268 
269         /**
270          * Sets the bitfield of reporting destinations to report to (buyer, seller, or both).
271          *
272          * <p>See {@link #getReportingDestinations()} for more information.
273          */
274         @NonNull
setReportingDestinations(@eportingDestination int reportingDestinations)275         public Builder setReportingDestinations(@ReportingDestination int reportingDestinations) {
276             Preconditions.checkArgument(
277                     isValidDestination(reportingDestinations),
278                     INVALID_REPORTING_DESTINATIONS_MESSAGE);
279 
280             mReportingDestinations = reportingDestinations;
281             return this;
282         }
283 
284         /** Builds the {@link ReportEventRequest} object. */
285         @NonNull
build()286         public ReportEventRequest build() {
287             return new ReportEventRequest(this);
288         }
289     }
290 }
291