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